From d4b239ecc1455bd212c410bdb2bacaa2d3a6b702 Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Fri, 28 Jul 2006 14:00:37 +0100 Subject: [PATCH 001/111] [MINI-OS] unbind_virq is broken and nobody uses it. Remove it. Signed-off-by: Steven Smith --- extras/mini-os/events.c | 5 ----- extras/mini-os/include/events.h | 1 - 2 files changed, 6 deletions(-) diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c index 0acacb2527..23a0c0a453 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -105,11 +105,6 @@ int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data), return 0; } -void unbind_virq( u32 port ) -{ - unbind_evtchn(port); -} - #if defined(__x86_64__) /* Allocate 4 pages for the irqstack */ #define STACK_PAGES 4 diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h index c1b58c4db0..5e032bb4b4 100644 --- a/extras/mini-os/include/events.h +++ b/extras/mini-os/include/events.h @@ -30,7 +30,6 @@ int bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *, void *data), void *data ); void unbind_evtchn( u32 port ); void init_events(void); -void unbind_virq( u32 port ); int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs, void *data), void *data); From a11943ada50a9c5c1c5c2f8c05fc2dfba1de935b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 14:00:57 +0100 Subject: [PATCH 002/111] [LIBXC] Generic include of arch-specific sub-makefile. Signed-off-by: Keir Fraser --- tools/libxc/Makefile | 3 +-- tools/libxc/ia64/Makefile | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 05fba845f4..98f5d9fdf4 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -35,8 +35,7 @@ GUEST_SRCS-$(CONFIG_IA64) += xc_linux_build.c GUEST_SRCS-$(CONFIG_MIGRATE) += xc_linux_restore.c xc_linux_save.c GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c -# This Makefile only adds files if CONFIG_IA64 is y. -include ia64/Makefile +-include $(XEN_TARGET_ARCH)/Makefile CFLAGS += -Werror CFLAGS += -fno-strict-aliasing diff --git a/tools/libxc/ia64/Makefile b/tools/libxc/ia64/Makefile index 95c295ae1e..974a5c3827 100644 --- a/tools/libxc/ia64/Makefile +++ b/tools/libxc/ia64/Makefile @@ -1,5 +1,5 @@ -CTRL_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_stubs.c +CTRL_SRCS-y += ia64/xc_ia64_stubs.c -GUEST_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_hvm_build.c -GUEST_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_linux_save.c -GUEST_SRCS-$(CONFIG_IA64) += ia64/xc_ia64_linux_restore.c +GUEST_SRCS-y += ia64/xc_ia64_hvm_build.c +GUEST_SRCS-y += ia64/xc_ia64_linux_save.c +GUEST_SRCS-y += ia64/xc_ia64_linux_restore.c From a0f55d516b1eec2c53530338e6fab512586eea5f Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Fri, 28 Jul 2006 14:02:49 +0100 Subject: [PATCH 003/111] [MINI-OS] Clean up event channel types in mini-os. Signed-off-by: John D. Ramsdell Signed-off-by: Steven Smith --- extras/mini-os/console/xencons_ring.c | 2 +- extras/mini-os/events.c | 23 ++++++++++------------- extras/mini-os/include/events.h | 24 ++++++++++++------------ extras/mini-os/time.c | 2 +- extras/mini-os/xenbus/xenbus.c | 3 ++- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/extras/mini-os/console/xencons_ring.c b/extras/mini-os/console/xencons_ring.c index 7693235ff0..6b02fcdc65 100644 --- a/extras/mini-os/console/xencons_ring.c +++ b/extras/mini-os/console/xencons_ring.c @@ -53,7 +53,7 @@ int xencons_ring_send(const char *data, unsigned len) -static void handle_input(int port, struct pt_regs *regs, void *ign) +static void handle_input(evtchn_port_t port, struct pt_regs *regs, void *ign) { struct xencons_interface *intf = xencons_interface(); XENCONS_RING_IDX cons, prod; diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c index 23a0c0a453..641c86ceba 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -26,20 +26,20 @@ /* this represents a event handler. Chaining or sharing is not allowed */ typedef struct _ev_action_t { - void (*handler)(int, struct pt_regs *, void *); + evtchn_handler_t handler; void *data; u32 count; } ev_action_t; static ev_action_t ev_actions[NR_EVS]; -void default_handler(int port, struct pt_regs *regs, void *data); +void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data); /* * Demux events to different handlers. */ -int do_event(u32 port, struct pt_regs *regs) +int do_event(evtchn_port_t port, struct pt_regs *regs) { ev_action_t *action; if (port >= NR_EVS) { @@ -60,8 +60,8 @@ int do_event(u32 port, struct pt_regs *regs) } -int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *, void *), - void *data ) +evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler, + void *data) { if(ev_actions[port].handler != default_handler) printk("WARN: Handler for port %d already registered, replacing\n", @@ -77,7 +77,7 @@ int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *, void *), return port; } -void unbind_evtchn( u32 port ) +void unbind_evtchn(evtchn_port_t port ) { if (ev_actions[port].handler == default_handler) printk("WARN: No handler for port %d when unbinding\n", port); @@ -86,8 +86,7 @@ void unbind_evtchn( u32 port ) ev_actions[port].data = NULL; } -int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data), - void *data) +int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data) { evtchn_op_t op; @@ -137,7 +136,7 @@ void init_events(void) } } -void default_handler(int port, struct pt_regs *regs, void *ignore) +void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore) { printk("[Port %d] - event received\n", port); } @@ -145,11 +144,9 @@ void default_handler(int port, struct pt_regs *regs, void *ignore) /* Unfortunate confusion of terminology: the port is unbound as far as Xen is concerned, but we automatically bind a handler to it from inside mini-os. */ -int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs, - void *data), - void *data) +evtchn_port_t evtchn_alloc_unbound(evtchn_handler_t handler, void *data) { - u32 port; + evtchn_port_t port; evtchn_op_t op; int err; diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h index 5e032bb4b4..1ffcecb61b 100644 --- a/extras/mini-os/include/events.h +++ b/extras/mini-os/include/events.h @@ -22,19 +22,19 @@ #include #include -/* prototypes */ -int do_event(u32 port, struct pt_regs *regs); -int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data), - void *data); -int bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *, void *data), - void *data ); -void unbind_evtchn( u32 port ); -void init_events(void); -int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs, - void *data), - void *data); +typedef void (*evtchn_handler_t)(evtchn_port_t, struct pt_regs *, void *); -static inline int notify_remote_via_evtchn(int port) +/* prototypes */ +int do_event(evtchn_port_t port, struct pt_regs *regs); +int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data); +evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler, + void *data); +void unbind_evtchn(evtchn_port_t port); +void init_events(void); +evtchn_port_t evtchn_alloc_unbound(evtchn_handler_t handler, + void *data); + +static inline int notify_remote_via_evtchn(evtchn_port_t port) { evtchn_op_t op; op.cmd = EVTCHNOP_send; diff --git a/extras/mini-os/time.c b/extras/mini-os/time.c index 1df4a26036..5567b5d391 100644 --- a/extras/mini-os/time.c +++ b/extras/mini-os/time.c @@ -215,7 +215,7 @@ void block_domain(u32 millisecs) /* * Just a dummy */ -static void timer_handler(int ev, struct pt_regs *regs, void *ign) +static void timer_handler(evtchn_port_t ev, struct pt_regs *regs, void *ign) { static int i; diff --git a/extras/mini-os/xenbus/xenbus.c b/extras/mini-os/xenbus/xenbus.c index 704ba58104..cb62eb3ef6 100644 --- a/extras/mini-os/xenbus/xenbus.c +++ b/extras/mini-os/xenbus/xenbus.c @@ -112,7 +112,8 @@ static void xenbus_thread_func(void *ign) } } -static void xenbus_evtchn_handler(int port, struct pt_regs *regs, void *ign) +static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs, + void *ign) { wake_up(&xb_waitq); } From 194a6f6b1f79d6bb4c40ce2a4fdafd845be4f2ce Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Fri, 28 Jul 2006 14:03:54 +0100 Subject: [PATCH 004/111] [MINI-OS] Extend alloc_unbound so that the remote domain isn't always dom0. Signed-off-by: John D. Ramsdell Signed-off-by: Steven Smith --- extras/mini-os/events.c | 32 +++++++++++++++----------------- extras/mini-os/include/events.h | 4 ++-- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c index 641c86ceba..dfc1206c2e 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -141,25 +141,23 @@ void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore) printk("[Port %d] - event received\n", port); } +/* Create a port available to the pal for exchanging notifications. + Returns the result of the hypervisor call. */ + /* Unfortunate confusion of terminology: the port is unbound as far as Xen is concerned, but we automatically bind a handler to it from inside mini-os. */ -evtchn_port_t evtchn_alloc_unbound(evtchn_handler_t handler, void *data) + +int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, + void *data, evtchn_port_t *port) { - evtchn_port_t port; - evtchn_op_t op; - int err; - - op.cmd = EVTCHNOP_alloc_unbound; - op.u.alloc_unbound.dom = DOMID_SELF; - op.u.alloc_unbound.remote_dom = 0; - - err = HYPERVISOR_event_channel_op(&op); - if (err) { - printk("Failed to alloc unbound evtchn: %d.\n", err); - return -1; - } - port = op.u.alloc_unbound.port; - bind_evtchn(port, handler, data); - return port; + evtchn_op_t op; + op.cmd = EVTCHNOP_alloc_unbound; + op.u.alloc_unbound.dom = DOMID_SELF; + op.u.alloc_unbound.remote_dom = pal; + int err = HYPERVISOR_event_channel_op(&op); + if (err) + return err; + *port = bind_evtchn(op.u.alloc_unbound.port, handler, data); + return err; } diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h index 1ffcecb61b..f0133621f8 100644 --- a/extras/mini-os/include/events.h +++ b/extras/mini-os/include/events.h @@ -31,8 +31,8 @@ evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler, void *data); void unbind_evtchn(evtchn_port_t port); void init_events(void); -evtchn_port_t evtchn_alloc_unbound(evtchn_handler_t handler, - void *data); +int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, + void *data, evtchn_port_t *port); static inline int notify_remote_via_evtchn(evtchn_port_t port) { From e573f4fac04be1866b13b08a31627c7dad06538f Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Fri, 28 Jul 2006 14:05:02 +0100 Subject: [PATCH 005/111] [MINI-OS] Add evtchn_bind_interdomain to mini-os, allowing clients to bind to interdomain event channels. Signed-off-by: John D. Ramsdell Signed-off-by: Steven Smith --- extras/mini-os/events.c | 20 ++++++++++++++++++++ extras/mini-os/include/events.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c index dfc1206c2e..57e835225d 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -161,3 +161,23 @@ int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, *port = bind_evtchn(op.u.alloc_unbound.port, handler, data); return err; } + +/* Connect to a port so as to allow the exchange of notifications with + the pal. Returns the result of the hypervisor call. */ + +int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port, + evtchn_handler_t handler, void *data, + evtchn_port_t *local_port) +{ + evtchn_op_t op; + op.cmd = EVTCHNOP_bind_interdomain; + op.u.bind_interdomain.remote_dom = pal; + op.u.bind_interdomain.remote_port = remote_port; + int err = HYPERVISOR_event_channel_op(&op); + if (err) + return err; + evtchn_port_t port = op.u.bind_interdomain.local_port; + clear_evtchn(port); /* Without, handler gets invoked now! */ + *local_port = bind_evtchn(port, handler, data); + return err; +} diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h index f0133621f8..cdb6311845 100644 --- a/extras/mini-os/include/events.h +++ b/extras/mini-os/include/events.h @@ -33,6 +33,9 @@ void unbind_evtchn(evtchn_port_t port); void init_events(void); int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, void *data, evtchn_port_t *port); +int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port, + evtchn_handler_t handler, void *data, + evtchn_port_t *local_port); static inline int notify_remote_via_evtchn(evtchn_port_t port) { From e6ce746c398d140f0bee7091fab86748164a00d6 Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Fri, 28 Jul 2006 14:06:27 +0100 Subject: [PATCH 006/111] [MINI-OS] Add a function mapping grant table error codes to strings. Signed-off-by: John D. Ramsdell Signed-off-by: Steven Smith --- extras/mini-os/gnttab.c | 12 ++++++++++++ extras/mini-os/include/gnttab.h | 1 + 2 files changed, 13 insertions(+) diff --git a/extras/mini-os/gnttab.c b/extras/mini-os/gnttab.c index a405e0c072..7f9f0096f1 100644 --- a/extras/mini-os/gnttab.c +++ b/extras/mini-os/gnttab.c @@ -137,6 +137,18 @@ gnttab_alloc_and_grant(void **map) return gref; } +static const char *gnttabop_error_msgs[] = GNTTABOP_error_msgs; + +const char * +gnttabop_error(int16_t status) +{ + status = -status; + if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs)) + return "bad status"; + else + return gnttabop_error_msgs[status]; +} + void init_gnttab(void) { diff --git a/extras/mini-os/include/gnttab.h b/extras/mini-os/include/gnttab.h index 65a02aa85f..f952442955 100644 --- a/extras/mini-os/include/gnttab.h +++ b/extras/mini-os/include/gnttab.h @@ -10,5 +10,6 @@ grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame, grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn); unsigned long gnttab_end_transfer(grant_ref_t gref); int gnttab_end_access(grant_ref_t ref); +const char *gnttabop_error(int16_t status); #endif /* !__GNTTAB_H__ */ From b907e33985fbc5ab2aa17ada5dcb5b8e98307b26 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 16:53:35 +0100 Subject: [PATCH 007/111] [IA64] Add missing empty files. --- xen/include/asm-ia64/linux-null/linux/kallsyms.h | 0 xen/include/asm-ia64/linux-null/linux/workqueue.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 xen/include/asm-ia64/linux-null/linux/kallsyms.h create mode 100644 xen/include/asm-ia64/linux-null/linux/workqueue.h diff --git a/xen/include/asm-ia64/linux-null/linux/kallsyms.h b/xen/include/asm-ia64/linux-null/linux/kallsyms.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xen/include/asm-ia64/linux-null/linux/workqueue.h b/xen/include/asm-ia64/linux-null/linux/workqueue.h new file mode 100644 index 0000000000..e69de29bb2 From 30ec81982666ed3db0e2ad0ea98252e6e4b1a2dd Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 16:53:58 +0100 Subject: [PATCH 008/111] Merge. --- .../drivers/xen/netfront/netfront.c | 83 ++++++++++++++----- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 05b876e93c..1db6bbc9d7 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -99,17 +99,17 @@ struct netfront_info { struct timer_list rx_refill_timer; /* - * {tx,rx}_skbs store outstanding skbuffs. The first entry in each - * array is an index into a chain of free entries. + * {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs + * is an index into a chain of free entries. */ struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1]; - struct sk_buff *rx_skbs[NET_RX_RING_SIZE+1]; + struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; #define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) grant_ref_t gref_tx_head; grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; grant_ref_t gref_rx_head; - grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; + grant_ref_t grant_rx_ref[NET_TX_RING_SIZE]; struct xenbus_device *xbdev; int tx_ring_ref; @@ -122,7 +122,7 @@ struct netfront_info { }; /* - * Access macros for acquiring freeing slots in {tx,rx}_skbs[]. + * Access macros for acquiring freeing slots in tx_skbs[]. */ static inline void add_id_to_freelist(struct sk_buff **list, unsigned short id) @@ -138,6 +138,29 @@ static inline unsigned short get_id_from_freelist(struct sk_buff **list) return id; } +static inline int xennet_rxidx(RING_IDX idx) +{ + return idx & (NET_RX_RING_SIZE - 1); +} + +static inline struct sk_buff *xennet_get_rx_skb(struct netfront_info *np, + RING_IDX ri) +{ + int i = xennet_rxidx(ri); + struct sk_buff *skb = np->rx_skbs[i]; + np->rx_skbs[i] = NULL; + return skb; +} + +static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np, + RING_IDX ri) +{ + int i = xennet_rxidx(ri); + grant_ref_t ref = np->grant_rx_ref[i]; + np->grant_rx_ref[i] = GRANT_INVALID_REF; + return ref; +} + #define DPRINTK(fmt, args...) \ pr_debug("netfront (%s:%d) " fmt, \ __FUNCTION__, __LINE__, ##args) @@ -598,8 +621,9 @@ static void network_alloc_rx_buffers(struct net_device *dev) skb->dev = dev; - id = get_id_from_freelist(np->rx_skbs); + id = xennet_rxidx(req_prod + i); + BUG_ON(np->rx_skbs[id]); np->rx_skbs[id] = skb; RING_GET_REQUEST(&np->rx, req_prod + i)->id = id; @@ -840,6 +864,19 @@ static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs) return IRQ_HANDLED; } +static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, + grant_ref_t ref) +{ + int new = xennet_rxidx(np->rx.req_prod_pvt); + + BUG_ON(np->rx_skbs[new]); + np->rx_skbs[new] = skb; + np->grant_rx_ref[new] = ref; + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; + np->rx.req_prod_pvt++; + RING_PUSH_REQUESTS(&np->rx); +} static int netif_poll(struct net_device *dev, int *pbudget) { @@ -874,12 +911,15 @@ static int netif_poll(struct net_device *dev, int *pbudget) i++, work_done++) { rx = RING_GET_RESPONSE(&np->rx, i); + skb = xennet_get_rx_skb(np, i); + ref = xennet_get_rx_ref(np, i); + /* * This definitely indicates a bug, either in this driver or in * the backend driver. In future this should flag the bad * situation to the system controller to reboot the backed. */ - if ((ref = np->grant_rx_ref[rx->id]) == GRANT_INVALID_REF) { + if (ref == GRANT_INVALID_REF) { WPRINTK("Bad rx response id %d.\n", rx->id); work_done--; continue; @@ -890,21 +930,12 @@ static int netif_poll(struct net_device *dev, int *pbudget) if (net_ratelimit()) WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", rx->id, rx->status); - RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = - rx->id; - RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = - ref; - np->rx.req_prod_pvt++; - RING_PUSH_REQUESTS(&np->rx); + xennet_move_rx_slot(np, skb, ref); work_done--; continue; } gnttab_release_grant_reference(&np->gref_rx_head, ref); - np->grant_rx_ref[rx->id] = GRANT_INVALID_REF; - - skb = np->rx_skbs[rx->id]; - add_id_to_freelist(np->rx_skbs, rx->id); /* NB. We handle skb overflow later. */ skb->data = skb->head + rx->offset; @@ -1158,15 +1189,23 @@ static void network_connect(struct net_device *dev) } /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ - for (requeue_idx = 0, i = 1; i <= NET_RX_RING_SIZE; i++) { - if ((unsigned long)np->rx_skbs[i] < PAGE_OFFSET) + for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { + if (!np->rx_skbs[i]) continue; + gnttab_grant_foreign_transfer_ref( np->grant_rx_ref[i], np->xbdev->otherend_id, __pa(np->rx_skbs[i]->data) >> PAGE_SHIFT); RING_GET_REQUEST(&np->rx, requeue_idx)->gref = np->grant_rx_ref[i]; - RING_GET_REQUEST(&np->rx, requeue_idx)->id = i; + RING_GET_REQUEST(&np->rx, requeue_idx)->id = requeue_idx; + + if (requeue_idx < i) { + np->rx_skbs[requeue_idx] = np->rx_skbs[i]; + np->grant_rx_ref[requeue_idx] = np->grant_rx_ref[i]; + np->rx_skbs[i] = NULL; + np->grant_rx_ref[i] = GRANT_INVALID_REF; + } requeue_idx++; } @@ -1392,8 +1431,8 @@ static struct net_device * __devinit create_netdev(int handle, np->grant_tx_ref[i] = GRANT_INVALID_REF; } - for (i = 0; i <= NET_RX_RING_SIZE; i++) { - np->rx_skbs[i] = (void *)((unsigned long) i+1); + for (i = 0; i < NET_RX_RING_SIZE; i++) { + np->rx_skbs[i] = NULL; np->grant_rx_ref[i] = GRANT_INVALID_REF; } From 47a078f10128e9b8334a054ec70419c10a11415b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:00:10 +0100 Subject: [PATCH 009/111] [NET] front: Clean up rx ring recovery. Signed-off-by: Keir Fraser This is an update to c/s 10855:03c8002068d9d60c7bbfc2f41af975e09b2e2211 which should have contained the following changeset message (rather than 'Merge.'). [NET] front: Stop using rx->id With the current protocol for transferring packets from dom0 to domU, the rx->id field is useless because it can be derived from the rx request ring ID. In particular, rx->id = (ring_id & NET_RX_RING_SIZE - 1) + 1; This formula works because the rx response to each request always occupies the same slot that the request arrived in. This in turn is a consequence of the fact that each packet only occupies one slot. The other important reason that this works for dom0=>domU but not domU=>dom0 is that the resource associated with the rx->id is freed immediately while in the domU=>dom0 case the resource is held until the skb is liberated by dom0. Using this formula we can essentially remove rx->id from the protocol, freeing up space that could be instead be used by things like TSO. The only constraint is that the backend must obey the rule that each id must only be used in the response that occupies the same slot as the request. The actual field of rx->id is still maintained for compatibility with older backends. Signed-off-by: Herbert Xu --- .../drivers/xen/netfront/netfront.c | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 1db6bbc9d7..41fddd04b0 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -1193,19 +1193,16 @@ static void network_connect(struct net_device *dev) if (!np->rx_skbs[i]) continue; - gnttab_grant_foreign_transfer_ref( - np->grant_rx_ref[i], np->xbdev->otherend_id, - __pa(np->rx_skbs[i]->data) >> PAGE_SHIFT); - RING_GET_REQUEST(&np->rx, requeue_idx)->gref = - np->grant_rx_ref[i]; - RING_GET_REQUEST(&np->rx, requeue_idx)->id = requeue_idx; + skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i); + ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); + + gnttab_grant_foreign_transfer_ref( + ref, np->xbdev->otherend_id, + __pa(skb->data) >> PAGE_SHIFT); + + RING_GET_REQUEST(&np->rx, requeue_idx)->gref = ref; + RING_GET_REQUEST(&np->rx, requeue_idx)->id = requeue_idx; - if (requeue_idx < i) { - np->rx_skbs[requeue_idx] = np->rx_skbs[i]; - np->grant_rx_ref[requeue_idx] = np->grant_rx_ref[i]; - np->rx_skbs[i] = NULL; - np->grant_rx_ref[i] = GRANT_INVALID_REF; - } requeue_idx++; } From db9f62f5703c98e17f5b61a88c914272865f7612 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:03:26 +0100 Subject: [PATCH 010/111] [NET] front: Move rx req pushing to one spot This patch moves all rx request pushing to network_alloc_rx_buffers. This is needed to reduce churn for TSO. More importantly, this makes it easier to send notifications when adding rx requests which is required for having a queue in dom0. Signed-off-by: Herbert Xu --- linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 41fddd04b0..77921f081d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -600,14 +600,17 @@ static void network_alloc_rx_buffers(struct net_device *dev) /* Could not allocate any skbuffs. Try again later. */ mod_timer(&np->rx_refill_timer, jiffies + (HZ/10)); - return; + break; } __skb_queue_tail(&np->rx_batch, skb); } /* Is the batch large enough to be worthwhile? */ - if (i < (np->rx_target/2)) + if (i < (np->rx_target/2)) { + if (req_prod > np->rx.sring->req_prod) + goto push; return; + } /* Adjust our fill target if we risked running out of buffers. */ if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) && @@ -678,6 +681,7 @@ static void network_alloc_rx_buffers(struct net_device *dev) /* Above is a suitable barrier to ensure backend will see requests. */ np->rx.req_prod_pvt = req_prod + i; + push: RING_PUSH_REQUESTS(&np->rx); } @@ -875,7 +879,6 @@ static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; np->rx.req_prod_pvt++; - RING_PUSH_REQUESTS(&np->rx); } static int netif_poll(struct net_device *dev, int *pbudget) @@ -1207,7 +1210,6 @@ static void network_connect(struct net_device *dev) } np->rx.req_prod_pvt = requeue_idx; - RING_PUSH_REQUESTS(&np->rx); /* * Step 3: All public and private state should now be sane. Get From 648ad07608c62e15343bb8834d86600223fbbec2 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:04:55 +0100 Subject: [PATCH 011/111] [NET] back: Replace netif->status with netif_carrier_ok The connection status to the frontend can be represented using netif_carrier_ok instead of netif->status. As a result, we delay the construction of the dev qdisc until the carrier comes on. This is a prerequisite for adding a tx queue. By the same token, netif->active is now simply the conjunction of netif_running and netif_carrier_ok so it too can be removed. Because netif_carrier_off/netif_carrier_on and rtnl_lock all entail memory barriers, there is no need to have extra memory barriers around them. Signed-off-by: Herbert Xu --- .../drivers/xen/netback/common.h | 2 -- .../drivers/xen/netback/interface.c | 32 +++++-------------- .../drivers/xen/netback/netback.c | 6 ++-- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h index c52aaa5f6c..3ba0251dca 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h @@ -86,8 +86,6 @@ typedef struct netif_st { struct timer_list credit_timeout; /* Miscellaneous private stuff. */ - enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; - int active; struct list_head list; /* scheduling list */ atomic_t refcnt; struct net_device *dev; diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index f52e2601b7..b5decfd3ea 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -36,28 +36,20 @@ static void __netif_up(netif_t *netif) { - struct net_device *dev = netif->dev; - netif_tx_lock_bh(dev); - netif->active = 1; - netif_tx_unlock_bh(dev); enable_irq(netif->irq); netif_schedule_work(netif); } static void __netif_down(netif_t *netif) { - struct net_device *dev = netif->dev; disable_irq(netif->irq); - netif_tx_lock_bh(dev); - netif->active = 0; - netif_tx_unlock_bh(dev); netif_deschedule_work(netif); } static int net_open(struct net_device *dev) { netif_t *netif = netdev_priv(dev); - if (netif->status == CONNECTED) + if (netif_carrier_ok(dev)) __netif_up(netif); netif_start_queue(dev); return 0; @@ -67,7 +59,7 @@ static int net_close(struct net_device *dev) { netif_t *netif = netdev_priv(dev); netif_stop_queue(dev); - if (netif->status == CONNECTED) + if (netif_carrier_ok(dev)) __netif_down(netif); return 0; } @@ -93,11 +85,12 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]) return ERR_PTR(-ENOMEM); } + netif_carrier_off(dev); + netif = netdev_priv(dev); memset(netif, 0, sizeof(*netif)); netif->domid = domid; netif->handle = handle; - netif->status = DISCONNECTED; atomic_set(&netif->refcnt, 1); init_waitqueue_head(&netif->waiting_to_free); netif->dev = dev; @@ -256,11 +249,9 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref, netif->rx_req_cons_peek = 0; netif_get(netif); - wmb(); /* Other CPUs see new state before interface is started. */ rtnl_lock(); - netif->status = CONNECTED; - wmb(); + netif_carrier_on(netif->dev); if (netif_running(netif->dev)) __netif_up(netif); rtnl_unlock(); @@ -296,20 +287,13 @@ static void netif_free(netif_t *netif) void netif_disconnect(netif_t *netif) { - switch (netif->status) { - case CONNECTED: + if (netif_carrier_ok(netif->dev)) { rtnl_lock(); - netif->status = DISCONNECTING; - wmb(); + netif_carrier_off(netif->dev); if (netif_running(netif->dev)) __netif_down(netif); rtnl_unlock(); netif_put(netif); - /* fall through */ - case DISCONNECTED: - netif_free(netif); - break; - default: - BUG(); } + netif_free(netif); } diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 6795bcd3af..80d16b7576 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -143,7 +143,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(skb->dev != dev); /* Drop the packet if the target domain has no receive buffers. */ - if (!netif->active || + if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)) || (netif->rx_req_cons_peek == netif->rx.sring->req_prod) || ((netif->rx_req_cons_peek - netif->rx.rsp_prod_pvt) == NET_RX_RING_SIZE)) @@ -404,7 +404,9 @@ static void add_to_net_schedule_list_tail(netif_t *netif) return; spin_lock_irq(&net_schedule_list_lock); - if (!__on_net_schedule_list(netif) && netif->active) { + if (!__on_net_schedule_list(netif) && + likely(netif_running(netif->dev) && + netif_carrier_ok(netif->dev))) { list_add_tail(&netif->list, &net_schedule_list); netif_get(netif); } From d5dd60406fa35f8cb7335d664dc6d4bce14698e6 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:13:08 +0100 Subject: [PATCH 012/111] [NET] front: Added feature-rx-notify This patch adds support to the frontend for notifying the backend whenever the rx ring is refilled. This is required in order for the backend to get a tx queue. Signed-off-by: Herbert Xu Modified to only send notification if req_event index is set appropriately. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c | 12 ++++++++++-- xen/include/public/io/netif.h | 7 ++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 77921f081d..2bfd63acd8 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -326,6 +326,12 @@ again: goto abort_transaction; } + err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1); + if (err) { + message = "writing feature-rx-notify"; + goto abort_transaction; + } + err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) @@ -569,7 +575,7 @@ static void network_alloc_rx_buffers(struct net_device *dev) unsigned short id; struct netfront_info *np = netdev_priv(dev); struct sk_buff *skb; - int i, batch_target; + int i, batch_target, notify; RING_IDX req_prod = np->rx.req_prod_pvt; struct xen_memory_reservation reservation; grant_ref_t ref; @@ -682,7 +688,9 @@ static void network_alloc_rx_buffers(struct net_device *dev) /* Above is a suitable barrier to ensure backend will see requests. */ np->rx.req_prod_pvt = req_prod + i; push: - RING_PUSH_REQUESTS(&np->rx); + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify); + if (notify) + notify_remote_via_irq(np->irq); } static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, diff --git a/xen/include/public/io/netif.h b/xen/include/public/io/netif.h index 7b219b00a2..b551006034 100644 --- a/xen/include/public/io/netif.h +++ b/xen/include/public/io/netif.h @@ -13,10 +13,11 @@ #include "../grant_table.h" /* - * Note that there is *never* any need to notify the backend when - * enqueuing receive requests (struct netif_rx_request). Notifications - * after enqueuing any other type of message should be conditional on + * Notifications after enqueuing any type of message should be conditional on * the appropriate req_event or rsp_event field in the shared ring. + * If the client sends notification for rx requests then it should specify + * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume + * that it cannot safely queue packets (as it may not be kicked to send them). */ /* From 6faab8acafcf9e334dcd86a0d0c609522019c416 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:23:15 +0100 Subject: [PATCH 013/111] [PCI] Pcifront for ia64. Added in Kconfig. On ia64, use ia64 sysdata instead of pcifront genuine one. Fix a warning on xenbus.c Signed-off-by: Tristan Gingold --- linux-2.6-xen-sparse/arch/ia64/Kconfig | 15 +++++++ .../drivers/xen/pcifront/pci_op.c | 13 +++--- .../drivers/xen/pcifront/xenbus.c | 1 + linux-2.6-xen-sparse/include/xen/pcifront.h | 42 ++++++++++++++++++- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/Kconfig b/linux-2.6-xen-sparse/arch/ia64/Kconfig index 63a5195290..a74eeffde4 100644 --- a/linux-2.6-xen-sparse/arch/ia64/Kconfig +++ b/linux-2.6-xen-sparse/arch/ia64/Kconfig @@ -438,6 +438,21 @@ config PCI_DOMAINS bool default PCI +config XEN_PCIDEV_FRONTEND + bool "Xen PCI Frontend" + depends on PCI && XEN + default y + help + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + +config XEN_PCIDEV_FE_DEBUG + bool "Xen PCI Frontend Debugging" + depends on XEN_PCIDEV_FRONTEND + default n + help + Enables some debug statements within the PCI Frontend. + source "drivers/pci/Kconfig" source "drivers/pci/hotplug/Kconfig" diff --git a/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c index 38906ade6e..6be14aebdc 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c @@ -105,7 +105,7 @@ static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn, .size = size, }; struct pcifront_sd *sd = bus->sysdata; - struct pcifront_device *pdev = sd->pdev; + struct pcifront_device *pdev = pcifront_get_pdev(sd); if (verbose_request) dev_info(&pdev->xdev->dev, @@ -144,7 +144,7 @@ static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn, .value = val, }; struct pcifront_sd *sd = bus->sysdata; - struct pcifront_device *pdev = sd->pdev; + struct pcifront_device *pdev = pcifront_get_pdev(sd); if (verbose_request) dev_info(&pdev->xdev->dev, @@ -207,12 +207,13 @@ int pcifront_scan_root(struct pcifront_device *pdev, err = -ENOMEM; goto err_out; } - sd->domain = domain; - sd->pdev = pdev; + pcifront_init_sd(sd, domain, pdev); - b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd); + b = pci_scan_bus_parented(&pdev->xdev->dev, bus, + &pcifront_bus_ops, sd); if (!b) { - dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n"); + dev_err(&pdev->xdev->dev, + "Error creating PCI Frontend Bus!\n"); err = -ENOMEM; goto err_out; } diff --git a/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c index 10d86812d8..f3a642e5b6 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "pcifront.h" #define INVALID_GRANT_REF (0) diff --git a/linux-2.6-xen-sparse/include/xen/pcifront.h b/linux-2.6-xen-sparse/include/xen/pcifront.h index 51b170a0fc..17c843ade1 100644 --- a/linux-2.6-xen-sparse/include/xen/pcifront.h +++ b/linux-2.6-xen-sparse/include/xen/pcifront.h @@ -11,16 +11,30 @@ #ifdef __KERNEL__ +#ifndef __ia64__ + struct pcifront_device; +struct pci_bus; struct pcifront_sd { int domain; struct pcifront_device *pdev; }; -struct pci_bus; +static inline struct pcifront_device * +pcifront_get_pdev(struct pcifront_sd *sd) +{ + return sd->pdev; +} -#ifdef CONFIG_PCI_DOMAINS +static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain, + struct pcifront_device *pdev) +{ + sd->domain = domain; + sd->pdev = pdev; +} + +#if defined(CONFIG_PCI_DOMAINS) static inline int pci_domain_nr(struct pci_bus *bus) { struct pcifront_sd *sd = bus->sysdata; @@ -32,6 +46,30 @@ static inline int pci_proc_domain(struct pci_bus *bus) } #endif /* CONFIG_PCI_DOMAINS */ +#else /* __ia64__ */ + +#include +#define pcifront_sd pci_controller + +static inline struct pcifront_device * +pcifront_get_pdev(struct pcifront_sd *sd) +{ + return (struct pcifront_device *)sd->platform_data; +} + +static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain, + struct pcifront_device *pdev) +{ + sd->segment = domain; + sd->acpi_handle = NULL; + sd->iommu = NULL; + sd->windows = 0; + sd->window = NULL; + sd->platform_data = pdev; +} + +#endif /* __ia64__ */ + extern spinlock_t pci_bus_lock; #endif /* __KERNEL__ */ From 160bfb4e1c46650488ce2235c0a8014ebe7f4e87 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:25:20 +0100 Subject: [PATCH 014/111] [LINUX] update_va_mapping multicalls: Use MULTI_UVMxxx_INDEX where possible. Signed-off-by: Jan Beulich --- .../include/asm-i386/mach-xen/asm/hypervisor.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h index 29b7b26807..38378554af 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h @@ -187,16 +187,14 @@ MULTI_update_va_mapping( mcl->args[0] = va; #if defined(CONFIG_X86_64) mcl->args[1] = new_val.pte; - mcl->args[2] = flags; #elif defined(CONFIG_X86_PAE) mcl->args[1] = new_val.pte_low; mcl->args[2] = new_val.pte_high; - mcl->args[3] = flags; #else mcl->args[1] = new_val.pte_low; mcl->args[2] = 0; - mcl->args[3] = flags; #endif + mcl->args[MULTI_UVMFLAGS_INDEX] = flags; } static inline void @@ -208,19 +206,15 @@ MULTI_update_va_mapping_otherdomain( mcl->args[0] = va; #if defined(CONFIG_X86_64) mcl->args[1] = new_val.pte; - mcl->args[2] = flags; - mcl->args[3] = domid; #elif defined(CONFIG_X86_PAE) mcl->args[1] = new_val.pte_low; mcl->args[2] = new_val.pte_high; - mcl->args[3] = flags; - mcl->args[4] = domid; #else mcl->args[1] = new_val.pte_low; mcl->args[2] = 0; - mcl->args[3] = flags; - mcl->args[4] = domid; #endif + mcl->args[MULTI_UVMFLAGS_INDEX] = flags; + mcl->args[MULTI_UVMDOMID_INDEX] = domid; } #endif /* __HYPERVISOR_H__ */ From ffb974095f3e5cf081d997924439eb743f9d7e58 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:33:26 +0100 Subject: [PATCH 015/111] [TPM] Remove some stale code from the TPM backend driver. The code used to be used for sending of vTPM control commands, but now this is all done with the hotplug scripts. Signed-off-by: Stefan Berger --- linux-2.6-xen-sparse/drivers/xen/Kconfig | 9 ----- .../drivers/xen/tpmback/tpmback.c | 39 ------------------- 2 files changed, 48 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/Kconfig b/linux-2.6-xen-sparse/drivers/xen/Kconfig index 39d316205a..b8a9479927 100644 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig @@ -143,15 +143,6 @@ config XEN_TPMDEV_BACKEND help The TPM-device backend driver -config XEN_TPMDEV_CLOSE_IF_VTPM_FAILS - bool "TPM backend closes upon vTPM failure" - depends on XEN_TPMDEV_BACKEND - default n - help - The TPM backend closes the channel if the vTPM in userspace indicates - a failure. The corresponding domain's channel will be closed. - Say Y if you want this feature. - config XEN_BLKDEV_FRONTEND tristate "Block-device frontend driver" depends on XEN diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c index f792a4cf35..466c3ee581 100644 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c @@ -55,7 +55,6 @@ struct packet { enum { PACKET_FLAG_DISCARD_RESPONSE = 1, - PACKET_FLAG_CHECK_RESPONSESTATUS = 2, }; /* local variables */ @@ -201,21 +200,6 @@ static void packet_free(struct packet *pak) kfree(pak); } -static int packet_set(struct packet *pak, - const unsigned char *buffer, u32 size) -{ - int rc = 0; - unsigned char *buf = kmalloc(size, GFP_KERNEL); - - if (buf) { - pak->data_buffer = buf; - memcpy(buf, buffer, size); - pak->data_len = size; - } else { - rc = -ENOMEM; - } - return rc; -} /* * Write data to the shared memory and send it to the FE. @@ -225,29 +209,6 @@ static int packet_write(struct packet *pak, { int rc = 0; - if ((pak->flags & PACKET_FLAG_CHECK_RESPONSESTATUS)) { -#ifdef CONFIG_XEN_TPMDEV_CLOSE_IF_VTPM_FAILS - u32 res; - - if (copy_from_buffer(&res, - &data[2 + 4], sizeof (res), - isuserbuffer)) { - return -EFAULT; - } - - if (res != 0) { - /* - * Close down this device. Should have the - * FE notified about closure. - */ - if (!pak->tpmif) { - return -EFAULT; - } - pak->tpmif->status = DISCONNECTING; - } -#endif - } - if (0 != (pak->flags & PACKET_FLAG_DISCARD_RESPONSE)) { /* Don't send a respone to this packet. Just acknowledge it. */ rc = size; From 87f45629c696175f7a8047ce2e25af8427ec2f31 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:35:39 +0100 Subject: [PATCH 016/111] [XEND] Better checking of shutdown of domain0. Signed-off-by: Masaki Kanno --- tools/python/xen/xend/XendDomainInfo.py | 2 ++ tools/python/xen/xm/shutdown.py | 15 ++++----------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 0d97fe38ac..35a014900d 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -943,6 +943,8 @@ class XendDomainInfo: def shutdown(self, reason): if not reason in shutdown_reasons.values(): raise XendError('Invalid reason: %s' % reason) + if self.domid == 0: + raise XendError("Can't specify Domain-0") self.storeDom("control/shutdown", reason) diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py index a72ec74f5b..7c974f80a9 100644 --- a/tools/python/xen/xm/shutdown.py +++ b/tools/python/xen/xm/shutdown.py @@ -23,8 +23,6 @@ from xen.xend.XendClient import server from xen.xend import sxp from xen.xm.opts import * -DOM0_ID = '0' - gopts = Opts(use="""[options] [DOM] Shutdown one or more domains gracefully. @@ -51,14 +49,6 @@ gopts.opt('reboot', short='R', use='Shutdown and reboot.') def shutdown(opts, doms, mode, wait): - if doms == None: doms = server.xend.domains(0) - dom0_name = sxp.child_value(server.xend.domain(0), 'name') - for x in [dom0_name, DOM0_ID]: - if x in doms: - if opts.vals.all: - doms.remove(x) - else: - opts.err("Can't specify Domain-0") for d in doms: server.xend.domain.shutdown(d, mode) if wait: @@ -86,8 +76,11 @@ def shutdown_mode(opts): return 'poweroff' def main_all(opts, args): + doms = server.xend.domains(0) + dom0_name = sxp.child_value(server.xend.domain(0), 'name') + doms.remove(dom0_name) mode = shutdown_mode(opts) - shutdown(opts, None, mode, opts.vals.wait) + shutdown(opts, doms, mode, opts.vals.wait) def main_dom(opts, args): if len(args) == 0: opts.err('No domain parameter given') From e489d9a4e91250b6c0ddfa19b461ec5d76e71942 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:36:08 +0100 Subject: [PATCH 017/111] [XM] Print shorthelp of xm shutdown. # xm shutdown Error: 'xm shutdown' requires between 1 and 4 arguments. shutdown [-w][-a][-R|-H] Shutdown a domain # xm shutdown vm1 -w -a -R -H Error: 'xm shutdown' requires between 1 and 4 arguments. shutdown [-w][-a][-R|-H] Shutdown a domain Signed-off-by: Masaki Kanno --- tools/python/xen/xm/main.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index f34ad0947e..b6d1dcb63c 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -569,6 +569,11 @@ def xm_reboot(args): from xen.xm import shutdown shutdown.main(["shutdown", "-R"] + args) +def xm_shutdown(args): + arg_check(args, "shutdown", 1, 4) + from xen.xm import shutdown + shutdown.main(["shutdown"] + args) + def xm_pause(args): arg_check(args, "pause", 1) dom = args[0] @@ -1109,6 +1114,7 @@ commands = { "restore": xm_restore, "save": xm_save, "reboot": xm_reboot, + "shutdown": xm_shutdown, "list": xm_list, # memory commands "mem-max": xm_mem_max, @@ -1151,7 +1157,6 @@ subcommands = [ 'create', 'migrate', 'sysrq', - 'shutdown', 'labels', 'addlabel', 'rmlabel', From cef4d5d58aab4fbddb5394d492188a072be843f0 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 28 Jul 2006 17:52:57 +0100 Subject: [PATCH 018/111] [NET] front: Fix the build (broken my me a few changesets back). Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 2bfd63acd8..bf7a57e0f1 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -1170,6 +1170,7 @@ static void network_connect(struct net_device *dev) struct netfront_info *np = netdev_priv(dev); int i, requeue_idx; struct sk_buff *skb; + grant_ref_t ref; xennet_set_features(dev); From 6a999d5ed854727911f9c83c5a0229f6c48d0a32 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Sat, 29 Jul 2006 13:06:41 +0100 Subject: [PATCH 019/111] Add back changes lost from xen-ia64 cset 10570:8dc4af3f192c with the new qemu tree. Signed-off-by: Alex Williamson --- tools/ioemu/vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index ca045a3c64..d5f71c45ca 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5792,7 +5792,7 @@ int main(int argc, char **argv) } if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, - nr_pages + (GFW_SIZE >> PAGE_SHIFT), 1)!= 1){ + IO_PAGE_START >> PAGE_SHIFT, 1) != 1){ fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); exit(-1); } @@ -5801,7 +5801,7 @@ int main(int argc, char **argv) PROT_READ|PROT_WRITE, page_array[0]); - fprintf(logfile, "shared page at pfn:%lx, mfn: %l016x\n", + fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n", IO_PAGE_START >> PAGE_SHIFT, page_array[0]); #endif #else /* !CONFIG_DM */ From d763fcc1635f3dfc4af6da15a3f329cbe0e3e14e Mon Sep 17 00:00:00 2001 From: "vhanquez@gwig.uk.xensource.com" Date: Sat, 29 Jul 2006 14:05:59 +0100 Subject: [PATCH 020/111] Limit the number of opened transactions per connection to 5. Signed-off-by: Vincent Hanquez --- tools/xenstore/xenstored_transaction.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index f9d844e045..a3f2157256 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -125,6 +125,7 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) { struct transaction *trans, *exists; char id_str[20]; + int started; /* We don't support nested transactions. */ if (conn->transaction) { @@ -132,6 +133,15 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) return; } + started = 0; + list_for_each_entry(trans, &conn->transaction_list, list) + started++; + + if (started > 5) { + send_error(conn, ENOSPC); + return; + } + /* Attach transaction to input for autofree until it's complete */ trans = talloc(in, struct transaction); INIT_LIST_HEAD(&trans->changes); From 8d79f14a5d89af02c8a9dd3710228c4d7c20b237 Mon Sep 17 00:00:00 2001 From: "vhanquez@gwig.uk.xensource.com" Date: Mon, 31 Jul 2006 09:30:36 +0000 Subject: [PATCH 021/111] Add a transaction_started field in xenstored connection structure instead of browsing the list of transaction each time Bump the default to 10, and make it configurable through the command line. Signed-off-by: Vincent Hanquez --- tools/xenstore/xenstored_core.c | 9 ++++++++- tools/xenstore/xenstored_core.h | 1 + tools/xenstore/xenstored_transaction.c | 10 ++++------ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 25330f9906..2511e4a5fc 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -80,6 +80,7 @@ static void check_store(void); int quota_nb_entry_per_domain = 1000; int quota_nb_watch_per_domain = 128; int quota_max_entry_size = 2048; /* 2K */ +int quota_max_transaction = 10; #ifdef TESTING static bool failtest = false; @@ -1342,6 +1343,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) new->write = write; new->read = read; new->can_write = true; + new->transaction_started = 0; INIT_LIST_HEAD(&new->out_list); INIT_LIST_HEAD(&new->watches); INIT_LIST_HEAD(&new->transaction_list); @@ -1739,6 +1741,7 @@ static void usage(void) " --entry-nb limit the number of entries per domain,\n" " --entry-size limit the size of entry per domain, and\n" " --entry-watch limit the number of watches per domain,\n" +" --transaction limit the number of transaction allowed per domain,\n" " --no-recovery to request that no recovery should be attempted when\n" " the store is corrupted (debug only),\n" " --preserve-local to request that /local is preserved on start-up,\n" @@ -1755,6 +1758,7 @@ static struct option options[] = { { "output-pid", 0, NULL, 'P' }, { "entry-size", 1, NULL, 'S' }, { "trace-file", 1, NULL, 'T' }, + { "transaction", 1, NULL, 't' }, { "no-recovery", 0, NULL, 'R' }, { "preserve-local", 0, NULL, 'L' }, { "verbose", 0, NULL, 'V' }, @@ -1774,7 +1778,7 @@ int main(int argc, char *argv[]) const char *pidfile = NULL; int evtchn_fd = -1; - while ((opt = getopt_long(argc, argv, "DE:F:HNPS:T:RLVW:", options, + while ((opt = getopt_long(argc, argv, "DE:F:HNPS:t:T:RLVW:", options, NULL)) != -1) { switch (opt) { case 'D': @@ -1804,6 +1808,9 @@ int main(int argc, char *argv[]) case 'S': quota_max_entry_size = strtol(optarg, NULL, 10); break; + case 't': + quota_max_transaction = strtol(optarg, NULL, 10); + break; case 'T': tracefile = optarg; break; diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index f16d018047..0849e7ba78 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -79,6 +79,7 @@ struct connection /* List of in-progress transactions. */ struct list_head transaction_list; uint32_t next_transaction_id; + unsigned int transaction_started; /* The domain I'm associated with, if any. */ struct domain *domain; diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index a3f2157256..fb20287f99 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -66,6 +66,7 @@ struct transaction struct list_head changes; }; +extern int quota_max_transaction; static unsigned int generation; /* Return tdb context to use for this connection. */ @@ -125,7 +126,6 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) { struct transaction *trans, *exists; char id_str[20]; - int started; /* We don't support nested transactions. */ if (conn->transaction) { @@ -133,11 +133,7 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) return; } - started = 0; - list_for_each_entry(trans, &conn->transaction_list, list) - started++; - - if (started > 5) { + if (conn->transaction_started > quota_max_transaction) { send_error(conn, ENOSPC); return; } @@ -166,6 +162,7 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) list_add_tail(&trans->list, &conn->transaction_list); talloc_steal(conn, trans); talloc_set_destructor(trans, destroy_transaction); + conn->transaction_started++; sprintf(id_str, "%u", trans->id); send_reply(conn, XS_TRANSACTION_START, id_str, strlen(id_str)+1); @@ -188,6 +185,7 @@ void do_transaction_end(struct connection *conn, const char *arg) conn->transaction = NULL; list_del(&trans->list); + conn->transaction_started--; /* Attach transaction to arg for auto-cleanup */ talloc_steal(arg, trans); From b4b462732b89593c721f7852a5323ee18fd367ea Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 10:40:21 +0100 Subject: [PATCH 022/111] [XEN] Some suspicion that we may enter an infinite #PF loop due to broken spurious pagefault detection. Beef up the tracing on that code path so we can catch some useful info if it happens. Signed-off-by: Keir Fraser --- xen/arch/x86/traps.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index aac1d70e76..44913b2f42 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -733,7 +733,10 @@ static int __spurious_page_fault( (l2e_get_flags(l2e) & disallowed_flags) ) return 0; if ( l2e_get_flags(l2e) & _PAGE_PSE ) - return 1; + { + l1e = l1e_empty(); /* define before use in debug tracing */ + goto spurious; + } l1t = map_domain_page(mfn); l1e = l1t[l1_table_offset(addr)]; @@ -742,6 +745,22 @@ static int __spurious_page_fault( if ( !(l1e_get_flags(l1e) & required_flags) || (l1e_get_flags(l1e) & disallowed_flags) ) return 0; + + spurious: + DPRINTK("Spurious fault in domain %u:%u at addr %lx, e/c %04x\n", + current->domain->domain_id, current->vcpu_id, + addr, regs->error_code); +#if CONFIG_PAGING_LEVELS >= 4 + DPRINTK(" l4e = %"PRIpte"\n", l4e_get_intpte(l4e)); +#endif +#if CONFIG_PAGING_LEVELS >= 3 + DPRINTK(" l3e = %"PRIpte"\n", l3e_get_intpte(l3e)); +#endif + DPRINTK(" l2e = %"PRIpte"\n", l2e_get_intpte(l2e)); + DPRINTK(" l1e = %"PRIpte"\n", l1e_get_intpte(l1e)); +#ifndef NDEBUG + show_registers(regs); +#endif return 1; } @@ -839,11 +858,7 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) if ( unlikely(!guest_mode(regs)) ) { if ( spurious_page_fault(addr, regs) ) - { - DPRINTK("Spurious fault in domain %u:%u at addr %lx\n", - current->domain->domain_id, current->vcpu_id, addr); return EXCRET_not_a_fault; - } if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) { From 0e81c9938ed27d7f9b83d2116c4127ae9d827722 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 17:29:00 +0100 Subject: [PATCH 023/111] [NET] back: Added tx queue This patch adds a tx queue to the backend if the frontend supports rx refill notification. A queue is needed because SG/TSO greatly reduces the number of packets that can be stored in the rx ring. Given an rx ring with 256 entries, a maximum TSO packet can occupy as many as 18 entries, meaning that the entire ring can only hold 14 packets. This is too small at high bandwidths with large TCP RX windows. Having a tx queue does not present a new security risk as the queue is a fixed size buffer just like the rx ring. So each guest can only hold a fixed amount of memory (proportional to the tx queue length) on the host. Signed-off-by: Herbert Xu Cannot BUG_ON netbk_queue_full yet !netbk_can_queue, as this can be triggered by a misbehaving client. Set req_event appropriately when stopping the packet queue, or we will not receive a notification. Signed-off-by: Keir Fraser --- .../drivers/xen/netback/common.h | 10 ++++++ .../drivers/xen/netback/interface.c | 9 ++--- .../drivers/xen/netback/netback.c | 36 ++++++++++++++++--- .../drivers/xen/netback/xenbus.c | 10 ++++++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h index 3ba0251dca..2783020a23 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h @@ -76,6 +76,10 @@ typedef struct netif_st { struct vm_struct *tx_comms_area; struct vm_struct *rx_comms_area; + /* Set of features that can be turned on in dev->features. */ + int features; + int can_queue; + /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */ RING_IDX rx_req_cons_peek; @@ -119,4 +123,10 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev); struct net_device_stats *netif_be_get_stats(struct net_device *dev); irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs); +static inline int netbk_can_queue(struct net_device *dev) +{ + netif_t *netif = netdev_priv(dev); + return netif->can_queue; +} + #endif /* __NETIF__BACKEND__COMMON_H__ */ diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index b5decfd3ea..4253008e51 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -51,14 +51,12 @@ static int net_open(struct net_device *dev) netif_t *netif = netdev_priv(dev); if (netif_carrier_ok(dev)) __netif_up(netif); - netif_start_queue(dev); return 0; } static int net_close(struct net_device *dev) { netif_t *netif = netdev_priv(dev); - netif_stop_queue(dev); if (netif_carrier_ok(dev)) __netif_down(netif); return 0; @@ -107,8 +105,11 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]) SET_ETHTOOL_OPS(dev, &network_ethtool_ops); - /* Disable queuing. */ - dev->tx_queue_len = 0; + /* + * Reduce default TX queuelen so that each guest interface only + * allows it to eat around 6.4MB of host memory. + */ + dev->tx_queue_len = 100; for (i = 0; i < ETH_ALEN; i++) if (be_mac[i] != 0) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 80d16b7576..4fa33527ec 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -136,6 +136,14 @@ static inline int is_xen_skb(struct sk_buff *skb) return (cp == skbuff_cachep); } +static inline int netbk_queue_full(netif_t *netif) +{ + RING_IDX peek = netif->rx_req_cons_peek; + + return ((netif->rx.sring->req_prod - peek) <= 0) || + ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) <= 0); +} + int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_t *netif = netdev_priv(dev); @@ -143,12 +151,16 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(skb->dev != dev); /* Drop the packet if the target domain has no receive buffers. */ - if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)) || - (netif->rx_req_cons_peek == netif->rx.sring->req_prod) || - ((netif->rx_req_cons_peek - netif->rx.rsp_prod_pvt) == - NET_RX_RING_SIZE)) + if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev))) goto drop; + if (unlikely(netbk_queue_full(netif))) { + /* Not a BUG_ON() -- misbehaving netfront can trigger this. */ + if (netbk_can_queue(dev)) + DPRINTK("Queue full but not stopped!\n"); + goto drop; + } + /* * We do not copy the packet unless: * 1. The data is shared; or @@ -178,6 +190,13 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) netif->rx_req_cons_peek++; netif_get(netif); + if (netbk_can_queue(dev) && netbk_queue_full(netif)) { + netif->rx.sring->req_event = netif->rx_req_cons_peek + 1; + mb(); /* request notification /then/ check & stop the queue */ + if (netbk_queue_full(netif)) + netif_stop_queue(dev); + } + skb_queue_tail(&rx_queue, skb); tasklet_schedule(&net_rx_tasklet); @@ -351,6 +370,10 @@ static void net_rx_action(unsigned long unused) notify_list[notify_nr++] = irq; } + if (netif_queue_stopped(netif->dev) && + !netbk_queue_full(netif)) + netif_wake_queue(netif->dev); + netif_put(netif); dev_kfree_skb(skb); gop++; @@ -974,8 +997,13 @@ static void netif_page_release(struct page *page) irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs) { netif_t *netif = dev_id; + add_to_net_schedule_list_tail(netif); maybe_schedule_tx_action(); + + if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif)) + netif_wake_queue(netif->dev); + return IRQ_HANDLED; } diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c index fd3d70459e..bcc9a794bd 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @@ -353,6 +353,7 @@ static int connect_rings(struct backend_info *be) unsigned long tx_ring_ref, rx_ring_ref; unsigned int evtchn; int err; + int val; DPRINTK(""); @@ -367,6 +368,15 @@ static int connect_rings(struct backend_info *be) return err; } + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-notify", "%d", + &val) < 0) + val = 0; + if (val) + be->netif->can_queue = 1; + else + /* Must be non-zero for pfifo_fast to work. */ + be->netif->dev->tx_queue_len = 1; + /* Map the shared frame, irq etc. */ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn); if (err) { From 0cfb94daa194f4f0cec431d9796ee18ca95c74bc Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 17:35:43 +0100 Subject: [PATCH 024/111] [NET] front: Add SG support This patch adds scatter-and-gather support to the frontend. It also advertises this fact through xenbus so that the backend can detect this and send through SG requests only if it is supported. SG support is required to support skb's larger than one page. This in turn is needed for either jumbo MTU or TSO. One of these is required to bring local networking performance up to a level that is acceptable. Signed-off-by: Herbert Xu --- .../drivers/xen/netfront/netfront.c | 341 +++++++++++------- 1 file changed, 212 insertions(+), 129 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index bf7a57e0f1..8d75229f40 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -46,11 +46,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -62,18 +62,13 @@ #include #include +#define RX_COPY_THRESHOLD 256 + #define GRANT_INVALID_REF 0 #define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE) #define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE) -static inline void init_skb_shinfo(struct sk_buff *skb) -{ - atomic_set(&(skb_shinfo(skb)->dataref), 1); - skb_shinfo(skb)->nr_frags = 0; - skb_shinfo(skb)->frag_list = NULL; -} - struct netfront_info { struct list_head list; struct net_device *netdev; @@ -332,6 +327,12 @@ again: goto abort_transaction; } + err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); + if (err) { + message = "writing feature-sg"; + goto abort_transaction; + } + err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) @@ -575,10 +576,13 @@ static void network_alloc_rx_buffers(struct net_device *dev) unsigned short id; struct netfront_info *np = netdev_priv(dev); struct sk_buff *skb; + struct page *page; int i, batch_target, notify; RING_IDX req_prod = np->rx.req_prod_pvt; struct xen_memory_reservation reservation; grant_ref_t ref; + unsigned long pfn; + void *vaddr; if (unlikely(!netif_carrier_ok(dev))) return; @@ -591,15 +595,16 @@ static void network_alloc_rx_buffers(struct net_device *dev) */ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons); for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) { - /* - * Subtract dev_alloc_skb headroom (16 bytes) and shared info - * tailroom then round down to SKB_DATA_ALIGN boundary. - */ - skb = __dev_alloc_skb( - ((PAGE_SIZE - sizeof(struct skb_shared_info)) & - (-SKB_DATA_ALIGN(1))) - 16, - GFP_ATOMIC|__GFP_NOWARN); - if (skb == NULL) { + /* Allocate an skb and a page. */ + skb = __dev_alloc_skb(RX_COPY_THRESHOLD, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(!skb)) + goto no_skb; + + page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); + if (!page) { + kfree_skb(skb); +no_skb: /* Any skbuffs queued for refill? Force them out. */ if (i != 0) goto refill; @@ -608,6 +613,9 @@ static void network_alloc_rx_buffers(struct net_device *dev) jiffies + (HZ/10)); break; } + + skb_shinfo(skb)->frags[0].page = page; + skb_shinfo(skb)->nr_frags = 1; __skb_queue_tail(&np->rx_batch, skb); } @@ -639,18 +647,20 @@ static void network_alloc_rx_buffers(struct net_device *dev) ref = gnttab_claim_grant_reference(&np->gref_rx_head); BUG_ON((signed short)ref < 0); np->grant_rx_ref[id] = ref; + + pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page); + vaddr = page_address(skb_shinfo(skb)->frags[0].page); + gnttab_grant_foreign_transfer_ref(ref, - np->xbdev->otherend_id, - __pa(skb->head)>>PAGE_SHIFT); + np->xbdev->otherend_id, pfn); RING_GET_REQUEST(&np->rx, req_prod + i)->gref = ref; - np->rx_pfn_array[i] = virt_to_mfn(skb->head); + np->rx_pfn_array[i] = pfn_to_mfn(pfn); if (!xen_feature(XENFEAT_auto_translated_physmap)) { /* Remove this page before passing back to Xen. */ - set_phys_to_machine(__pa(skb->head) >> PAGE_SHIFT, - INVALID_P2M_ENTRY); + set_phys_to_machine(pfn, INVALID_P2M_ENTRY); MULTI_update_va_mapping(np->rx_mcl+i, - (unsigned long)skb->head, + (unsigned long)vaddr, __pte(0), 0); } } @@ -889,19 +899,145 @@ static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, np->rx.req_prod_pvt++; } +static int xennet_get_responses(struct netfront_info *np, + struct netif_rx_response *rx, RING_IDX rp, + struct sk_buff_head *list, int count) +{ + struct mmu_update *mmu = np->rx_mmu + count; + struct multicall_entry *mcl = np->rx_mcl + count; + RING_IDX cons = np->rx.rsp_cons; + struct sk_buff *skb = xennet_get_rx_skb(np, cons); + grant_ref_t ref = xennet_get_rx_ref(np, cons); + int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD); + int frags = 1; + int err = 0; + + for (;;) { + unsigned long mfn; + + if (unlikely(rx->status < 0 || + rx->offset + rx->status > PAGE_SIZE)) { + if (net_ratelimit()) + WPRINTK("rx->offset: %x, size: %u\n", + rx->offset, rx->status); + err = -EINVAL; + } + + /* + * This definitely indicates a bug, either in this driver or in + * the backend driver. In future this should flag the bad + * situation to the system controller to reboot the backed. + */ + if (ref == GRANT_INVALID_REF) { + WPRINTK("Bad rx response id %d.\n", rx->id); + err = -EINVAL; + goto next; + } + + /* Memory pressure, insufficient buffer headroom, ... */ + if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) { + if (net_ratelimit()) + WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", + rx->id, rx->status); + xennet_move_rx_slot(np, skb, ref); + err = -ENOMEM; + goto next; + } + + gnttab_release_grant_reference(&np->gref_rx_head, ref); + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* Remap the page. */ + struct page *page = skb_shinfo(skb)->frags[0].page; + unsigned long pfn = page_to_pfn(page); + void *vaddr = page_address(page); + + MULTI_update_va_mapping(mcl, (unsigned long)vaddr, + pfn_pte_ma(mfn, PAGE_KERNEL), + 0); + mcl++; + mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT) + | MMU_MACHPHYS_UPDATE; + mmu->val = pfn; + mmu++; + + set_phys_to_machine(pfn, mfn); + } + + __skb_queue_tail(list, skb); + +next: + if (!(rx->flags & NETRXF_more_data)) + break; + + if (cons + frags == rp) { + if (net_ratelimit()) + WPRINTK("Need more frags\n"); + err = -ENOENT; + break; + } + + rx = RING_GET_RESPONSE(&np->rx, cons + frags); + skb = xennet_get_rx_skb(np, cons + frags); + ref = xennet_get_rx_ref(np, cons + frags); + frags++; + } + + if (unlikely(frags > max)) { + if (net_ratelimit()) + WPRINTK("Too many frags\n"); + err = -E2BIG; + } + + return err; +} + +static RING_IDX xennet_fill_frags(struct netfront_info *np, + struct sk_buff *skb, + struct sk_buff_head *list) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + int nr_frags = shinfo->nr_frags; + RING_IDX cons = np->rx.rsp_cons; + skb_frag_t *frag = shinfo->frags + nr_frags; + struct sk_buff *nskb; + + while ((nskb = __skb_dequeue(list))) { + struct netif_rx_response *rx = + RING_GET_RESPONSE(&np->rx, ++cons); + + frag->page = skb_shinfo(nskb)->frags[0].page; + frag->page_offset = rx->offset; + frag->size = rx->status; + + skb->data_len += rx->status; + + skb_shinfo(nskb)->nr_frags = 0; + kfree_skb(nskb); + + frag++; + nr_frags++; + } + + shinfo->nr_frags = nr_frags; + return cons; +} + static int netif_poll(struct net_device *dev, int *pbudget) { struct netfront_info *np = netdev_priv(dev); - struct sk_buff *skb, *nskb; + struct sk_buff *skb; struct netif_rx_response *rx; RING_IDX i, rp; - struct mmu_update *mmu = np->rx_mmu; - struct multicall_entry *mcl = np->rx_mcl; + struct multicall_entry *mcl; int work_done, budget, more_to_do = 1; struct sk_buff_head rxq; + struct sk_buff_head errq; + struct sk_buff_head tmpq; unsigned long flags; - unsigned long mfn; - grant_ref_t ref; + unsigned int len; + int pages_done; + int err; spin_lock(&np->rx_lock); @@ -911,47 +1047,54 @@ static int netif_poll(struct net_device *dev, int *pbudget) } skb_queue_head_init(&rxq); + skb_queue_head_init(&errq); + skb_queue_head_init(&tmpq); if ((budget = *pbudget) > dev->quota) budget = dev->quota; rp = np->rx.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - for (i = np->rx.rsp_cons, work_done = 0; + for (i = np->rx.rsp_cons, work_done = 0, pages_done = 0; (i != rp) && (work_done < budget); - i++, work_done++) { + np->rx.rsp_cons = ++i, work_done++) { rx = RING_GET_RESPONSE(&np->rx, i); - skb = xennet_get_rx_skb(np, i); - ref = xennet_get_rx_ref(np, i); + err = xennet_get_responses(np, rx, rp, &tmpq, pages_done); + pages_done += skb_queue_len(&tmpq); - /* - * This definitely indicates a bug, either in this driver or in - * the backend driver. In future this should flag the bad - * situation to the system controller to reboot the backed. - */ - if (ref == GRANT_INVALID_REF) { - WPRINTK("Bad rx response id %d.\n", rx->id); + if (unlikely(err)) { + i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1; work_done--; + while ((skb = __skb_dequeue(&tmpq))) + __skb_queue_tail(&errq, skb); + np->stats.rx_errors++; continue; } - /* Memory pressure, insufficient buffer headroom, ... */ - if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) { - if (net_ratelimit()) - WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", - rx->id, rx->status); - xennet_move_rx_slot(np, skb, ref); - work_done--; - continue; + skb = __skb_dequeue(&tmpq); + + skb->nh.raw = (void *)skb_shinfo(skb)->frags[0].page; + skb->h.raw = skb->nh.raw + rx->offset; + + len = rx->status; + if (len > RX_COPY_THRESHOLD) + len = RX_COPY_THRESHOLD; + skb_put(skb, len); + + if (rx->status > len) { + skb_shinfo(skb)->frags[0].page_offset = + rx->offset + len; + skb_shinfo(skb)->frags[0].size = rx->status - len; + skb->data_len = rx->status - len; + } else { + skb_shinfo(skb)->frags[0].page = NULL; + skb_shinfo(skb)->nr_frags = 0; } - gnttab_release_grant_reference(&np->gref_rx_head, ref); - - /* NB. We handle skb overflow later. */ - skb->data = skb->head + rx->offset; - skb->len = rx->status; - skb->tail = skb->data + skb->len; + i = xennet_fill_frags(np, skb, &tmpq); + skb->truesize += skb->data_len; + skb->len += skb->data_len; /* * Old backends do not assert data_validated but we @@ -967,96 +1110,38 @@ static int netif_poll(struct net_device *dev, int *pbudget) skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank); np->stats.rx_packets++; - np->stats.rx_bytes += rx->status; - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* Remap the page. */ - MULTI_update_va_mapping(mcl, (unsigned long)skb->head, - pfn_pte_ma(mfn, PAGE_KERNEL), - 0); - mcl++; - mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT) - | MMU_MACHPHYS_UPDATE; - mmu->val = __pa(skb->head) >> PAGE_SHIFT; - mmu++; - - set_phys_to_machine(__pa(skb->head) >> PAGE_SHIFT, - mfn); - } + np->stats.rx_bytes += skb->len; __skb_queue_tail(&rxq, skb); } /* Some pages are no longer absent... */ - balloon_update_driver_allowance(-work_done); + balloon_update_driver_allowance(-pages_done); /* Do all the remapping work, and M2P updates, in one big hypercall. */ - if (likely((mcl - np->rx_mcl) != 0)) { + if (likely(pages_done)) { + mcl = np->rx_mcl + pages_done; mcl->op = __HYPERVISOR_mmu_update; mcl->args[0] = (unsigned long)np->rx_mmu; - mcl->args[1] = mmu - np->rx_mmu; + mcl->args[1] = pages_done; mcl->args[2] = 0; mcl->args[3] = DOMID_SELF; - mcl++; - (void)HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl); + (void)HYPERVISOR_multicall(np->rx_mcl, pages_done + 1); } + while ((skb = __skb_dequeue(&errq))) + kfree_skb(skb); + while ((skb = __skb_dequeue(&rxq)) != NULL) { - if (skb->len > (dev->mtu + ETH_HLEN + 4)) { - if (net_ratelimit()) - printk(KERN_INFO "Received packet too big for " - "MTU (%d > %d)\n", - skb->len - ETH_HLEN - 4, dev->mtu); - skb->len = 0; - skb->tail = skb->data; - init_skb_shinfo(skb); - dev_kfree_skb(skb); - continue; - } + struct page *page = (struct page *)skb->nh.raw; + void *vaddr = page_address(page); - /* - * Enough room in skbuff for the data we were passed? Also, - * Linux expects at least 16 bytes headroom in each rx buffer. - */ - if (unlikely(skb->tail > skb->end) || - unlikely((skb->data - skb->head) < 16)) { - if (net_ratelimit()) { - if (skb->tail > skb->end) - printk(KERN_INFO "Received packet " - "is %zd bytes beyond tail.\n", - skb->tail - skb->end); - else - printk(KERN_INFO "Received packet " - "is %zd bytes before head.\n", - 16 - (skb->data - skb->head)); - } + memcpy(skb->data, vaddr + (skb->h.raw - skb->nh.raw), + skb_headlen(skb)); - nskb = __dev_alloc_skb(skb->len + 2, - GFP_ATOMIC|__GFP_NOWARN); - if (nskb != NULL) { - skb_reserve(nskb, 2); - skb_put(nskb, skb->len); - memcpy(nskb->data, skb->data, skb->len); - /* Copy any other fields we already set up. */ - nskb->dev = skb->dev; - nskb->ip_summed = skb->ip_summed; - nskb->proto_data_valid = skb->proto_data_valid; - nskb->proto_csum_blank = skb->proto_csum_blank; - } + if (page != skb_shinfo(skb)->frags[0].page) + __free_page(page); - /* Reinitialise and then destroy the old skbuff. */ - skb->len = 0; - skb->tail = skb->data; - init_skb_shinfo(skb); - dev_kfree_skb(skb); - - /* Switch old for new, if we copied the buffer. */ - if ((skb = nskb) == NULL) - continue; - } - - /* Set the shinfo area, which is hidden behind the data. */ - init_skb_shinfo(skb); /* Ethernet work: Delayed to here as it peeks the header. */ skb->protocol = eth_type_trans(skb, dev); @@ -1065,8 +1150,6 @@ static int netif_poll(struct net_device *dev, int *pbudget) dev->last_rx = jiffies; } - np->rx.rsp_cons = i; - /* If we get a callback with very few responses, reduce fill target. */ /* NB. Note exponential increase, linear decrease. */ if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > @@ -1210,7 +1293,7 @@ static void network_connect(struct net_device *dev) gnttab_grant_foreign_transfer_ref( ref, np->xbdev->otherend_id, - __pa(skb->data) >> PAGE_SHIFT); + page_to_pfn(skb_shinfo(np->rx_skbs[i])->frags->page)); RING_GET_REQUEST(&np->rx, requeue_idx)->gref = ref; RING_GET_REQUEST(&np->rx, requeue_idx)->id = requeue_idx; From ee5e8cb59c0a417644908bc2918f9fafc14c138a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 17:42:13 +0100 Subject: [PATCH 025/111] [NET] back: Transmit SG packets if supported This patch adds scatter-and-gather transmission support to the backend. This allows the MTU to be raised right now and the potential for TSO in future. Signed-off-by: Herbert Xu --- .../drivers/xen/netback/common.h | 6 + .../drivers/xen/netback/interface.c | 25 ++ .../drivers/xen/netback/netback.c | 421 ++++++++++++------ .../drivers/xen/netback/xenbus.c | 7 + xen/include/public/io/netif.h | 4 + 5 files changed, 328 insertions(+), 135 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h index 2783020a23..c5ec30071a 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h +++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h @@ -129,4 +129,10 @@ static inline int netbk_can_queue(struct net_device *dev) return netif->can_queue; } +static inline int netbk_can_sg(struct net_device *dev) +{ + netif_t *netif = netdev_priv(dev); + return netif->features & NETIF_F_SG; +} + #endif /* __NETIF__BACKEND__COMMON_H__ */ diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index 4253008e51..008d7fd1ca 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -62,10 +62,34 @@ static int net_close(struct net_device *dev) return 0; } +static int netbk_change_mtu(struct net_device *dev, int mtu) +{ + int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN; + + if (mtu > max) + return -EINVAL; + dev->mtu = mtu; + return 0; +} + +static int netbk_set_sg(struct net_device *dev, u32 data) +{ + if (data) { + netif_t *netif = netdev_priv(dev); + + if (!(netif->features & NETIF_F_SG)) + return -ENOSYS; + } + + return ethtool_op_set_sg(dev, data); +} + static struct ethtool_ops network_ethtool_ops = { .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = netbk_set_sg, .get_link = ethtool_op_get_link, }; @@ -101,6 +125,7 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]) dev->get_stats = netif_be_get_stats; dev->open = net_open; dev->stop = net_close; + dev->change_mtu = netbk_change_mtu; dev->features = NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(dev, &network_ethtool_ops); diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 4fa33527ec..55024ea297 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -40,6 +40,11 @@ /*#define NETBE_DEBUG_INTERRUPT*/ +struct netbk_rx_meta { + skb_frag_t frag; + int id; +}; + static void netif_idx_release(u16 pending_idx); static void netif_page_release(struct page *page); static void make_tx_response(netif_t *netif, @@ -100,21 +105,27 @@ static spinlock_t net_schedule_list_lock; static unsigned long mfn_list[MAX_MFN_ALLOC]; static unsigned int alloc_index = 0; -static unsigned long alloc_mfn(void) +static inline unsigned long alloc_mfn(void) +{ + return mfn_list[--alloc_index]; +} + +static int check_mfn(int nr) { - unsigned long mfn = 0; struct xen_memory_reservation reservation = { - .nr_extents = MAX_MFN_ALLOC, .extent_order = 0, .domid = DOMID_SELF }; - set_xen_guest_handle(reservation.extent_start, mfn_list); - if ( unlikely(alloc_index == 0) ) - alloc_index = HYPERVISOR_memory_op( - XENMEM_increase_reservation, &reservation); - if ( alloc_index != 0 ) - mfn = mfn_list[--alloc_index]; - return mfn; + + if (likely(alloc_index >= nr)) + return 0; + + set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index); + reservation.nr_extents = MAX_MFN_ALLOC - alloc_index; + alloc_index += HYPERVISOR_memory_op(XENMEM_increase_reservation, + &reservation); + + return alloc_index >= nr ? 0 : -ENOMEM; } static inline void maybe_schedule_tx_action(void) @@ -136,12 +147,87 @@ static inline int is_xen_skb(struct sk_buff *skb) return (cp == skbuff_cachep); } +static struct sk_buff *netbk_copy_skb(struct sk_buff *skb) +{ + struct skb_shared_info *ninfo; + struct sk_buff *nskb; + unsigned long offset; + int ret; + int len; + int headlen; + + nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC); + if (unlikely(!nskb)) + goto err; + + skb_reserve(nskb, 16); + headlen = nskb->end - nskb->data; + if (headlen > skb_headlen(skb)) + headlen = skb_headlen(skb); + ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen); + BUG_ON(ret); + + ninfo = skb_shinfo(nskb); + ninfo->gso_size = skb_shinfo(skb)->gso_size; + ninfo->gso_type = skb_shinfo(skb)->gso_type; + + offset = headlen; + len = skb->len - headlen; + + nskb->len = skb->len; + nskb->data_len = len; + nskb->truesize += len; + + while (len) { + struct page *page; + int copy; + int zero; + + if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) { + dump_stack(); + goto err_free; + } + + copy = len >= PAGE_SIZE ? PAGE_SIZE : len; + zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO; + + page = alloc_page(GFP_ATOMIC | zero); + if (unlikely(!page)) + goto err_free; + + ret = skb_copy_bits(skb, offset, page_address(page), copy); + BUG_ON(ret); + + ninfo->frags[ninfo->nr_frags].page = page; + ninfo->frags[ninfo->nr_frags].page_offset = 0; + ninfo->frags[ninfo->nr_frags].size = copy; + ninfo->nr_frags++; + + offset += copy; + len -= copy; + } + + offset = nskb->data - skb->data; + + nskb->h.raw = skb->h.raw + offset; + nskb->nh.raw = skb->nh.raw + offset; + nskb->mac.raw = skb->mac.raw + offset; + + return nskb; + + err_free: + kfree_skb(nskb); + err: + return NULL; +} + static inline int netbk_queue_full(netif_t *netif) { RING_IDX peek = netif->rx_req_cons_peek; - return ((netif->rx.sring->req_prod - peek) <= 0) || - ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) <= 0); + return ((netif->rx.sring->req_prod - peek) <= MAX_SKB_FRAGS) || + ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) <= + MAX_SKB_FRAGS); } int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -165,20 +251,12 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) * We do not copy the packet unless: * 1. The data is shared; or * 2. The data is not allocated from our special cache. - * NB. We also couldn't cope with fragmented packets, but we won't get - * any because we not advertise the NETIF_F_SG feature. + * 3. The data is fragmented. */ - if (skb_shared(skb) || skb_cloned(skb) || !is_xen_skb(skb)) { - int hlen = skb->data - skb->head; - int ret; - struct sk_buff *nskb = dev_alloc_skb(hlen + skb->len); + if (skb_cloned(skb) || skb_is_nonlinear(skb) || !is_xen_skb(skb)) { + struct sk_buff *nskb = netbk_copy_skb(skb); if ( unlikely(nskb == NULL) ) goto drop; - skb_reserve(nskb, hlen); - __skb_put(nskb, skb->len); - ret = skb_copy_bits(skb, -hlen, nskb->data - hlen, - skb->len + hlen); - BUG_ON(ret); /* Copy only the header fields we use in this driver. */ nskb->dev = skb->dev; nskb->ip_summed = skb->ip_summed; @@ -187,11 +265,12 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) skb = nskb; } - netif->rx_req_cons_peek++; + netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1; netif_get(netif); if (netbk_can_queue(dev) && netbk_queue_full(netif)) { - netif->rx.sring->req_event = netif->rx_req_cons_peek + 1; + netif->rx.sring->req_event = netif->rx_req_cons_peek + + MAX_SKB_FRAGS + 1; mb(); /* request notification /then/ check & stop the queue */ if (netbk_queue_full(netif)) netif_stop_queue(dev); @@ -227,116 +306,80 @@ int xen_network_done(void) } #endif -static void net_rx_action(unsigned long unused) +static u16 netbk_gop_frag(netif_t *netif, struct page *page, int count, int i) { - netif_t *netif = NULL; - s8 status; - u16 size, id, irq, flags; - multicall_entry_t *mcl; - mmu_update_t *mmu; - gnttab_transfer_t *gop; - unsigned long vdata, old_mfn, new_mfn; - struct sk_buff_head rxq; - struct sk_buff *skb; - int notify_nr = 0; - int ret; - /* - * Putting hundreds of bytes on the stack is considered rude. - * Static works because a tasklet can only be on one CPU at any time. - */ - static u16 notify_list[NET_RX_RING_SIZE]; + multicall_entry_t *mcl = rx_mcl + count; + mmu_update_t *mmu = rx_mmu + count; + gnttab_transfer_t *gop = grant_rx_op + count; + netif_rx_request_t *req; + unsigned long old_mfn, new_mfn; - skb_queue_head_init(&rxq); - - mcl = rx_mcl; - mmu = rx_mmu; - gop = grant_rx_op; - - while ((skb = skb_dequeue(&rx_queue)) != NULL) { - netif = netdev_priv(skb->dev); - vdata = (unsigned long)skb->data; - old_mfn = virt_to_mfn(vdata); - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* Memory squeeze? Back off for an arbitrary while. */ - if ((new_mfn = alloc_mfn()) == 0) { - if ( net_ratelimit() ) - WPRINTK("Memory squeeze in netback " - "driver.\n"); - mod_timer(&net_timer, jiffies + HZ); - skb_queue_head(&rx_queue, skb); - break; - } - /* - * Set the new P2M table entry before reassigning - * the old data page. Heed the comment in - * pgtable-2level.h:pte_page(). :-) - */ - set_phys_to_machine( - __pa(skb->data) >> PAGE_SHIFT, - new_mfn); - - MULTI_update_va_mapping(mcl, vdata, - pfn_pte_ma(new_mfn, - PAGE_KERNEL), 0); - mcl++; - - mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) | - MMU_MACHPHYS_UPDATE; - mmu->val = __pa(vdata) >> PAGE_SHIFT; - mmu++; - } - - gop->mfn = old_mfn; - gop->domid = netif->domid; - gop->ref = RING_GET_REQUEST( - &netif->rx, netif->rx.req_cons)->gref; - netif->rx.req_cons++; - gop++; - - __skb_queue_tail(&rxq, skb); - - /* Filled the batch queue? */ - if ((gop - grant_rx_op) == ARRAY_SIZE(grant_rx_op)) - break; - } + old_mfn = virt_to_mfn(page_address(page)); if (!xen_feature(XENFEAT_auto_translated_physmap)) { - if (mcl == rx_mcl) - return; + new_mfn = alloc_mfn(); - mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; + /* + * Set the new P2M table entry before reassigning + * the old data page. Heed the comment in + * pgtable-2level.h:pte_page(). :-) + */ + set_phys_to_machine(page_to_pfn(page), new_mfn); - if (mmu - rx_mmu) { - mcl->op = __HYPERVISOR_mmu_update; - mcl->args[0] = (unsigned long)rx_mmu; - mcl->args[1] = mmu - rx_mmu; - mcl->args[2] = 0; - mcl->args[3] = DOMID_SELF; - mcl++; - } + MULTI_update_va_mapping(mcl, (unsigned long)page_address(page), + pfn_pte_ma(new_mfn, PAGE_KERNEL), 0); - ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); - BUG_ON(ret != 0); + mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) | + MMU_MACHPHYS_UPDATE; + mmu->val = page_to_pfn(page); } - ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, - gop - grant_rx_op); - BUG_ON(ret != 0); + req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i); + gop->mfn = old_mfn; + gop->domid = netif->domid; + gop->ref = req->gref; + return req->id; +} - mcl = rx_mcl; - gop = grant_rx_op; - while ((skb = __skb_dequeue(&rxq)) != NULL) { - netif = netdev_priv(skb->dev); - size = skb->tail - skb->data; +static void netbk_gop_skb(struct sk_buff *skb, struct netbk_rx_meta *meta, + int count) +{ + netif_t *netif = netdev_priv(skb->dev); + int nr_frags = skb_shinfo(skb)->nr_frags; + int i; - atomic_set(&(skb_shinfo(skb)->dataref), 1); - skb_shinfo(skb)->nr_frags = 0; - skb_shinfo(skb)->frag_list = NULL; + for (i = 0; i < nr_frags; i++) { + meta[++count].frag = skb_shinfo(skb)->frags[i]; + meta[count].id = netbk_gop_frag(netif, meta[count].frag.page, + count, i + 1); + } - netif->stats.tx_bytes += size; - netif->stats.tx_packets++; + /* + * This must occur at the end to ensure that we don't trash + * skb_shinfo until we're done. + */ + meta[count - nr_frags].id = netbk_gop_frag(netif, + virt_to_page(skb->data), + count - nr_frags, 0); + netif->rx.req_cons += nr_frags + 1; +} +static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta) +{ + int i; + + for (i = 0; i < nr_frags; i++) + put_page(meta[i].frag.page); +} + +static int netbk_check_gop(int nr_frags, domid_t domid, int count) +{ + multicall_entry_t *mcl = rx_mcl + count; + gnttab_transfer_t *gop = grant_rx_op + count; + int status = NETIF_RSP_OKAY; + int i; + + for (i = 0; i <= nr_frags; i++) { if (!xen_feature(XENFEAT_auto_translated_physmap)) { /* The update_va_mapping() must not fail. */ BUG_ON(mcl->result != 0); @@ -344,10 +387,9 @@ static void net_rx_action(unsigned long unused) } /* Check the reassignment error code. */ - status = NETIF_RSP_OKAY; if (gop->status != 0) { DPRINTK("Bad status %d from grant transfer to DOM%u\n", - gop->status, netif->domid); + gop->status, domid); /* * Page no longer belongs to us unless GNTST_bad_page, * but that should be a fatal error anyway. @@ -355,17 +397,128 @@ static void net_rx_action(unsigned long unused) BUG_ON(gop->status == GNTST_bad_page); status = NETIF_RSP_ERROR; } - irq = netif->irq; - id = RING_GET_REQUEST(&netif->rx, netif->rx.rsp_prod_pvt)->id; - flags = 0; + gop++; + } + + return status; +} + +static void netbk_add_frag_responses(netif_t *netif, int status, + struct netbk_rx_meta *meta, int nr_frags) +{ + int i; + + for (i = 0; i < nr_frags; i++) { + int id = meta[i].id; + int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data; + + make_rx_response(netif, id, status, meta[i].frag.page_offset, + meta[i].frag.size, flags); + } +} + +static void net_rx_action(unsigned long unused) +{ + netif_t *netif = NULL; + s8 status; + u16 id, irq, flags; + multicall_entry_t *mcl; + struct sk_buff_head rxq; + struct sk_buff *skb; + int notify_nr = 0; + int ret; + int nr_frags; + int count; + + /* + * Putting hundreds of bytes on the stack is considered rude. + * Static works because a tasklet can only be on one CPU at any time. + */ + static u16 notify_list[NET_RX_RING_SIZE]; + static struct netbk_rx_meta meta[NET_RX_RING_SIZE]; + + skb_queue_head_init(&rxq); + + count = 0; + + while ((skb = skb_dequeue(&rx_queue)) != NULL) { + nr_frags = skb_shinfo(skb)->nr_frags; + *(int *)skb->cb = nr_frags; + + if (!xen_feature(XENFEAT_auto_translated_physmap) && + check_mfn(nr_frags + 1)) { + /* Memory squeeze? Back off for an arbitrary while. */ + if ( net_ratelimit() ) + WPRINTK("Memory squeeze in netback " + "driver.\n"); + mod_timer(&net_timer, jiffies + HZ); + skb_queue_head(&rx_queue, skb); + break; + } + + netbk_gop_skb(skb, meta, count); + + count += nr_frags + 1; + + __skb_queue_tail(&rxq, skb); + + /* Filled the batch queue? */ + if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE) + break; + } + + if (!count) + return; + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + mcl = rx_mcl + count; + + mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; + + mcl->op = __HYPERVISOR_mmu_update; + mcl->args[0] = (unsigned long)rx_mmu; + mcl->args[1] = count; + mcl->args[2] = 0; + mcl->args[3] = DOMID_SELF; + + ret = HYPERVISOR_multicall(rx_mcl, count + 1); + BUG_ON(ret != 0); + } + + ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, count); + BUG_ON(ret != 0); + + count = 0; + while ((skb = __skb_dequeue(&rxq)) != NULL) { + nr_frags = *(int *)skb->cb; + + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; + + netif = netdev_priv(skb->dev); + netif->stats.tx_bytes += skb->len; + netif->stats.tx_packets++; + + netbk_free_pages(nr_frags, meta + count + 1); + status = netbk_check_gop(nr_frags, netif->domid, count); + + id = meta[count].id; + flags = nr_frags ? NETRXF_more_data : 0; + if (skb->ip_summed == CHECKSUM_HW) /* local packet? */ flags |= NETRXF_csum_blank | NETRXF_data_validated; else if (skb->proto_data_valid) /* remote but checksummed? */ flags |= NETRXF_data_validated; - if (make_rx_response(netif, id, status, - (unsigned long)skb->data & ~PAGE_MASK, - size, flags) && - (rx_notify[irq] == 0)) { + + make_rx_response(netif, id, status, offset_in_page(skb->data), + skb_headlen(skb), flags); + netbk_add_frag_responses(netif, status, meta + count + 1, + nr_frags); + + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret); + irq = netif->irq; + if (ret && !rx_notify[irq]) { rx_notify[irq] = 1; notify_list[notify_nr++] = irq; } @@ -376,7 +529,7 @@ static void net_rx_action(unsigned long unused) netif_put(netif); dev_kfree_skb(skb); - gop++; + count += nr_frags + 1; } while (notify_nr != 0) { @@ -1046,7 +1199,6 @@ static int make_rx_response(netif_t *netif, { RING_IDX i = netif->rx.rsp_prod_pvt; netif_rx_response_t *resp; - int notify; resp = RING_GET_RESPONSE(&netif->rx, i); resp->offset = offset; @@ -1057,9 +1209,8 @@ static int make_rx_response(netif_t *netif, resp->status = (s16)st; netif->rx.rsp_prod_pvt = ++i; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, notify); - return notify; + return 0; } #ifdef NETBE_DEBUG_INTERRUPT diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c index bcc9a794bd..503afa6e0a 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @@ -377,6 +377,13 @@ static int connect_rings(struct backend_info *be) /* Must be non-zero for pfifo_fast to work. */ be->netif->dev->tx_queue_len = 1; + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0) + val = 0; + if (val) { + be->netif->features |= NETIF_F_SG; + be->netif->dev->features |= NETIF_F_SG; + } + /* Map the shared frame, irq etc. */ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn); if (err) { diff --git a/xen/include/public/io/netif.h b/xen/include/public/io/netif.h index b551006034..c17b864762 100644 --- a/xen/include/public/io/netif.h +++ b/xen/include/public/io/netif.h @@ -124,6 +124,10 @@ typedef struct netif_rx_request netif_rx_request_t; #define _NETRXF_csum_blank (1) #define NETRXF_csum_blank (1U<<_NETRXF_csum_blank) +/* Packet continues in the next request descriptor. */ +#define _NETRXF_more_data (2) +#define NETRXF_more_data (1U<<_NETRXF_more_data) + struct netif_rx_response { uint16_t id; uint16_t offset; /* Offset in page of start of received packet */ From 3fa4fb49fe1a8a531c9594a5472b085e01b63d55 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 17:45:22 +0100 Subject: [PATCH 026/111] [NET] front: Add TSO support This patch adds TCP Segmentation Offload (TSO) support to the frontend. It also advertises this fact through xenbus so that the frontend can detect this and send through TSO requests only if it is supported. This is done using an extra request slot which is indicated by a flag in the first slot. In future checksum offload can be done in the same way. Even though only TSO is supported for now the code actually supports GSO so it can be applied to any other protocol. The only missing bit is the detection of host support for a specific GSO protocol. Once that is added we can advertise all supported protocols to the guest. Signed-off-by: Herbert Xu Disable for now, as in domU->dom0 direction. Signed-off-by: Keir Fraser --- .../drivers/xen/netfront/netfront.c | 107 +++++++++++++++++- xen/include/public/io/netif.h | 4 + 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 8d75229f40..9ab89571de 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -116,6 +116,11 @@ struct netfront_info { struct mmu_update rx_mmu[NET_RX_RING_SIZE]; }; +struct netfront_rx_info { + struct netif_rx_response rx; + struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; +}; + /* * Access macros for acquiring freeing slots in tx_skbs[]. */ @@ -333,6 +338,14 @@ again: goto abort_transaction; } +#if 0 /* KAF: After the protocol is finalised. */ + err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); + if (err) { + message = "writing feature-gso-tcpv4"; + goto abort_transaction; + } +#endif + err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) @@ -899,12 +912,54 @@ static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, np->rx.req_prod_pvt++; } +int xennet_get_extras(struct netfront_info *np, + struct netif_extra_info *extras, RING_IDX rp) + +{ + struct netif_extra_info *extra; + RING_IDX cons = np->rx.rsp_cons; + int err = 0; + + do { + struct sk_buff *skb; + grant_ref_t ref; + + if (unlikely(cons + 1 == rp)) { + if (net_ratelimit()) + WPRINTK("Missing extra info\n"); + err = -EBADR; + break; + } + + extra = (struct netif_extra_info *) + RING_GET_RESPONSE(&np->rx, ++cons); + + if (unlikely(!extra->type || + extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { + if (net_ratelimit()) + WPRINTK("Invalid extra type: %d\n", + extra->type); + err = -EINVAL; + } else + memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); + + skb = xennet_get_rx_skb(np, cons); + ref = xennet_get_rx_ref(np, cons); + xennet_move_rx_slot(np, skb, ref); + } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); + + np->rx.rsp_cons = cons; + return err; +} + static int xennet_get_responses(struct netfront_info *np, - struct netif_rx_response *rx, RING_IDX rp, + struct netfront_rx_info *rinfo, RING_IDX rp, struct sk_buff_head *list, int count) { struct mmu_update *mmu = np->rx_mmu + count; struct multicall_entry *mcl = np->rx_mcl + count; + struct netif_rx_response *rx = &rinfo->rx; + struct netif_extra_info *extras = rinfo->extras; RING_IDX cons = np->rx.rsp_cons; struct sk_buff *skb = xennet_get_rx_skb(np, cons); grant_ref_t ref = xennet_get_rx_ref(np, cons); @@ -912,6 +967,11 @@ static int xennet_get_responses(struct netfront_info *np, int frags = 1; int err = 0; + if (rx->flags & NETRXF_extra_info) { + err = xennet_get_extras(np, extras, rp); + cons = np->rx.rsp_cons; + } + for (;;) { unsigned long mfn; @@ -1023,11 +1083,38 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np, return cons; } +static int xennet_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso) +{ + if (!gso->u.gso.size) { + if (net_ratelimit()) + WPRINTK("GSO size must not be zero.\n"); + return -EINVAL; + } + + /* Currently only TCPv4 S.O. is supported. */ + if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { + if (net_ratelimit()) + WPRINTK("Bad GSO type %d.\n", gso->u.gso.type); + return -EINVAL; + } + + skb_shinfo(skb)->gso_size = gso->u.gso.size; + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; + + /* Header must be checked, and gso_segs computed. */ + skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; + skb_shinfo(skb)->gso_segs = 0; + + return 0; +} + static int netif_poll(struct net_device *dev, int *pbudget) { struct netfront_info *np = netdev_priv(dev); struct sk_buff *skb; - struct netif_rx_response *rx; + struct netfront_rx_info rinfo; + struct netif_rx_response *rx = &rinfo.rx; + struct netif_extra_info *extras = rinfo.extras; RING_IDX i, rp; struct multicall_entry *mcl; int work_done, budget, more_to_do = 1; @@ -1058,12 +1145,14 @@ static int netif_poll(struct net_device *dev, int *pbudget) for (i = np->rx.rsp_cons, work_done = 0, pages_done = 0; (i != rp) && (work_done < budget); np->rx.rsp_cons = ++i, work_done++) { - rx = RING_GET_RESPONSE(&np->rx, i); + memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); + memset(extras, 0, sizeof(extras)); - err = xennet_get_responses(np, rx, rp, &tmpq, pages_done); + err = xennet_get_responses(np, &rinfo, rp, &tmpq, pages_done); pages_done += skb_queue_len(&tmpq); if (unlikely(err)) { +err: i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1; work_done--; while ((skb = __skb_dequeue(&tmpq))) @@ -1074,6 +1163,16 @@ static int netif_poll(struct net_device *dev, int *pbudget) skb = __skb_dequeue(&tmpq); + if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { + struct netif_extra_info *gso; + gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; + + if (unlikely(xennet_set_skb_gso(skb, gso))) { + __skb_queue_head(&tmpq, skb); + goto err; + } + } + skb->nh.raw = (void *)skb_shinfo(skb)->frags[0].page; skb->h.raw = skb->nh.raw + rx->offset; diff --git a/xen/include/public/io/netif.h b/xen/include/public/io/netif.h index c17b864762..c012d11bfa 100644 --- a/xen/include/public/io/netif.h +++ b/xen/include/public/io/netif.h @@ -128,6 +128,10 @@ typedef struct netif_rx_request netif_rx_request_t; #define _NETRXF_more_data (2) #define NETRXF_more_data (1U<<_NETRXF_more_data) +/* Packet to be followed by extra descriptor(s). */ +#define _NETRXF_extra_info (3) +#define NETRXF_extra_info (1U<<_NETRXF_extra_info) + struct netif_rx_response { uint16_t id; uint16_t offset; /* Offset in page of start of received packet */ From e40c413dc976d43067347109548bc02c6747eabe Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 17:49:36 +0100 Subject: [PATCH 027/111] [NET] back: Transmit TSO packets if supported This patch adds TSO transmission support to the backend. Signed-off-by: Herbert Xu Disable for now, as domU->dom0 direction. Signed-off-by: Keir Fraser --- .../drivers/xen/netback/interface.c | 14 ++++ .../drivers/xen/netback/netback.c | 75 +++++++++++++------ .../drivers/xen/netback/xenbus.c | 10 +++ 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c index 008d7fd1ca..d60b23b0f2 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c @@ -84,12 +84,26 @@ static int netbk_set_sg(struct net_device *dev, u32 data) return ethtool_op_set_sg(dev, data); } +static int netbk_set_tso(struct net_device *dev, u32 data) +{ + if (data) { + netif_t *netif = netdev_priv(dev); + + if (!(netif->features & NETIF_F_TSO)) + return -ENOSYS; + } + + return ethtool_op_set_tso(dev, data); +} + static struct ethtool_ops network_ethtool_ops = { .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = netbk_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = netbk_set_tso, .get_link = ethtool_op_get_link, }; diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 55024ea297..82832368b9 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -50,12 +50,12 @@ static void netif_page_release(struct page *page); static void make_tx_response(netif_t *netif, netif_tx_request_t *txp, s8 st); -static int make_rx_response(netif_t *netif, - u16 id, - s8 st, - u16 offset, - u16 size, - u16 flags); +static netif_rx_response_t *make_rx_response(netif_t *netif, + u16 id, + s8 st, + u16 offset, + u16 size, + u16 flags); static void net_tx_action(unsigned long unused); static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0); @@ -225,9 +225,9 @@ static inline int netbk_queue_full(netif_t *netif) { RING_IDX peek = netif->rx_req_cons_peek; - return ((netif->rx.sring->req_prod - peek) <= MAX_SKB_FRAGS) || + return ((netif->rx.sring->req_prod - peek) <= (MAX_SKB_FRAGS + 1)) || ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) <= - MAX_SKB_FRAGS); + (MAX_SKB_FRAGS + 1)); } int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -265,12 +265,13 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) skb = nskb; } - netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1; + netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 + + !!skb_shinfo(skb)->gso_size; netif_get(netif); if (netbk_can_queue(dev) && netbk_queue_full(netif)) { netif->rx.sring->req_event = netif->rx_req_cons_peek + - MAX_SKB_FRAGS + 1; + MAX_SKB_FRAGS + 2; mb(); /* request notification /then/ check & stop the queue */ if (netbk_queue_full(netif)) netif_stop_queue(dev); @@ -347,11 +348,16 @@ static void netbk_gop_skb(struct sk_buff *skb, struct netbk_rx_meta *meta, netif_t *netif = netdev_priv(skb->dev); int nr_frags = skb_shinfo(skb)->nr_frags; int i; + int extra; + + meta[count].frag.page_offset = skb_shinfo(skb)->gso_type; + meta[count].frag.size = skb_shinfo(skb)->gso_size; + extra = !!meta[count].frag.size + 1; for (i = 0; i < nr_frags; i++) { meta[++count].frag = skb_shinfo(skb)->frags[i]; meta[count].id = netbk_gop_frag(netif, meta[count].frag.page, - count, i + 1); + count, i + extra); } /* @@ -361,7 +367,7 @@ static void netbk_gop_skb(struct sk_buff *skb, struct netbk_rx_meta *meta, meta[count - nr_frags].id = netbk_gop_frag(netif, virt_to_page(skb->data), count - nr_frags, 0); - netif->rx.req_cons += nr_frags + 1; + netif->rx.req_cons += nr_frags + extra; } static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta) @@ -422,6 +428,8 @@ static void net_rx_action(unsigned long unused) netif_t *netif = NULL; s8 status; u16 id, irq, flags; + netif_rx_response_t *resp; + struct netif_extra_info *extra; multicall_entry_t *mcl; struct sk_buff_head rxq; struct sk_buff *skb; @@ -511,8 +519,33 @@ static void net_rx_action(unsigned long unused) else if (skb->proto_data_valid) /* remote but checksummed? */ flags |= NETRXF_data_validated; - make_rx_response(netif, id, status, offset_in_page(skb->data), - skb_headlen(skb), flags); + resp = make_rx_response(netif, id, status, + offset_in_page(skb->data), + skb_headlen(skb), flags); + + extra = NULL; + + if (meta[count].frag.size) { + struct netif_extra_info *gso = + (struct netif_extra_info *) + RING_GET_RESPONSE(&netif->rx, + netif->rx.rsp_prod_pvt++); + + if (extra) + extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE; + else + resp->flags |= NETRXF_extra_info; + + gso->u.gso.size = meta[count].frag.size; + gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; + gso->u.gso.pad = 0; + gso->u.gso.features = 0; + + gso->type = XEN_NETIF_EXTRA_TYPE_GSO; + gso->flags = 0; + extra = gso; + } + netbk_add_frag_responses(netif, status, meta + count + 1, nr_frags); @@ -1190,12 +1223,12 @@ static void make_tx_response(netif_t *netif, #endif } -static int make_rx_response(netif_t *netif, - u16 id, - s8 st, - u16 offset, - u16 size, - u16 flags) +static netif_rx_response_t *make_rx_response(netif_t *netif, + u16 id, + s8 st, + u16 offset, + u16 size, + u16 flags) { RING_IDX i = netif->rx.rsp_prod_pvt; netif_rx_response_t *resp; @@ -1210,7 +1243,7 @@ static int make_rx_response(netif_t *netif, netif->rx.rsp_prod_pvt = ++i; - return 0; + return resp; } #ifdef NETBE_DEBUG_INTERRUPT diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c index 503afa6e0a..eb51533942 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @@ -384,6 +384,16 @@ static int connect_rings(struct backend_info *be) be->netif->dev->features |= NETIF_F_SG; } +#if 0 /* KAF: After the protocol is finalised. */ + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d", + &val) < 0) + val = 0; + if (val) { + be->netif->features |= NETIF_F_TSO; + be->netif->dev->features |= NETIF_F_TSO; + } +#endif + /* Map the shared frame, irq etc. */ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn); if (err) { From 31c8886dc2adf4fb0bda8bb09b342080518e0fe4 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 18:07:25 +0100 Subject: [PATCH 028/111] [BLKTAP] Properly daemonise the blktap control daemon. Fixes bug #709. Signed-off-by: Harry Butterworth --- tools/blktap/drivers/blktapctrl.c | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/blktap/drivers/blktapctrl.c b/tools/blktap/drivers/blktapctrl.c index f4ade5b780..14a86d9088 100644 --- a/tools/blktap/drivers/blktapctrl.c +++ b/tools/blktap/drivers/blktapctrl.c @@ -622,6 +622,38 @@ static void print_drivers(void) DPRINTF("Found driver: [%s]\n",dtypes[i]->name); } +/* Stevens. */ +static void daemonize(void) +{ + pid_t pid; + + /* Separate from our parent via fork, so init inherits us. */ + if ((pid = fork()) < 0) + DPRINTF("Failed to fork daemon\n"); + if (pid != 0) + exit(0); + + /* Session leader so ^C doesn't whack us. */ + setsid(); + + /* Let session leader exit so child cannot regain CTTY */ + if ((pid = fork()) < 0) + DPRINTF("Failed to fork daemon\n"); + if (pid != 0) + exit(0); + + /* Move off any mount points we might be in. */ + if (chdir("/") == -1) + DPRINTF("Failed to chdir\n"); + + /* Discard our parent's old-fashioned umask prejudices. */ + umask(0); + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); +} + int main(int argc, char *argv[]) { char *devname; @@ -633,6 +665,7 @@ int main(int argc, char *argv[]) __init_blkif(); openlog("BLKTAPCTRL", LOG_CONS|LOG_ODELAY, LOG_DAEMON); + daemonize(); print_drivers(); init_driver_list(); From 50fe16d8b692218bc78775183f5c05e97ccb77c3 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 18:12:04 +0100 Subject: [PATCH 029/111] [DOCS][ACM] Update the user guide for Xen with a chapter describing the sHype/ACM security module for Xen. Section 10.2 offers a quick guide showing how to setup and test the workload protection with sHype/ACM in Xen. Signed-off by: Reiner Sailer --- docs/figs/acm_ezpolicy.eps | 657 ++++++++++++++++ docs/figs/acm_overview.eps | 1463 ++++++++++++++++++++++++++++++++++++ docs/src/user.tex | 982 ++++++++++++++++++++++++ 3 files changed, 3102 insertions(+) create mode 100644 docs/figs/acm_ezpolicy.eps create mode 100644 docs/figs/acm_overview.eps diff --git a/docs/figs/acm_ezpolicy.eps b/docs/figs/acm_ezpolicy.eps new file mode 100644 index 0000000000..3f8ce95870 --- /dev/null +++ b/docs/figs/acm_ezpolicy.eps @@ -0,0 +1,657 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%BoundingBox: 0 0 610 400 +% +% created by bmeps 1.2.6a (SCCS=1.78) +% +/pstr + 610 string +def +/inputf + currentfile + /ASCII85Decode filter + /RunLengthDecode filter +def +gsave +0 400 translate +610 400 scale +610 400 8 [610 0 0 -400 0 0] +{ inputf pstr readstring pop } +image +r;Qmd6ps=,r^.#_8PW)W:fC4d:Jq*eJka?]JkgnmP"tsM!)EGd%7s,^8OZ0@77fs; +77'??705qG4Sf!e6pt0dBlJ$6H@:BtK8,-ULk:B'L4Y6'Lk:B'LAZi1L4b55LA6Du +I0Fb9BjEhVr;R-m;-@(3Bk_O*G'831IK"hMI=cm!I=cmrIK"NpI=6EfrcJ3er,r'_ +rHA*Xrb2IA?VWW\rrbGT86&[hKU.P +?s?uGrEfn8='8U';G^7f;cEWm%T$&$92/,W:eEo6!<5/JrCmAj;cQlt>52>&>5_TU +=+XM*=+XN'A:QXo4rs"Q\9heEFlgauZO%i5;8rW'* +rt:&I2DR$=.30ck4@D_29hnM`;u9So;Z]fm;#X2j9hg44b"I=Ya\%.Vn4>s,jHtgV +I!BaVEH,o8Bk_3g>%QEJ8P+s'R#6KCG]\+KEGoc0BkLjXA_N/87uZW-R?PuC84ZHM;#O;n8qKZt8qKY(8Qc"] +Xg"XjQ&q#bMM[(?IsQ-K=^(,_8cP6]YbdeROH,9WM2$Y4H?*\%>3e[Ks/*9:Ybn+b +S=,_1P`h&aK6h<7s+3no97fdX8qKY(8Q>_M +ZF-X&R$3VkN/NLGJ:)KU>snW`8cOgV[A][aPE:c_Mhm(;I!'726iTYEs-p[8Z`0do +SXZ%8QBRAfL44&>s#)bg-mocQ1-@oo8l\nn='Jo.i +MMd.@J9u69s#)bg-n,oS1-@oo9%j!_lMlH/JkL\gN(Y,iJ=W=!O,8O?H?O=GChdZt +Ame7292#;8SY)8Bs!VPm?qUGg7/r=IX/+AIP)bETK7JFNaa8;R=oUB<0.87b,W7YM +8PB*YrqcWrn"3GU5QXKCkPG5V9+(@lPY78@PY78@p%(fWl1t3L!U9FI9*+;Qr(I%h +!r:o[fh2A7n*NdIrrW#WY4kQml1mtFn*f[;q>^"Y!U9E39BSs"8FT.Zs*U)uOc+pC +H?O:FC2!QX$"-C*84`c.Q'[X,rsNFN?qUGg7/r4?Un@Yd"H%teJ:.@r&UAV@=oUB< +0.81`,W7eQ8k]3Zrql]tLDXF&rkATFBGc!gr;QaLrC[OTs//K!s//K!s4/st9*5.n +0)S?Ds8O_>9*5.n0)\EIs8O0emJjZd9**Z;n4Nf6p&7Scn*W+%9*YFr++!>S\+iT# +s8O]En*W+%9*67Xs8W$>o1K/bs"8mrJkO]g)uk,DOc>0KI<]jPCM79h@Us%W9)hOW +s*'QeNVHZsLKCM.0e@:EbS8cMFVs*'?YM>r-RGB.V;B4PKO +@Urh;s$]?ULR=KsP`PhD!.b(K'6SA=G&UR`3&`K=.2F0e4\/:Bs7lTmrrT)Pa7fN7 +f/SQbrr>[i9+[?fj?`&1j?`&1H::K`s8UsT9,.F+hXsPAruXnjs1qA.ruXnjs8UsT +9*Fqfs66]]Sr(@IuruXm,s7nEChZ*W4r_!=mru_7? +%SKIAp&F]p9BlJO9;DOUqF^niru_55"5a(XhYp.MhZ*W4r_!=mruZhcJkO]g2?.WL +LkgY6I!BdQD/!Tm@U`hR8H2=Us)<[JL];mPG]dtBBkCoU@Ui_8s$fKXJWlCbP)kS" +rtK^$FEMbF=8t6=2D6Ts-oaOa925H]rWN9$k:#fjrrYO$s8Vsj./!U$s6'DCs7@C, +fDiO^s4'hs2Co9gJ-)qehc1*859-a+!45Wru]km]r1n\ +9hkZfS"frG9DqR2s8O08Q2fDffDiO^s4'h9E5#6JkL\gf1S%%Ck%(jK7A8nF`MA8B4YR^@pMS( +92#;$ItNFSIscK`Ec,Z*AcH4L>t4ic8H4.!P*;#gN/@Q6!do9;rcJ`h97S*CU+%H;+ +5u.I[+&;\4+%?5*5P>$u5u'R1:B1>9:/:ih+8Z!Z7fW9M:B1>99E5#QrD"[=ru[Qr +q0G:%ruX`1q*@dUruY#9ru^q6+$iXb6Vd:E61t8(7Jfgqs8O09:AXu47fW9MqYqX, +s7nrUs8O0m:4c6m:,W&bH\$d"J:2`gF`D;6B4PL\>"&Bc:B,!SJV*oPI9;#gPK;#gP;;#gP;s8O2=:^4i;\c:h7 +:A[j's8O0;;#gP;;#gPKs8O0;s8O`Ks8O0m;!:`-:@M"8s'p5#J:W6"H[9mXE,96" +@piD+s%Z>h@s39Ns+#QFH?XIMCh`oZ?s#er9M5>.L5_1SNrK%pL]@DJH?XLPBiG$r +5!(PO*%+&c,rDNass8F)U5YtBX +s8O0>;u6M9;ucY8;uck>;u6Ol*s2<=+8f%Qs8O0>;uck>qYqX9s7ma8s8O0>s8O2> +;ZZpurZ;h>:fI5j+&i48+&i4>+&i4>+8Z!ZqbmXjs8T>dqG7t-ruY'6qYqX6s7mc5 +ruY);q&`H5ruZhhJl(&q"TMhJH%#Ph-ZO$=An,.I5lXYWs'K_jIK+bEH[0gYEGfOk +@pW/#s%H,dF+T7.NrK%[M2-fart0HsE+`#I5^@oG_c,p2td3U6c8rp+&Z(ks09fJbqN,sruY3>s8O0;q>$4RqYqYj +s09fJbqS&TMp25$McAU6]N"q2+8o.?s8O2<<&XdV+&l4ms09fJbqN,nruY4gs2E4Y +fi6E"`DksP<)i_o+&l5>ru]qoZ-<6m0NA)P+&r:?+8o.?s8O2=<#"$cZ-<6m0N@oK ++&r:?+4C2.<9;g4&/5*s*K*=H?XOQDJK2Z>#@H_:/(\*I>*OWrre18 +L4t6YrtBHkA5E4n6U*Xf*%X0?9i=nP2`CLk!IoUsrs1^e4S/T;!%#DXrrKT"qGmjZ +s*@D/s40..<\3),s48>__aBO_dN,+%KAFq7Kc.ruY:go)JET7oiZ[s4/:f +dN,+%KAfs8U[m7om>!]Rj2JEGJrUs$T7>3\MI%4%;tC;c?Rn +<*!+(=]\a6TDecljs:#&rr2uBqYpW;3$8!$#"Th<>?Dt6,ffr`]mT ++'VrJ+%9C41/D+F+!4,S>7=%E8k:%&>?aB83?K@@>6,ffqHEtB+8oCG808pGr`^IA ++!4]k9JR\M?arH+'Vqk+'Vr?+!4,S>6Q)j>?`0kr*'1D+8T1D808pG +r`^"61/D*r+'VrC3?L7^>?eN8Vb$Se!?WE^>6@D<+%lN:"%XLU9)`#r;_h.#>No@D +=7B8os&39?smDP@T]Q,rr^IF!6k0:!T,#O +>M<9as8Va6;hA5*>I[l@s%QU'ASD!U&SGZa?WpH+7Q19N>Q7E"?tF$LBfKa:@UE;= +:e!AC<)im,CiaiII!U-dH?j^VEG]E#>"AT_7moBn*%!a::/b(k=]o$;?X[AP@VD,, +rr^IF!5J7-!P^mO?.rQes5&Yo?%Q:4>I[lqls!.]='Ad1>$>'3=&i0p9Lh>.pr>$>'4>$5!0)AR]"N;Hj)m7moBn)C@O8 +:/Fkh='&O/?!grI@>B+*rrOJHFT2:A,s7t#rrK<"Jm6o4!Zsj3Jm3h2[p)gtfi1+$ +6:4%+6UF((5?dEH<'1Z!!&elrrVp3mt+Mj<.\)$<97'h;,gCg:ejb]:JOSU9M.qU +9En*Z8k_iI8,G[^3\hU#4$,hk5!M:tr^6ZR"%WC+5l:QaPYjPb^\e$4BUAaN7Y4+# +7Y3qK5ljABqEY0I4[&a+!BiRE4V9e>4?>M_3]B#W4$#,8-9F:Wr]U?I5PdVIs8Qc! +o)Ag43<0#15LhuM5(YtM54UlB4#8W3,rf7*p#lPYs7[r!o`#'_0\?@)K'7gMK'7gM +`omXq3[Pak3+#APkl1S`cR>.RrrTYX\,QDZk^r#Mk^r$^6R!!'dt!!%W7K'7gMPir??3[Pak +3+#AVkkkD_kQ'fHmcaQKr9+7`kQ'fHo&p&RroaC`kQ'c/!!)u]!!)lZ!!%W7K'7gM +Pir??3[Pak3+#AVkPtVZkPtVNkPtVXkPtV^kPtVRkPtV^kPtVDkPtV]kPtVZkPtU7 +k^r#Mk`k996olY5,rf7*qre"[r9+7`kQ'i1rW)QR!!)o[r;Zo_!9jC^o]Q8TroaIb +kQ'i1rW!5fkQ'i1!9iVHo]Q8TrTF:_kii!G"6eqKkktL5k^r#MkaCW>6olY5,rf7* +qrmqX"m>sM!9aF^kPtVTkktJ_ki`$GkQCnL!9aFQkQ_+O!9iVHkQ(VG#QX&gki`$1 +kQ(8=qZ$Z\!<20b!9aFH!<20^!.sEdk^r#ekQaL:-5n0i?VL@\!!)r\!s%NbkkkGQ +kPtV\kPtV^kQCnL!9aFQkQV%N!9iVHkkkDckQ'fHkQ'fHo]Q8TrTF7^kkkD_kQ'fH +roa=^K'7gMK'8Ze#=LU")C7@M9`+#R!;u$`!9aFH!:]1P!;u$\!<20b!9aFH!:f7X +!9aFHkQ'fHr9+=bkQ'fHkQ(8=!!)u]!W_Ear9+1^kQ(VG!!%W7K'7gMRcjuE3[Pak +3+#AVkPtV\kQCnL!9aF^kPtVTkPtV\kPtV^kQCnL!9aFPkPtV^kQ1bJ!<20a!9iVH +roa=^oB6/SrTF:_kQ(VG"9@WckQ(VG!!%W7K'7gMRcjuE3[Pak3F>JWkPtV\kQCnL +!9iYG!;#FP!!2g?T!!%W7K'7gMQKSQA4I3k^r#Mk^r#nkQaL<+rVaf?VH(8 +K'7gMK'8un#=LZu)C7CN9S2J[k^r#MkbI>H6p)Y3,ro=+K'7gMK'7gMUZ_qN4I3s+:9&s+:9Grs(qS+rVaf?VH(8K'7gMK'8un#=LZu)C7CN9S2J[kecQKs+9Hd +kkXEI6p)Y3,ro=+K'7gM_W^:bK'7gMqI3k^r$8kj&2"k^r$okQaL< ++rVad?VH(8K':)8qYpWcT2>MP!_A[@qYu02K'<$o#=LZu)C7=L9S2J[kecQ\rr\#n +@'BRE"Li%]Gk_.9K'7gMqUMO0ZX.lK'7gM +q?!IoUsrs)CI +PlLb\!'L/Y!OkVskQ0#VK'8'T!R]6kkQaL<+rVad?VLC]!7$2[K'3=#jPJYOg?R2h +@%[5o"2@\54T#-Za#Nt[!7$2[TBH@;hV7n\rmh#%"5DVfjSe9Bchuu36p)Y3,rT+( +r9+.+K'7gM"R+_#N_@VN!Ec8trs.\.,p`O;!'L/Y!T,$skQ&n[kb%&@hVaDeoe6J5 +J)fPekQ&p+kQaL<,8qjd?VLC]!7$2[K'3@$gl?O$c2RfXQi-jg,lg&]b_6$Zqu6]3 +5l9aFc@Y8PkQ9P"8+Y^A7ul[/kQ&p+kQaL<,8qjd?VLC]!7$2[K'3=#ge5i7rW.e! +rVm/I!%$e-s'l$kqu6]#;#BGVc@Y8PkRuZDd*P)*6-qpE6-qpE6-qpE9DmuRcMZl2 +6p)\4,rT+(r9+.+K'7gM!pJAmrqt(=!QR1urs6gK!0mMY,lf7grrHN"qre%*K'8ij +"PYWV62^HR"4#4Hli$#IcMZl26p)\4,rT+(r9+.+K'7gM"6eMoqTSa:s!ZLtrs(Xd +!$qV-!%%RC!r!Q#qre%*K'8ij"5GTSc1Ul75KkhJrTF7,r9+AR4KquHNU!<<,r +kQ(Y`lf\B)0['+ls8VgAht6pOmkEAns82![cFW3?!!(O4!<<,ikQ(Y`gZSYLL +k?pjDrVucY!7'Kc!<<-!kQ(Y`ki`$I!9E>E!!)HN!<<,RkQ(Y`roa@_!;G[X!!(I2 +"5GTH2#d+U!!)Z`!!)Z`o>/6sm/?,JcMZl26p)\4,rT+(r9+.+puh_Y!<)*f!!)3_ +!9aC_kihmDroj:\"R,%L!9jC^"R,%L!9j:[roj:\!U/bF!!MKc!9iYE!!MNL!!)6^ +!;G[W!;bm[!!)u]!rr>bkkkD`ki`!Hkl(S\kktJdki`!HkPtVHqu?`\qu?`\rW)r] +qu?l`kPtVHrVuu_kkkGYkQ(Y`rTF=`!9iYE!!2UZFIs=4tJ%tgZqre%*hrk(@!<20c!!)6H!!*#^!WW5arW!&akPtVYkQ(Y` +roajm!9aC_ki`!Hki`!HkPtV^kQ(Y`r9+.]!;u$d!!)6H!!)3_!<20d!9aC_kPtV^ +kQCkckPtV^kQV%N!!)3_!<20`!!)6^!!DHK!!)r\!<<-!kQLqdki`!HroaRe!9aC_ +kPtV^kQCkckPtV^kPtVAkQBTo\ki7p!<<,unc\Ko\hNLLkQ&p+kQaL<,8qjd?VLC] +!7(B'!<<,ukQCkckPtV]kQ(Y`roa@_!;ks_!!)3_!<20b!!)3_!<)*^!!)lZ"TSPd +kPtV^kQCkckPtV^kQCkckPtV^kQ(Y`q<.eYq<.hZ!<)*a!!)3_!<20b!!)3_!<20_ +!!)o["98Gc!!)r\!<<-!kR7Fkki`!Hki`!HkPtV^kQCkckPtV^kQLqdki`!HqWIq[ +!<)*a!!)3_!<20j!!)6H!!)6H!!)3_!<20f!!)3_!9iVH!<20b!!)3_!<20b!!)3_ +!<20_!!)o["5GU%oDA([!:o^[!!)Te!!r,q!:g*inc/[gnc8^jrpg0l!:g*irpg3m +!:o[\!;c6hna,?km/?,JcLg<#cJRj_!<20_!!*#^"98Gc!!*#^!WW5aqu?i_kPtV^ +kRRXnkPtVHkPtVHkPtVH!!*#^!<<,tkkkG[kktJ`ki`!Hr9+7`!9aC_roaC`!9jC^ +rTF@a!9aC_roaIb!9aC_roa@_!;u'X!<20_!!*#^#64bf!!)3_!<20`!!)6^!8coA +gb?=Nr:0jg!<)HknPHeNm/?,JcMZl26p)\4,rT+(r9+.+puh_Y!<)*a!!)3_!<)*^ +!!*#^!rr>bkkb>]kPtV^kQCkckPtV^kQ(Y`rTO+Y"6eqK!<20b!!)3_!<20b!!)3_ +!<20_!!)lZ!!)fX!<<,ukQ1_akkY8\kPtV^kQ:ebkihmD!pBUar9+.]!<20h!!)6H +!!)6H!!)6Z!!;?a!<20c!!)6H!!)lZ!<<,ukQ1_akkY8dki`!Hki`!HkPtV^kQh.g +kPtVHkPtV^kQCkckPtV^kQCkckPtV^kQ(Y`qre.;0_=o5nc/[hncSpmnc/[fo(`:a +nc8^jrpg0l!:g*irpg3m!:o[\!;c6hna,?km/?,JcLg<#cJRgg!!)3_!<)*^!!*#^ +"98Gc!!*#^!<<,qkQ(Y`roadk!9aC_ki`!Hki`!HkkY;WkQ(Y`qWIq[!<20_!!)r\ +"98Gc!!*#^!rr>bkktJcki`!HkPtV^kQCkckPtV^kQ(Y`r9+7`!9aC_rTF7^!<20c +!!)3_!9j7Z!U/bG!9!&Cgb?0>p@8@V\$e!WrTF7,r9+AR4`ZS:bEkQ&p+kQaL<,8qjd?VLC]!7(B'!<<,ukQCkckPtV]kQ:ebkii!G!pBUa +roaIb!9aC_roaRe!9aC_kPtV\kQ(Y`roaLc!9iVH!<20b!!)3_!<20b!!)3_!<20_ +!!)o[!!)cW!<<-!kQLqdki`!HrTF=`kPtV^kQCkckPtV^kQCkckPtV\kQ(Y`roaaj +!9iVH!9iVH!9aC_rTF=`kPtV^kQLqdki`!HqWIq[!<20c!!)6H!!)u]$NTDS!!)6H +!!)3_!<20f!!)3_!9iVH!<20b!!)3_!<20b!!)3_!<20_!!)o["5GU$o)%qW!<)Eh +!:fUW!!i&a!!)QZ!!)odqu?ihnGiRfnb`C`nHA@Ij=os!kQ&p#kQ&ockQ(Y`roaRe +!9iVH!9iYG!!;?a!<20_!!)iY!<<-!kRRXnkPtVHkPtVHkPtVH!!)u]!!)r\!<<,t +kQh.gki`!HkPtV^kQh1P!!)3_!9iYG!!29`roaRe!9aC_kPtV^kQCkckPtV^kQ(Y` +r9+.]!<20e!!)6H!!)6HrW!,c!!)3_!<)*_!9aF^kQ(Y`iTLC!0XFjYnGrUirUC$[ +['MIQrTF7,r9+AR4^ki`!Hr94+["R#gckihmD!pBUaroaLc +!9aC_kkb>\kihmDroj=]"R#gckihpE"6eqK!<20_!!)o[!!)cWqZ-TYqu?c]kkbAZ +kkb>]kPtV[kl(PjkPtVHkPtVHkPtVHkkkD_ki`!Hroa@_!<23]!;u'X!<)-Z!<20f +!!)6H!!)3_!<20b!!)3_!<23]!!MKc!9iYE!!DHK!!*#^!<<,skQBTonaXuq!<<,r +n-&4Fj"TiukQ&p#kQ&ockQ(Y`rTF=`!9iYG!!VQd!9aC_roa@_!;PdW!"\8n!9aC_ +ki`!Hki`!HkihpEqrmnW#j;6gki`!HkihsF"mG.M!9iYG!!MKc!9iYF!!VTM!!)6H +qu?i_kPtV^kQ(Y`r9+.]!<)*`!!)6HrW!2e!!)3_!9iYE!<23\!9!&Cgb>t9p@&4R +@'D?OrTF7,r9+AR4c.q#9pg +p@e1FrTF7,o]Q;#K'8fi"75OKo_eC]q#9pgp@e1FrTF7,r9+AR4o]Q;#K'8!R!71T, +#=LZu)C7=L9`4)Tcd7:-K'9i1!R]6ckQ0#VK'8'T!R]6kkQaL<+rVad?VL@\!RB&D +k^r$3kQ0)Vo&p,"d":J>kQ0)Vqre8Q4H6p)Y3,r]1)K'7gMK'7gMUZ_qN4H6p)\4 +,rT+(K'7gMK'7gMUZ_qN4^Qrs8;p$s8N'!s8W#tK)^H&l2LaMmcX\sd":JHkQ0)Vp?2`L4\!!*#u +!<<-!rrE*"rr3$"!<;utK)^H&kl1XLn)sbsrTF=DhV7,FkLKRc"5DVfjS\4pQi-(- +VZ?bqkQ&s'kQaL<+rVad?VLC]!13Za&(I\m^nl51guG2R?YG(pl%8qes3:QDQga,< +cMcr/hVaDea=m]]J)fPdkQ$s(rrAD`kQ%OBD?92*rTF7,pZMiM4K)a*q!130kaR9*,kQ&p&kQaL<+rVad?VLC]!1/<;K)`C] +!130UKrrrDrr!!*#u!W`6#r;Q`s[Jp5nr9+6\DZBb9kR[^nqN!6aDO6T53%9UX +s8W&]"3AROs8D-]cM-N-6p)\4,r]1)r9+-Iqu7$%i8iGWa0)bZf_C'uK)a!n!130< +!7(Q,!o,L&n+6V\!;?'a!;c$s+:9orrADSkQ&p, +kQBToo^qSC!<<,qo)o$no)JdioDARhoCMk[qXXj\mH-+hr9+-Irr2ruqu6Wrrr3$" +rrE#t!!*#u!W`6#qu6Wrrr3*$rrE'!rr2ru[Jp5nr9+6\DZBb9kQLpF-S)_'rr^4p +JcG]4"3AROs8D-]cM-N-6p)\4,r]1)r9+-IqYpu_oC)=l\&-G3ZHhq;r;Qct!<3!! +!!)Zk!<<+Os+::7rrADSkQ&p,kQBTooCM>>!<<,sne2!'nc/[\nc/[\nc/[\!!)T\ +!!)ld"S(j?0^S`$!13Za!!)rs!!*#u!W`6#rVlitrr3'#s8N)srr<&urr`?%!<3&u +rr<&,rrAD`kQ@`#s8W)^"l_(c9eF:s6ic7 +Zhsb'K0]D!"3AROs8D-]cM-N-6p)\4,r]1)r9+-IrVmD_dE^8rrADSkQ&p,kQBTonaZ,Y5\G%LHb\#"3AROs8D-]cM-N-6p)\4 +,r]1)r9+-IrVmDTZa.!i_K3rTF@)aR9*,kQ&p&kQaL<,8qje?VLC]!13Za&)=Cp['5AA^:^:pI$U\@ +kPY>\!!*#u!rr?$s82iurr<&ts8Duus82kKs+::?rrADSkQ&p,kQ0Hma6EfjiS6-S +r9+-Irr;osmf*7err;osW;cjar9+6\DZBb9kQ9KgLAUuTnl@3>V^TaekQAoImf37L +!7(?&#=L[!)C7=L9`4)SQi6ppe?$9tV0:\Mj.pj*BS3JPK)^H&c2Rd1n)sbsrTFF@ +5fDO8h9=^Zh:pPm5k"X7!13]b!!*#u!!)Bc!!&hp!13WI"/g&:s8M3as+)].qu6ik +=",kGs8D-`aN3fLrTF7,pZMiM4 +K)a*q!130rTF@)aR9*,kQ&p&kQaL< +,8qje?VLC]!13Za%t:M;m^%,eoA,I;:L.7+Y(H\*s3:QDQga,%Qi-%LVf)P7roj=\#Ln2d.k3`* +d/F"CkQAoImf37L!7(?&#=L[!)C7=L9`4)SQ\,6hs1/.0Qga,Qga,kaR9*,kQ&p&kQaL<,8qje?VLC]!13T_ +$MiW5bOEWV[E@q:K)^H&b5VI.n)sbs\**gYo)A[iQN$rOr9+3[DZAn@!Ug!dkQ&p& +kQaL<,8qje?VLC]!13T_$N8oDeaLP]Zan``K)^H&b5VI.n)sbs\**gYo)A[iQN$rO +r9+0ZDW]"@mf37L!7(?&#=L[!)C7=L9`4)SQhp^hi8r__`2p8N_T2>srrE*"K)^H& +rVlkan)sbsrTF=DhV7,FkLKRc"5DVfjS\3AQ\PM?Qi-%IVr[7Gs8D-]cM-N-6p)\4 +,r]1)r9+-IqYpu_oC)=l\&-G3ZHhq;qu?Qoli6k_q>UHq!.t6&s8DrtQga,I9R!!)rs#QOl)rr<'!!!)ut#QOl)rr<'!!!)rs%fcV0 +rr<'!!!*$!!<<'!!.t6)rrADSkQ&p,kQ0Hmde*V@!;Q3io^Cutm/6&IQ\PM?QeCR& +cM-N-6p)\4,r]1)r9+-IrVmD`Yd1X?Lto_WV1X/]Vn)!fs82its8W#trr;os!WW2t +!!3-"qu?cts8;p$s8N'!s8VusK)^Q)!13017dh;%%dG$ep8Y3CQmoDJXkoCDq^q""XZmH-+hr9+-ILAq7?g#rF]pZMiM4Etnc/[\nc/[\!!)fb"S(j?0^S`$!1/H?!12C&!7(?&#=L[!)C7=L9`4)S +Qi6ppT6k[DU2R3"Z&\_]!s&B$!<3!"!<3&urrE*"qu6]trrE&u!W`6#rr3$"rr@ZN +MuNdDn)sbsr9+7LnFQ;7p#l,Lo`Op]p$;P>!1/H?!12C&!7(?&#=L[!)C7=L9`4)S +Qg4S]/N#C5Kp%U*A7oGjj5[D)qu6`us8N)urrN3#!<2uu!<)rr!!3*"rr3!!s82it +rr@ZNMuNdDn)sbs\**gYLAq7?g#rF]pZMiM4W]hZ&\_]!s&B$!<3!"!<3&urr<&urr<&urrN3#!<3!"!<3&srr<%Ns,6mWQga,< +cFW]hZ&\b^rW!!!!<3!&!<<'! +!<3&ts8;ourrE&u!W`9#rW)rt!<<+Os,I$YQga,oDd2$K)_,9!130W]hZ&\h`!pJhJqWInZroa=^roa=^roa=^roaC`kQ(VG!W_Ear9++\q<3G1 +Q2^iNK'7gMo&pW]hZ&\h`!pJhJqre1` +kQ'i1!<20^!<20^!<20`!9aF^kQ1bJ!<20`!9aFYk^ri"rrAC;k^r$hkQaL<,8qje +?VLC]!13!N%kTXr-\[_HC27Tt_W0[]NrK%ZkihpE!U'O_kQV%NkPtVH!<)-[!!29` +roaC`kii!Groa@_!;ku3s-K)^H&ec,W9 +K'7gMo&pMMd4As+::(rrAC;k^r$hkQaL<,8qje +?VLC]!13!N%kTXr.:.^^F)(aTpo('eUk8Vus5W]hZ&\b^!!)ut!W`6#rr3<*rrE*!!<<'!rrE&u!W`6#rr3-%rrE*! +!<2uu!;c]t!!*$!rr3$"rrE&u!W`6#rr2rurVlitqYpQr!.t6\rrADSkQ&p,kQB]" +N_@GI"$h@rir&!?Q\PM?Qi-%IVr_dsmf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C5 +Kp%U6CMRS"j5[D)r;Q`srVlp!rrE&u$3:)+s8N*!rrE'!rr3$"rrE&u!W`6#rr3'# +s8N)urr<&trrN3#!<3!"!<3&urrN3#!<2uu!<)ot!<2uu!<)ot!.t6\rrADSkQ&p, +kQBV#Fj.r,"5J$ZjS\3AQ\PM?Qi-%JVf(\t!m'g0rTF7,pZMiM4W]hZ&\b^!!)ut!W`9#r;[0(!<<'!s8N*!s8;ourrE&u!W`6# +rVlp!s8W&u!WW3!!<3#t!<3#s!!3*"rVuis!WW3!!!3-"rW%QM\,QGpn)sbsrTF=< +9?YBT!r^87qre$HLAq7?r9+0ZDWq*&aN3fLrTF7,pZMiM4W]hZ&XG9K)ad/!130kaR9*,kQ&p&kQaL<,8qje?VLC]!13!N%kTXr-\[_HC27Tt +_W0[]MLtk[s5^KnkQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4SR[8'Lk2tR('k^rhmrrADSkQ&p, +kQ9Nnp$_MR!!)`brW)fe!<<,toDnplqXap^mcQ:jr9+-Irr2ruqu6Wrrr3$"rrDus +r;Zlu!;lcr!<3!$!<3'!s8;rqrr<&qrr<&urr<&urr<&ts8;ourrE&u!MMV$, +g?=.gMuNdDn)sbsrTF@=0_=o&nc8^jqskC#!:g*io'ub\o'ub\nc/[\nc/[dnc\LL +jY6'!kQ$tJrr<&srr<&urrN3#!<)ot!<3!#!<<'!r;Q`srr3*$rrE'!rr30&s8N*! +rrDrr"T\Q&s8N)urr<&urr<&urrN3#!<3!"!<3&urrN3#!9*qXQi-%LVf)P7roaOF +/;$YJ[eg"*W%$3okQAoImf37L!7(?&#=L[!)C7=L9`4)SQg4S]/N#C7?A4)SCB+>/ +W2?Gfrr:^9K)^c/!130F:s6ic7Zhsb'K0]D! +"3AROs8D-]cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0d"s7a@ij0=XDrrM?Ir;c*G +!W_EaqriY3MuNdDn)sbsrTF@=0_+]$n,WLhqX=Lc!<2Hu!!)Kg!:]IX!:TsgnF-DX +qX=XVlJjSbr9+-ILAq7?r9+6\DZBb9kQ*Gnrr3)h;(JpLrrJrHrTF@)aR9*,kQ&p& +kQaL<,8qje?VLC]!13!N%kTXr-\[_HE,5LJ_;jR\NrK%[ki`$GkPtVJkQ1bJ!;ku3 +s,6mWQga,jnGE7enF6>UqX=XVlJjSbr9+-I +LAq7?r9+6\DZBb9kQ*AgrVluh;C\mKrrJlErTF@)aR9*,kQ&p&kQaL<,8qje?VLC] +!13!N%kTXr-\[_HE,5LJ_;jR\NrK%[ki`$GkQ1bJkl(P`ki`$GkQV%N!9aFHkl(Pb +ki`$1!;ku3s,6mWQga,'MrrIm=rTF@)aR9*,kQ&p&kQaL<,8qje?VLC]!13!N%kTXr-\[_HE++*; +_;jR\NrK%[ki`$GkPtV\kQ1bJ!<20d!9aC_ki`$GkQCnL!9aF[k^rhmrrADSkQ&p, +kQ0Hma6s/ukM\,^r9+-Ig&D$PgA_3SrrCaP!13WI"/g&:s8M3`LGA8qrs/'o.]i[K +89Xsq"3AROs8D-]cM-N-6p)\4,r]1)r9+-IlMhAH2)Qb8P*0-^B4Sp?j0=XDrrM?I +r;ci\r;[)dkQ'fHki`$GkPtV^kQCnL!9aF[k^rhmrrADSkQ&p,kQ0Hma6EfjiS6-S +r9+-Ir;Z]qmJm+bqYpNqpAb'kl2LebrrCaP!13WI"/g&:s8M3`gF@sTrs&$p.B99o +bPgW,aN3fLrTF7,pZMiM4W]hZ&\h`!pJhJ +r9++\roaUfki`$1!9iVHroa=^roaIbkQ'fHqriY3MuNdDn)sbsrTFF@5fDO8h9=^Z +h:pPm5k"X7!13Za!!)q1s3 +rVm&tO=+!$s8D-`aN3fLrTF7,pZMiM4W]h +Z&\h`!pJhJqrmtYroa=^roa=^rTO4\"R,%LkQ(MDK)^c/!130W]hZ&8P\g?=.gMuNdDn)sbs\**gYrVlitr;Q`srr3$"rrE#t!!*#u!s&B$!;uis +!<3!$!<3'!!<3!&!<<'!s8N)srr<&urr<&urr<&urr<&urr<&urr`?%!<3&PrrAD` +kQ@`#s8VBJ"3AROs8D-]cM-N-6p)\4,r]1)r9+-IlMhAf:/4W-H$O"7B4[3tT8Dq6 +s4Z[gs,6mWQga,kaR9*,kQ&p& +kQaL<,8qje?VLC]!12=;g?=.gMuNdDn)sbs\**gY_#FB7aSu7,r9+3[DZAn@!Ug!d +kQ&p&kQaL<,8qje?VLC]!13Q^#6+Defso,qK)^H&a8Z.+n)sbs\**gY_#FB7aSu7, +r9+0ZDW]"@mf37L!7(?&#=L[!)C7=L9`4)SQi$dhrpAIln&MTRnc".?K)`sm!130< +!7(Q,!p&4mjP&eIrn7J/gtq,ikQ$s(rrAD`kQ%OAmK!:ckQ&p&kQaL<,8qje?VLC] +!13T_$MiW5bOEWV[E@q:K)^H&b5VI.n)sbsrTF@?i/UIO0EXRij5U"#!1/H?!13WI +irAu@!7(?&#=L[!)C7=L9`4)SQi$dirSZben&MT;\_-\/s+:9nrrADSkQ&p,kQBV# +Fj.r,"5J$ZjS\3AQ\PM?QeCR&cM-N-6p)\4,r]1)r9+-IqYpo\jkK:CXKo1La7Y&a +K)a$o!130T]="uOYPeD9!!*'!!!*$!!<<'!!<3$!s8N'!rr<&t +rr`<%rr<&srriB&s8N'!K)^H&rVlkan)sbsrTF:;0[fUp!!)fe"SD0H0^S`$!1/H? +!12C&!7(?&#=L[!)C7=L9`4)SQi6pp^q7(lqYK]l[^3NS['R*Lr;ZZp!WW2s!!iN( +!<<'!!<;ut#64]'!<3$!r;Qp#!<<'!!.t6&s8DrtQga,3po^i+`q"+Re!;Q0hoBtcqm/6&IQ\PM?QeCR&cM-N-6p)Y3 +,r]1)r9+-IrVmDTZa.!i_b.6)qZK)aC$!130MMQlaK)aO(!130W]hZ&XG9K)ad/!130MMQlaK)aO( +!130/W2?GfK)^H& +i;WeDmcX\sd":JHkQ0)Vp?2`L4"Z&\b^r;cis"T\Q&s8N)urrE*" +qu6]trrE&u!W`6#rr3$"rr@ZNNW0!FK'7gMo&pW]hZ&\b^qu?ct!<3!& +!<<'!!<3&ts8;ourrE&u!W`9#rW)rt!<<+Os,[0[Q\+FQkjmpB6p)Y3,rT+(r9+-I +lMhAH2)Qb8P*0QqCM1NEj0=Vrs+::/rrAC;k^r$hkQaL<+rVac?VLC]!13!N%kTXr +-\[_HC27Tt_W0[]Ne7:_s5i/UH^0S2"%0EHZQr;R$b!!';( +o/m"!r;Qf,8:p&WkkXEI6p)\4,rT+(r9+7hr +bl.PBa#J\7K'<$o#=L[!)C7:K9`4)Uge5hBrdt-lrW--!r;Qg\!'L8\"3^`Fbl.PB +h]RO7K'<$o#=L[!)C7=L9`4)TgG&X)K):/sbkhESQi-jb49.MCrr^IF!6kEA!P^mO +k^r$okQaL<,8qje?VLC]!o,L+K)(#ob4u'nGl7RC49-],rr[rT-0G1+!O#=Ok^r$o +kQaL<,8qje?VLC]!SfA\pO`.]pAr;or;R$b!!#m?UEon;r;Qe*T7Z9YkkXEI6p)\4 +,r]1)r9+1:0S8ulo`5$me+E_A!;6$a!8@)H!!'b+!rj\#rVls^!+R>S!!+D!rVlrn +)"3(?K'<$o#=L[!)C7=L9`4)TgbA!cquH-W!<<,To`5$mrq-9l!8$lE!!)W`!<<,[ +o`5$mp@SFd!8-rF!!)W`!<<-!o`5$me+EeB^Hhbt#F'qWk&`_-k5>5\BUAaNk^r$o +kQaL<,8qje?VLC]!o,L&lgt2X!9s+V!!(gH!<<,JoDnple+uo)Jd^o)Jd^oDJXlo)Jd^oDJXioCMk[ +r::F!!:p3^!!)W^!!)Tj!;#g\!;uHf!!`#p!:p3^oDJXioCMk[!;$0iqt'ad!V>p] +!!Vuc!!)W^r;cigr;Zihr;Zul!!)W^r;ZlioDAUWo)Sgko^`4cs7[r!o`#'_0\?@) +K'7gMq>!<<,to)/Omnc/[\nc/[fncSpmnc/[hnc]!n +o'ub\rUTme%IsK!o'ub\nc/[\nc/[enc8^jrpg^&!:g*io'ub\o'ub\nc/[\nc/[g +ndb^#o'ub\nc/[\nc/[\!!)ug$NL1t!!)T\!!)Qi!<)I!!!)Qi!:o[\!:g*io'ub\ +rUTme&Fof$o'ub\nc/[\!!)T\!!)ug!rr>lo)/P#nc/[\nc/[\!!)T\!!)T\!!)ug +!<<,une(p&o'ub\nc/[\!!)T\!!)Qi!<)Hh!!*#h%fcV#!!)T\!!)Qi!:o[\!:KCY +!!)``rr3&G.$sZ-!k0Serr7T6K'<$o#=L[!)C7=L9`4)VgbA?km.(/W!;uBg!!*#h +qZ$Zfo)&Ihnc/[ho(rFcnc8^jrpgKu!:o[\!:g*io'ub\o)/Oinc/[hndPR!nc/[\ +nc/[\nc/[\qZ-TcqZ$Zfo)/Ojo'ub\rUL6p!:g*io'ub\o)/P#o'ub\nc/[\nc/[\ +!!)T\!!)ug!<<-!nd,9ro'ub\nc/[\qZ-Tc"TSPnnc/[hndkd$o'ub\nc/[\nc/[\ +nc/[go)/Oho()YX"7cElo(rCgnc/[gnc8^jrpgR"!:g*io'ub\nc/[\nc/[go)/Og +o)/Ranc/[ao)8Rjmq=]4qYpZ\?qBJZs+9HdkkXEI6p)\4,r]1)r9+7<0_4f$nGrUi +r:'df!<2Kh!!)re#QOkpnGiRZ!!*#g!<<,qnGrUirp^Bs!:fRZ!:^$hnaQSZqsa[e +!<2L!!!)Nh!:fRZ!:fRZ!:^$hq=+Ic!;lUZFIs=4tJ%tgZK'7gMqUrU9sj!:]IX!<)Ec!"8;c!!)NX!!)NX +!!)uer;cidqu?lh!!)NXqu?cenGN=fnF6DW"RlBknF6AV#Oq3_!:]IX!:oU[!!)3O +"RkX90^ODTK';dh#=L[!)C7=L9`4)VgbA6eK("<[_!_Eol/FD`K'7gMo&p+K&2+9_qkRQgXj#%mt0bTkjmpB6p)Y3,r]1) +r9+7?IVGj7d"9W[cih\&AqT],k^r$hkQaL<+rVad?VLC]"6A[.97ejL0Y]:D5_S_# +K'7gMo&pPkjmpB6p)Y3,r]1) +K'7gMK'7gMUZ_qN4H6p)Y3,r]1)K'7gMK'7gMUZ`"P4&D6,8qje?VJtmrl,&X_SO(a_"kb=^APZr]RmeJ]RmfI]`#GB +^&GeT`QU_4,8qje?VKM:rn@G+rn-hopX];m!S,`re:Q/$dt6&#e)AaUdeqPreC)do +rm_D.gI+.K)C7=L9^D!CkQ'fFkk"!5k547ljFZHEjFZIGjS\'8iW.s9iX"R44K'%[IK'%[Ii8t%$qr[k=#=LZu)C7=L +9_@ZFl4*"Bkih9qkih9qkih9qqrmn>K'%[IK'%[IiT:.%roO`tZf^DVZfU::4kl^/5l08*/pZDS>k5OOqk(;`Ik(;aOjq"f)s5gSns5cX2+rVad?VL@] +rp'CFp#u57!TiGAk(;]HjauTGjj`B*jT#8AjT#8@6p)Y3,r]1)kND'mp?2A9nDs]3 +jS.\die$0Aie$1MiWeH&j5T(Yj8%[>6p)Y3,r]1)o&BQ*p##l.hu2Jbhh'a;hh'b< +h\G#)Za8NFZa8NFZa8KD6p)Y3,r]1)o\B,okh:XAK%Yb/K%],9'=5%FfsA$bfsA$b +fL.hG)C7=L9^^O(f(%:Be:Q2%e:Q3-e.hr_eC=NueC4HtdmQ;B)C7=L9\eFsh;d;f +gOe.2g4J%1g=P$dg"=qF4 +grestore +currentdict /inputf undef +currentdict /pstr undef diff --git a/docs/figs/acm_overview.eps b/docs/figs/acm_overview.eps new file mode 100644 index 0000000000..e52bcf3419 --- /dev/null +++ b/docs/figs/acm_overview.eps @@ -0,0 +1,1463 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%BoundingBox: 0 0 1106 631 +% +% created by bmeps 1.2.6a (SCCS=1.78) +% +/pstr + 1106 string +def +/inputf + currentfile + /ASCII85Decode filter + /RunLengthDecode filter +def +gsave +0 631 translate +1106 631 scale +1106 631 8 [1106 0 0 -631 0 0] +{ inputf pstr readstring pop } +image +K)^H&K)^H&K)^H&VuHbSm(WPPK)^H&K)^H&K)^H&K)^H&_Z']3LFD?d!FYAJs-s#g +mt/JcM5>!.TV#K)^H&K)_5<"F'nH#`%UC")%Z7^OlKW +rr[`N!2kF`T>(F-!.TV#K)^H&K)_8="NLKB.+dV]"7H3iO+RD'rr[`N!8iD.TDnrm +!.TV#K)^H&K)_;>"SX;E#g_T3![%JFK)_GB"+L:Nhh(m#rrN0#ItI]Ps+:9&s-iri +NrT08j8T3X!#YH^s.B;nIfKK+K)_JC!WW4MK)^H&K)^H&RfrrN0#B]8sk5lL``3/'U!BSY35rr[`N!8iD. +TDnrm!.TV#K)^H&K)_>?"6TXaTAfeNmmr$1rVut,n"]mbIfKK+K)_JC!WW4MK)^H& +K)^H&S,WTJ!!'LcrrK +&-*jIVuHjK!!(o.s.B;m!!%Mbrrqk`Im?71JcM_L"UI@YBRe@Ks+16Z!!#:*rr_-Y +!5F-cgA_8I!!$u9rr[`N!8iD.TDnrm!.Vod!N/bG!1X#j+E6MdrrN0#ItI^4rrPFc +5fis-hZ*YkK)aO("#p8lpSe)oIfKK+K)_JC!WW4M`W#tJ0`:tR#XCY"Jq'\J!a%]1 +r;Zm)E:;$N!WW4MK)`I_!^H`NaSuA"!!'ccs4RDSQN.$+W;csL!!(oprrg)j@q1b, +rrR9gA,H9+g&B4PrrRm:Z1@nr^P/rgrrN0#=SK'#ldGe6ha%/@!si#,pO`F=rrUf% +./j2I&:PhZ3= +bWPe'!0mE]!6hqP!3uM'"jI#HYrj?2!!4H/UZh^Yk1T_5!0mH_!87#E"Qh!1!5JC1 +!WW3npQbg@e,KWm(]XOIL\HE#S,WN85lL`aB_TjQ!WW4MK)`I_!^H`NaSuA"!!'cc +s4RDSpAb2cW;csL!!(pKrr@cN,m"&HUYYqNfd6Lq!+Z$."MZ5_-/#j/!'L5\!nmV, +pAb4kk3N$LKd?^]rr2tPrVurBo`"p8rVuqPqYpTs!)*'P!9M`1"fDV+!-%CYs-N`h +^EQ!!&Xirr[`N!8mMM!O3sH!!#mP +rr>pp!!=Mn4PB`6!'L5\!+WV?!5JL5"&]*ubk;#;--Y`U!%%UE"/GnrL&M&Pbk1o8 +Pl:X_L&1fN!!#[dQ2p$srrfM*!!o3Ks-3Neml1:I3;:i#!WW4MK)`I_!^H`NaSuA" +!!'ccs4I>Q!!&Xirr[`N!8mPN!2K8g!'K-pq!!%,Prr?R.!!C"9 +s31HB"Asl,;'l/@!'KWJ!%%UE"2Fm9L&M&Pbk1o8L&M&PU\aul!!#[dQ2p$trrgXR +!"cnss-!BbpK.Cq=OI-M!!%M#s1A:45QF'jrr_-Y!5HSS!d$Q0p\t<"4JVfR!d$Q" +qu6bn,s9lYrr[?h4QaEY!WW4mW;csL!!(pOrrAhl!!4H/-2mlE4Pp) +!WW3npQbg@fDc!:+92DNK)^r4"SY.]!/K#&!WW4MK)`I_!^H`NaSuA"!!'dTrrBh5 +!!%`KrrAhn!!(^Nrr[rT!%%OB"!mpI;>gFr,ldq!^]+?8!2$4i"+L:Nhtd9P^\n-< +-*dLMo-FA:;;V@!!#[dQ2p$urr[3?!0;a3NrK7N+92]1e,KIL!.TV#]Dhpt!'nX*"5a(Y +^W?ETg&1mNU\k&kZ2O_'-2dcC-2mlEU](2mbl.SB-2dcF,ldq!^]+?8!2$4i"+L:N +htm?Ro-OA9!@>tgrr]#B4PB6(!p533rVlo\g%bRL49,@-XoAJL!!">DrrC:B!!%`N +rrC:B!!#.Drr@cP!!(7rrN0#9D=_Pjk0S8cN!rAK)^f0"4$rI +:t,FG!!%M#s1A:45QEA1YlO+!2KMn!+Z!-!6kEB!/:@N!5JL5!'L8\ +"6M]lA,Q?/juaqerVlqQ4Al(W!/:CP!6k??!M_dU,m@..!!">-qYpTs!)*'P!9Ml5 +"&Jstc[u1TrrZ't!700p!WW4MK)`I_!^H`4pm(pAdf0F,!!'dRrrAhn!!#.[rr>1\ +!!&8]rrA;^!!#.[rr>1[!!&8^rrXPI!/82f!WW4mW;csL!!(pRrrBh4!!&ecrrI3f +qu?a[bl7VBbl.SC4AktU"GQmUUF#U6!87AO"!mpI4T#-ZKdHWs!@-rVllArVuqPrVlo\4T5<\ +PlC[_FT)7?bl.PAL&M&Sbl@^rrVuq?rr2tPrVurBr;QaZpAb1>q>UKr!)*'P!9Mo6 +"4mMQBS-8Arr_-a!*IbN!WW4MK)`I_!^H`4pm(pAdf0F,!!'dQrr?R.!!>@`s)e5? +!+Yp+!+Ys-!%%UD!%%RD!/:CO"!mpIKtmWh!!&Xirr[`N!8m\R!)`^q!+YX#!'L&W +"=<[>s310:"""!I4S8[Sg&D!R,ldokrVloB-27HB-/&;\rVurBrVljprW!#Ds310: +!'L8\!+Ya'!/:7K!2KMn!+Ys,!6kEB"_5d#P[c$=!!">Drr>1\!!(7Arr>pq!!CIF +s31HB!'L8\!/:CP!6kEA!'KrT!%%I@!WW3npQbg@g&D/(!!(>ss,$aX:]Ldqec,[N +!.TV#]Dhpt!%.K,!9MZ/"5a(Y^Vp-P4T5<]A$Q"5!'L,X!'L/Z"53_S^\e'34T59^ +,ldq!^]+?8!2$4i"+L:Nhu*KSg&:sP-0Fk"!+Yp,!%%RD"(VB2bk_;?;*=gX!mL[u +q>gL@!Bc)7rrXPI!'L8\!SJdt!!4H/4T,6]L&WIu!!(^Nrr>1\!!:CEbkhA@,s;/, +"$HV`Z2FY),s4:9rVupEq>URD!!">-r;Qc@o`+usrVljDrVurOrVlj[rW!&Es8U=B +!!%-?rr@cP!!(7Brr?R.!!FTXKnWD&!!">@rrN0#9D=_Pjk9Y8-ibBAs+p[WT)\kh +ec,[N!.TV#]Dhpt!%.K,!9MZ/"5a(Y^Vp-Qo-OA9"=4$J--Z5c!%%OC"/GnrA,H<, +-2miG,ldq!^]+?8!2$4i"+L:Nhu*KSFT)7?A+]d$^\n-7A(gmHrW!$Hs8U=?!!8qq +bl.SKU]:A/PftER!'L&V"!mpI4T>?\;>pOr4MUmq!0mH_"blt&!!">Crr>1\!!:CE +bkqGIFQWTL!!#.]s#g8\!0mK_!0mH_!%%LA!/:CP!+Yp+!6k-:!@>MZrrXPI!%%RC +!'L5\"3gfFbl.SBL&V)PL&M&Xbl@_*,ldokbl.PAPl:X_-2IQB!!#[dQ2p%#rr^jQ +!-j+qM#RSG#QRuWrrN0#ItI^4rrPFc-MWl,jjO/2hZ*Yk_uBb]-2[`CPktC[bkhAH +A,lQT!!";F!%%UD"!mpIbeO/Z!!&Xirr[`N!8m_S!'L5\!5J1+!+Z!.!)`^p!+Z!. +!l+cZqu?hQs8U=B!!%`NrrXPI!'L)W!6kEB"$HV`^]"354T,3ZL&M&UL&WG!!%%RC +!'L5\!mL\gr;Zhmrr3-J!!#mr^]"39A,lS(4T,6[A,H90o-FA:-1h$6!6k'8!2KPn +"!mpI-2dcC4T5<_bl@]srVuqPrr2tPrW!&Es8S>_!!&ekrrXPI!'L)W!WW3npQbg@ +gA_8a!!(&ks+gUU:]NK*rrN0#ItI^4rrPFc-MWl,jjO/2hZ*Yk_Z'V#r;Zh-q>UbT +!!"<-!!#.]^]"35L&M&Pbl7VE,ldqh^]+?8!2$4i"+L:Nhu*KV,ldokoD\e:rVurO +rVll4rW!"Rs31EA!'L8\!5JL5!/:@N"!mpI4Sf!Wbl.SE4TGFkrVuqnr;Qb=rW!,: +s!7XF-2dcI49,@-k5W[)!!$O-rro/D4PBaVrW!#)KdHWs!'L,X!+Z!.!/::L!6kEB +!)``L!FmGS!!ah's8OAF!%%RC#ArrXPI +!'L)W!WW3npQbg@gA_8I!!)K;rrJ@Ko`#!-L$"Qu!p53$qYpWgKp;E5"5.0]k0O&/ +BE01*rrN0#IuaO0ft[N?!L2:&rr^"u-)8lf!^H`4pm(pAdf0F,!!'dNrr>1[!!$O) +rt.?n!'Gr8!%%YT!!">:,ldq0rr3'H!!(6XrrN0#T;_blIfKK+r;QjF!!">:rrXPI +!%%RC!6kEB!epZur;Zh^rr2tPrVuqPr;QjF!!#.WrrC:B!!YRcs#^8]-2[]B4T5u!%%RC#!;kc-3+"hrVuqPq#:=VrVupEqu?a[U\aunjs:!--2IQ@bl.SBL&CrO +^HDJq##YF#,ldokr;Qj]!!">Err@cP!!%`Prr@cP!!^[Is#^8]4So'[,ldp-q>UKr +!)*'P!9Mr7!e11UeGfYK!!#.Dp\t>j!!"=ErrSrAFRoG3L&<4u!!&ekrrXPI!+Ym* +"$?P`4O=$/IfKK!rrN0#J+EU>g&B1sKfjIRrr@cL!!,3Wm/I/M!!">BrrJ@Zg&D+= +!%.K,!9MZ/"5a(Y^Vg'O;>U=nU\aun,ldpebl.SNUEom?A,eXk!+Z'/bl.SBbeO/Z +!!&Xirr[`N!8m_S"!mpI-2@KCg!'Krbl.SB4T,3Zbl.SDL&[D:!!+D.rr2tPrVuqP +r;QjF!!#.WrrC:B!!YRcs!7XF-2[]K,ldoks8OAF!%%RC#!;kc-3+"hrVuqPq#:=V +q>^OYU\OihA,ZH.U\Xoibl.SBL&1fU,ldokk5Q_-!%%RC"$?P`-3!oEL&M&PL&V)P +L&M&Vbl@]*!!#.XrrXPI!'L)W!WW3npQbg@gA_4f!$Kek!%%UE!@@@5rrAhm!!(6D +rrgOl!!&eerrKANq#CClr;QbNrVupEqu6Ykr;Zi4d/O37!!)35rrN0#J+WaAUHJAQ +!847L!%%C?!)`.`"$?P`-2dcF49,@DgA_4>!%.K,!9MZ/"5a(Y^Vp-PA,ZH34='t- +-0G.*!2KMn"i('`!!#.\!!p@>@fQKTs8U=B!!(6XrrN0#T;_blIfKK+r;QaCrVuqn +qu7#p@fQL+s8OAF!'L2Z!5JL5!gN_=rVupErVlkOrVuqPr;QjF!!#.WrrC:B!!YRc +s!7XF-2dcC^]"3;-3+!-!!">CrrtRc!%%[Fbl.SBL%tZJ4T,6],uMGOrrBh5!!#.V +rrC:B!!%`Lrr>1\!!UUH49,@-r;Qj]!!">Err@cP!!%`Prr@cP!!^[Is#^8]-2RWD +,ldp-q>UKr!)*'P!9Mr7!al!neGfMjr;Zg[qYpQ1r;Zg[WrE&]rVuq?pAY,fpAb1U +r;QaCr;Zhmr;Qb,r;Zh>d/O3?!!(p-rrN0#J+`gA;>:+kL!K]#ffUR&h>[I$pAb1U +mf*AO!!">DrrC:A!!(^,rrPFc-MWl,jjO/2hZ*Yk`W#pJrW!!Gk-=mc!'L2Z##P@# +-3+!Bqu@0Ps8S;`!%$e-bQ%Vhk.got!!&Xirr[`N!8m_S!-J2?!@>tgrrJl@rW!0L +s8OAF!%$e+rr>pq!!:jRL&M&P4T59[^]"35A,Q?/,ldp-q>UH=rW!-bs8OAF!%%RC +!)`^q"$HV`4T5<\bl.PG49,@-s8U=B!!%`Jrr>pq!!,sZqu6]Zbl.PA;>pOqU\Oih +bl.SBL&CrOUJ_!j"""!I4T5<\bl.PD49,@-rr2tPrVuqPrr2tPrW!&Es8R3?!!$O, +rrgOl!!">@rrN0#9D=_PjkB_9?iWI@rr?R-!!%-=rrM^;rVusFo;hlkA,QB-4SSjU +U\k)n,s3LQ!!#.[rrM7.r;Zh>r;QaCr;Zg[d/O3?!!(p-rrN0#J+imB4SJgUL!K]$ +;#gSBk2-+C,ldp-bfmh!r;Zh>n,EJP!!">DrrhI1!!">!rrPFc-MWl,jjO/2hZ*Yk +`r?%'rW!'Ibl@]brVuq?rVm'J!!#.]s-3E]"(VB2g&:sTPlJr-!%#AZ!WW4mW;csL +!!(pSrrM7.rW!'I@teD=qu?g]s8QU.!!GFHs8QU.!!>@`s+UFP!'L5[!6kEB!'L2Z +"!mpI4Sf!Wbl.SE4TGFkrVuqPrr2t.r;Zp^s8RfP!"5%ks5qNO!!">Fs31HB!/:4J +!2KMn!@=N>rs.4e,liZ!s4RAO!'L#U!6kEB"a%tQF?ClI!!B"rs+UFP#aGAhk0,+O +!%%XE!/:CP!/:FP!/:CP"O-oGjsC!,"_6]ps-+i/!!">@rrN0#9D=_PjkB_9?iWI? +rr?R-!!&emrr>pq!!+CiX8`1)qu?^Cq#:?/r;[*LZ2ajq,ldpBrVll4qu?^ZrVlo\ +-2dfD-.)YoT)\lKf)GdO!.XbC!'L2["!r&C4T5<\L!K\u4T5<\bhi@%,ldp-rVlkm +rVupEn,EJP!!">Crr^#5;;'\'!^H`4pm(pAdf0F,!!'dSrrAhn!!+CirVlj[rW!>$ +s8V4-!!%-@s5kX+!!'e5rs0nN!)`c\!!">Crr^#G,uM__!WW4mW;csL!!(pRrrAhe +!!#mqrrM7.rW)pDr;Zr)s8RfP!!#.ZrrXPI!%%RC"!mpI4Sf!Wbl.SE4TGGrr;Zm] +@jV$Q"$HV`U\t2l-2dfG-0G6OrVuqPp\t4Ur;ZpG4?Oqg!!?a2s'u$.!2K;g!6k'8 +!2KPn!2KJmr[%LC"=<41s+UFP!/:FP!/:CP!6kHB!-J/>r[%IB!%%I@!WW3npQbg@ +gA_4^!'ns3!'L5\"=;:ls)e2>!2Jo\!p533rVlo\fua6po-O86!875K!V7W:!!+Ci +rVltp,s9lZrr@cN!!">DrrAhl!!"=lrr\kn!8lB-!WW4Mq#:>(r;Zh-rr3,`,ldq? +cMmlSrVuqPhu<]0rVup\r;Qb=rVurBnG`SQ!!"=mrrPFc-MWl,jjO/2hZ*YkaSu78 +r;Zhmr;Qc3rW!$Hbl>od!!&8_rr>1\!!">Drs_g*!%%Z!!!"=!Ki'-Br;ZhOaSu;A +!2$4i"+L:Nhtm?QU\Ffi-'\?-!0m6Y!+Z$.!0mH_!/:@N"!mpI-2miHjs:!-4Sf!W +bl.SB4T>?\FS5\7L&V)P-2%od!!%`IrrL=ipAbFEg&L1\!!">=rrC::!!,3s +r;QaCp&G3=s8RfP!!%`Prr@cP!!(7Arr>1S!!(^KrrN0#9D=_PjkB_9?iWI>rrLe! +rW!!Gk-=jb!+Yg(!SMSo498requ7!L!!&eoKdA#F-&(Xa!d$PYjo5U=nbgHFmT)\lKf)GdO!.XhE!0mE^!+Ys,!jPUe +p\t9VbhW4#UP6I)rW!%BKnZ;]rrC:B!!%-=rr@cP!!(74rrY@`!%%.7!mJmAjo5BI +!%.K,!9MZ/"5a(Y^W?ET-2mlEU\aujL&M&R4TEY)!!(7Brr@0?!!%`Orr@cP!!1;t +o`+usaSu;A!2$4i"+L:Nhtd9R^JQ"^RC;5=!f!R)ka!!gaJs5kU-!5JO5"-`cc-2[]CF=$ea +"!mpI-2IQB!!#[dQ2p%#rrQR.5g]N2Z2FY'4=0t,!'L&V!+Yj*!@=N?rrC:B!!,2Z +qZ$VMm/I'\rVurOkPkOerVusFA,ZH.FSl(<^\n-4U\"Kc-2RZB^]+65-2RZB^X<&` +T)\lKf)GdO!.XkF!Tk^-!!$O&rsRLB-):LT;'dLg-):DL4ojuar3qYpU^!%.K,!9MZ/"5a(Y^W?EW +,ldq?q#:V0!!">Ff`2!urVlu^,lg(*rrqO2!!(6Xq#CLC-"F^1rrN0#T;_blIfKK+ +p\t6UrlbB)pAY0UFT+B'FQWK#!b3NRqu6c',pf>brrC:B!!%`IrrJA!qu6l_PYjPQ +^Y/Sd!/:@N$):um4ER@',pcFfrrQ[V;=jemk+dW-4GBQmrVlu^,lf7`rs.[r4?S=O +UWiE2$):um4ER@',pcFerrV>:g&1jOP_HmJrs>HB4Ca)[s--Bqq>UKr!)*'P!9Mr7 +!al!nci4!?q>^OBbk_8=4SJgX^]4>Xp&G(=m/I'>rVurBkPkNErVutQbl.SB4T#-Y +;>pOqA+T^$jsBm)"*FSC^\Rp1L!fo&T)\lKf)GdO!.XkF!+Z!.!'KrS"Ao.!,uOO> +!%%UD!M^t;!!+C@qu6]@4Sf$\-):M?-1q6C1l4RrFObl.SBL&M#OZ2O_' +-2miEYpK8I!@>tgrrY@`!%%UD!/:CP!2KJl!+Yj*"!s`BU](5nFSc";;>pOqg&(dN +5QE/+Q2p$prr_-Y!5HVT!ni:4pAYAO4L+qdZ%^m/rrM9+qYq#04GEh8Yrj!DtuY!!(71rr@cP!!(7,rr@0? +!!YRcs!7XF-2dcCg&:sP-0Fh!!2KAj"$HV`A,ZH.4T5<\;:5CGT)\lKf)GdO!.XnG +!Tk^-!!'e,rr>1T!!CIFs0;:u!@?n,rrJl@p](CBs8R37!!#.\rr>1U!!$O"rrC:B +!!J#Us5o%6!!%`PrrB>!!!#.[rrY@`!%%UD!/:CP!/:CO!-Iu9![[l]r;Zi4r;Qc3 +rVusFk55/[5QE/+Q2p$prr_-Y!5F-cf`)!Q!2$4i"+L:NhoG`tbi\-h!)`^q!82u( +q>UKr!)*'P!9Mr7!al!nc2Rbir;Zh-q>UW\,ldok^]+65A,ZH1;?-[?qZ$\ms31HB +!2K)a"L2H!4=0t,rB((bmJd4?-2mlH^]4<[rVurBrVlk>rVuq.o)A]"rW!15,ldok +s8ODE!!KPQ!!"=mrr\kn!8lB-!WW4Mqu6Y?]jsBs+!@9l,!!%`PrrY@`!%%UD!/:CP!6kHB!5JI4 +$&-U<@fQKTs8P4\!!#.Zrr>pq!!$O*rrPFc-MWl,jjO/2hZ*YkK)aL'!WW4mW;csL +!!(oYrrAhn!!"pq!!H1!bfi3K!!%`Orr>1\!!'e)rr=AE +!!0>NrVuuC^]"3:-3#7k!%$%m".oPnhq%f/!!%NGrr=AE!!'e+rr>1[!!?a&s+UFP +!mL[urVuq.rr3"o-2mlEU]18n;>pOu--ZDhbl.SBA,H9+L&M&PL&:lU,ldokbl@_* +A,ZH.-1_'9L%bQJ4PB`6!+Z!."=:h_s.fPn!%%XE"$?P`-2miDFT)7?bl7VB;>pOq +L&M#TZ%_??s1eL4!/:FP!5JI4!875K!^H`4pm(pAdf0F,!!'ccs4I>Q!!&Xirr[`N +!8k3a"/@.g4T:$7;>gIpKnB@"rrN0#9D=_PjkB_9?iWI?\^]"35L%50C-2%<>-0F[r!0mE^!@9&h!!#mprrXPI!%%49 +!87>O![[kVrVutQA,ZH0FT4K&!!'d^rr\kn!8lB-!WW4Mr;Qo^,ldokoD\eQrVuq. +rr3G&!!">-s!7XF-1h/$4T,6[-3!oEg&:sP--ZAg!6kEB!/:=M!2KMn!/:@N!2KMn +"GQlj@jV'R!/:"D!/:4K!@;jcrr=AE!!';&rsCjg!%$e-s#^8]-2miD4T5<_bl@^X +rVup\pAY,&rVupErr2sqrVupqq>UL]!%.K,!9MZ/"5a(Y^OlL!6kEB!/:=M!6kEB!/:@N"_.N4-o!!+Bfnc&TC +rW)p[!E#*YrrC:B!!">Crr@cP!!^[Is#^8]-2miD4T5<_bl@]QrVur5pAY0U-2mlG +L&\pd!!'e0rrPFc-MWl,jjO/2hZ*YkK)aL'!WW4mW;csL!!(oarr>1V!!#lJs7ZHo +!!#[dQ2p%#rrQR.5gfT3U\t/o4TA:X!!+D;r;QaCqZ$[D;8<#.!0mH_!@?n-rr@cP +!!%`?rr@cP!!(7/rr>1W!!+Alr;ZiNrr3'H!!">?rrLfsrVlj[rW!%Ss5kX)!!>@` +s1eO5!'J^0".oPnhq%f/!!%NHrrC:B!!#.QrrY@`!%%F?!6k31\!!(7A +rrC:B!!%`MrrC:B!!%-=rr>1W!!4HVk4&BNFT)7?g%YLHU](5nA,Q?,L&M&Vbl@]* +!!">Drr>1\!!^[Is!7XF-1q3;L&M&R-0A_:!!#mkrrPFc-MWl,jjO/2hZ*YkK)aL' +!WW4mW;csL!!(o`rrJ?Hr?VM-A&!Wqp&>'n!)*'P!9Mr7!al!ndf0<^r;ZsHbl?fO +rVupqr;QaCr;ZmFA*3Ue!/:CP!%%UD!/:CP!/9h?!/:CP!6jg0!Tk^-!!dV"^Wapa +s&&aq!0mK_!%%UE!2KGk"S6+'!)`aq!%%UE"3gfF-2RZBPlC[b,ldokdf0EA!!(p- +rrN0#J,K!Bd.Rrr>1\!!(7ArrC:B!!%`M +rrC:B!!#.Zrr>1Y!!4HVk3i6O49,@-pAY,HrVuqPr;QbNrW!/Hs8P1]!%%UD!'L5\ +#0d,I,ldp-oD\e:rVusr-2mlE^\Ig15QE/+Q2p$prr_-Y!5F-cf`)!Q!2$4i"+L:N +hh(m#rrN0#9D=_PjkB_9?iWI@rrL=irVusFbl7VBZ2FY&L&M#O-2mlEL&1fPg"HE* +L&M&P4T59[^]"35A*s9uPQ1\0li-rprVupEqYpPjrVupqrr2t?rVusFbl.PBUF#m> +"""!I^]"35-3!oEFSl+>-0G4,!'L5\!2J$C".oPnhq%f/!!%NGrr=AE!!'e2rsFu: +!!$O/s#^8]-2@K?bl%MC,uMGPrr>pq!!(7@rrXPI!/:=M!6kEB!'L2Z!'L2[!@Q!!&Xirr[`N!8iD.TDnrm!)*'P!9Mr7!al!neGfQn +-2dfD^\n*3A,QB-Z2Xb'A,ZH/4MUjp#/<8#!5JPfrVup\rVllArVup\m/I-@4L+5P +!%%UE!/:7K#UKHN-0G7-jsC!,"=7Q3@jV$Q"$HV`L&M&P4T>?\bkqG@4T59[A,ZH. +A(1G[T)\lKf)GdO!.XnG!)`^q!@>M[rrKl3r;[$as8P1]!%%F?"m.*2!%$=qrrq)0 +Z2aiXrVuq?r;QjF!!#.YrrC:B!!#.Zrr?R.!!%-;rrJmKo)AeS!!">=rrqO2!!">: +rr3,F,ldokrr3'_!!">Drr>1\!!gaJs#^8]-0G+)!R0^'rr>1Y!!'e.rrPFc-MWl, +jjO/2hZ*YkK)aL'!WW4mW;csL!!(o.s.B;m!!#[dQ2p%5rrDf_rrQR.5h5l8fd6Rs +!2KDj!'L5\"XVCms5kX+!!=N04=0q+!i,dLrVup\r;QjF!!"=prrA;_!!">?rr?R. +!!&8_rrAhe!!#mqrr>pq!!#mprr=AD!!&8^rrAhn!!"=orr\kn!8m&@!;Gs^!WW4M +qu6]M-2dfF4?Oqe!!]4us#^8]-27E>;>pP(4JV'=s1`%D!%$e-g&:sT-,9K[k&gS& +!@?n+rrC:B!!#.ZrrBh4!"!/Zs8Uc:49,@koD\nT!!">pq!!GF!bbHK`!!%`P +rrY@`!%%UD!'L5\"3gfFL&M&Q4L+nc"GJ-%-0G.*!2KGl!)`Ii!^H`4pm(pAir9#Q +o)AgL!!'dtrrqQ/UP4EGmJd:N;*<(Mrs7ces3/63KqllarrRm:FP6Zq!!&Xirr[`N +!8iD.TDnrm!)*'P!9NSI!a(NXo)Ac!!'o*7!)`[p!2KAi!5JI4!'L8\!M^t8!!>@` +s-3K_!/:@N"!mpI-.Mqp;>pOqL%tZJ^]"354T59[U\Ffi-'\B.!'L5\!/:CO!+Z!. +!@?n,rrM7.rVurOeGfWC!!(p@rrVpSYOVVo!!%NFrrAhf!!+CNrr3'_!!">>rrBh3 +!<+;C!!">Err>1[!<+;B!!%`NrrC:B!!#.Yrr>po!!+Alqu?_=oD\nT!!">UJj-2ITC-"HQFrrY@`!%%@=!M^t9!!+C@rr3#C-2%<=-2dcCbl.SB;>U:m +;>1%j4S&LS@fQKTo`"oFq#CFAbl.PD49,@-rVljprVurBrr3#C-27H?4So'XFT)7? +4SA^U5QE/+Q2p%+rri'%!+=^Xrr_-Y!5Idu!0m9Z!@>t[rr[rT!'L8\!87>O!5I7f +!'KoS#*f/fPQ1\0rr3'H!!(6srrN0#T;_blIfKK+e,KJH-"HWJ!i%&=`W$$^!!">$ +rrTrhZ24J%fnH^,rrTH&FPQlt!!#[dQ2p%5rs%ot!!!jsp\+Ug?iWIBrr^J--&)$l +"-b)XFSl(Bfp%1Q;2)d^rrQ[V;>^@qYpC]ke,KI2bk1o9UVHX)!9X:)!9X+W"6NH, +L&:lOZ"'$prr^Ik!)_5F".oPnhrt(?\,H@.0X(0L!WW4Mq#:BWA,R\T4ET`_rrZ*u +!'KrS!p3u=qu?dEA(ge[!SL?J!!O[&@fQKkr;QcMrVuqnq>UMk4=0q+![Tsnnc&^E +,pd[)rrJl@qu?apg&1jPF8u;NrVlu7,lg(*rrV=[-2[`D4JV`P!%%UE!2K5e!^H`4 +pm(pAiVrm[rVut,ht[3RhZ*Ykl2LsA!!"<-4=0t,!@?n!rr[rT!'L8\!2KMn!0l4; +!'L5\q^)4A"/GnrA,ZH4g&M'u!!(6srrN0#T;_blIfKK+eGfN5rVurBp\tBY,ldq! +a8Z;),ldoko`"u7-):)3!Tmnj,m+,I-0G.*"MZ5_!2KGk"PG($!-I&s!WW3npQbg@ +li-rer;Zm9O8&GL!al!n`;]l#k(!#YY7!AL_OrrN0#J*Ht8 +k$qoSo)Aj:^P/H,p\tBLP_Fh+rr3&)L$&:4!jPUepAY\,64,@,Lh\"5a(Y^Zkb# +K`D*8rr2tPrVuq.o)AfG!!#.[rrQ%D4PB`;49,A'k5>5\fp&92rr^q:-"HrS"!mpI +bhE'u!!&Xirr[`N!8l<+!/:CP!6k3;!0mH_!0kP(!/:CP!/:+G"JYqs-0Fn#!JMiq +!!&8]rr>pq!!#.Yrr?R.!!">$rrN0#9D=_Pjm2pHYPS;$(m"FfrrQR.5_B#jrr\kn +!8lu>!-%f8!AL_QrrN0#ItI^Frr>1\!!&8UrrPFc-MWl,jl$.=&GlG.@,Ln^"5a(Y +^Zkb#K`D*8rVlta!!">9rr[rT!'J^0"$?P`L$nsC,ldqhgA_3S!2$4i"+L:NhphZ+ +L&M&PbkM,;4T5<\bfB_c,ldokp&>':-2mlE^\7[-A+os'L&M#PjsC!,!@?n+rr=AD +!!'djrrN0#9D=_Pjm2pHfD,CJ(m"FhrrQR.5_B#jrr\kn!8lu>!13K]!AL_SrrN0# +ItI^GrrBh5!!">:rrPFc-MWl,jl$.=3;EOT@,Lt`"5a(Y^Zkb#F8u;'rVluD!!">9 +rr[rT!'KlQ!SP]VrrY@`!/9k@"!mpIbhE'u!!&Xirr[`N!8l<+!/:CP!6k3;!'L5\ +!6iOa!5JL5!+Y^%!'L2[!/:1I!+Ys-"!p&l-2mlEL&M#OU\k)l^]"05jsBs+!/9;0 +!WW3npQbg@li-tZpAb73O8&YR!al!nK)^T*".oPnhrk">\+]k'0X(HT!WW4MK)a-r +!+Z!.!+YX#!^H`4pm(pAi;WdZpAbD*huDR6!5Idu"$?P`FT)4AUAt9?rVm)a@lu&" +A+T[!",-^T4T>?_fd.r>r;Qu+49,@-4JVoU!`:8=qYpUo-&)$l#Wr(eL&_1sbi\d% +"/@.gg&D!R,ldqhr;QeO4T6W-;5<:R!WW4mW;csL!!(p+rr@cP!!(7;rraVJ!%$dK +rr>pq!!(^Grr@0=!!#.Vrr@cO!!GF;s8Tk5!!&8^rr@0=!!%`OrrAhl!!#mQrrN0# +'DEgR3U/j0"SMg"(m"Fk?iWHDs+^OUT)\jNk^M*kPkS`!2$4i"+L:NhphZ+L&M&PbkM,>,ldokmJd3OL#2h4 +js:!-4SJdT^\\!2-2IQ@^\n-44T,3\F1Z!!#.[rr?R,!!#.Z +!!#.\rr[rT!'L8\",-^T4T>?bfd-Uu,s3LQ!!11T!!(^O +rrY@`!/:FP"!mpIbl7VB4T5?[-2mlE^Zb\!!!&Xirr[`N!8lc8!p4Ser$;A+g&D!O +L&M&PbkM,C,ldoks8UbLA,-'6Kfk(hs'l$/;?+Cb4Cb/]rrM8Hr]C6ZPih]>!+Z!. +!2K8f!'L,Y!@?n)rr>1\!!#.Qrr=AC!!">Drr=AC!!">%s3(HE#lm5Bs+^ORT@!W= +ItI^HrrAhn!!&8Srr>=%!!'durr>1V!",M$s5kU-!%!?CA,ZH4U]:@J!!#.\rrZa2 +!'L8\$p4Li--ZDhPU03,s'u$.!2KPn!/:CP!2K5e!'KuU!%%UD"!mpIL&V)V,ldqh +s8RfP!!ebgs03jM!/9Y:!WW4mW;csL!!(p9rrJl@q#CClrr2t?rVurBp\tOG!!">F +s!7XFA,?3*Z2O_)U]2Y>!!">C!!+Ciqu6\N-2RZC-$8q^"Qh!1!'KuT!-J2?!B`LD +!!'e2rr@cP!!+D!o`"pEqZ$UBrr2uOqZ$UBhZ(h#"(5(.5_B#jrrA\A!!Ej_!!%M# +s3CWGF=%!!'durr=AA!!+CNrr2t?rVur5rr39e!!$O/s+LFQ4T>?b49,@D +s8Skn!!'e0rrhp>!!">ErrXPI!'KoR"?ZYa-&)6?r;QjF!!%`Prs^7S!6kKC,ldq! +s5mf;rVurOkl1\a!2$4i"+L:NhrF_:^\7^.4T>?`49,@-k55/cbeJjc,ldoks5kX, +!!';$rr>1\!!8Db-2.B?-0G1+!+Ya'!/:7K!+Z!.!2K;g!SJdu!!0igrVuq?qu6XB +rVuq_oD\fcq>^W4s8R3;!!(7#rrN0#'DEgR3U/j0#5%s"@,Lul!'l/9LAq@J!!#"A +5QE_8!!X!an,E@fItI^4rrPFc$MYqJ3T*.&*q]L95c4S^^Zkb",ldrE,lpl:(jL&M&RL&[D:!!&edrrY@`!/:+G +"!mpI^]+6@,ldqhs3(HC-*^;nrVusFUZ_XY!!&Xirr[`N!8li:!/:CP#<[^)b]Egb +A,cK849,@-s4O0$4=)^\7^0&:a0JrrN0#ItI^4 +rrPFc-MWl,jl$.=@.sX*5em?V!!'durrXPI!6k6<"!mpIL&M#XK`D*8s8RcQ!'L8\ +#s81fL&_0!!!'e-rs1^e!%%5!!!#.QrrY@`!/:+G"!mpIbl7VG,ldqhs.fDj![V@= +k5PJ_!2$4i"+L:NhrF_:;>pOqZ2O\(P[ikTrr>1\!!">;!!FVJs5kX,!!%->rr>1\ +!!@?Cs!@UD#>r7[YpBAM-3!oE4T5<\PlC[_Pl:X_-2RWA;>pOqU\FcgPl:Xf-1h0! +,ldokr;QaZrVuqno)A\9rVuq.rW!!^s4RAO!@>#M!!$NdrrN0#9D=_Pjm2pHhtR0P +@,Ln^!al!nK)^T*".oPnhrk">TD8Hg&:a0HrrN0#ItI^4rrPFc-MWl,jl$.=5ktB\ +5em+?!!(7Brrj\K!6kIsqu?dEFQVZa!WW4mW;csL!!(p: +rrA;_!!4Hgk5##W4R`=N4T>?\L&M&T-0G7-U](5r-0G7--2mlEPl:U^A,ZH0^]2(J +!!Hg3s._^T!!$O+rrBh5!!#mjrrM^;rW!(Cs3/\5rVurBrVlsG!!">9rrCaO!!ah' +,ldoks)e5?!Fsg^!!#.=rrN0#9D=_Pjm2pH\,$(*@,Lh\!al!nK)bWG!i%l3r;Qhn +4GDbo!L/;Nrr\kn!8lu>!-nA@!YBkMqYpTs!.TV#]Dhpt!%.K,!9N/=!#YS5!AM:d +rr_-Y!5Idu"!mpIbkV2?,ldperVm1$!!$O/s+LFQ4T>?e49,A8s8OAF!6k-9!'L/Z +!%%49"$?P`L%YHJ,ldqhrr3-J!!(7CU](5o4I"h)!WW4mW;csL!!(p9rr>1[!!4HV +k55/Y4Sf$b,pcEBUWgq.!!#.[rr=AE!!?a2s#g8\!+Z$."$?P`-2dcCPl:XaL&Z8o +!!9EZ-2[`C4So'X4T5<\^\@a.A,QB.,piEg!0mK_!6kEB!'KiP!0mH_!^-K/rVuuC +-2mlJ^],S[!%$P&!WW3npQbg@li-ruqu?b*ht[3Q?iWI(rrC9ZrrCaO!!&8_rrCaO +!!&8DrrZa2!)^H0".oPnhrk">./a,I&:a0DrrN0#ItI^4rrPFc-MWl,jl-4>a8>o< +0X(?Q"5a(Y^Zkb#,ldqhq#:S/!!"=hs8Skn!!^4?f49,A's8P1]!'KlP +rrTr4A,Q?,^\e'3L%>6G49,A8p&>+?!!'e5rs9tO!6kK*,ldper;QhP,uNn+!WW4m +W;csL!!(p8rr>1Z!!+C"r;QaZrW!$_FHk#GrrXPI!'L5[!2KJm!PcDK!!+D.rr2s\ +rVurOrVllArW!"Rs#g8\!%%OC!Bd.RrrAhn!!#mjrr=A;!!#mqrrC:B!!#.Prr>1\ +!!7lSA,ZH.;>pOt-3+!-rVur5i;WiY!)*'P!9NSI!V[0)!!-KbpAY2%!'n6t"S4_U +-)8BX!6kEB!/:FP!6kEB!/9J5"$?P`-,'<\T)\lKkl1Y'rW!!2J+*+2!WW4MK)`I_ +!^H`4pm(pAiVrmkrVusQYPA,"hZ*Ykl2Li3!!(7?_K`D*8 +rr30b!!#.]s.fPn"!qH24T5<\Pl1O];>pOq-1V!;49,A8p&>+?!!%`PrrsbL!6kKC +A,ZH.-2p"/,ldokkl1\a!2$4i"+L:Nhr+M8UHJGS!'L5["$?P`-2.?@,ldp-r;QaZ +rVusr;>pOqA,ZE-4T5<\bl.PAbl.SDL&X:3!!,3Wq#:IZ!!">-p\t4>q#CFA-2mlE +-3!oEbl.SB4S\pWbh;sp!%%UE!mL\>q>^V-s8R3?!!%-!rrN0#9D=_Pjm$rrQ[mZ0M>hbl.SBL&V)Pbl.SBL#`18,ldok^&J2,!!(p? +rrd9@&:a0@rrN0#ItI^4rrPFc-MWl,jl6:CpD^OBk5G;[4T5<\bl.PAU](5pL&X:6!!4HD^\@a.L&M&PA,$!'U](5p-&%'PbQ@hE +-2mlMg&M*7,ldokk55/`ffT67L&_1frW!'Is8V4-qZ$`Os8Tk5!!#.>rrN0#9D=_P +jmBrr>pn!!$O,rr>1\!!(7Arr>pq!!8qq;>pOr;1\ +!!$O*rr?R.!!&8_rr>1\!!,4RrVlnP-2mlH4TGG'rVup\rr2s\qu?^CrVm!H!!">- +iVrrZ!)*'P!9NSI!9`kO!al!n]`/(D,s9E.rr>1\!!(7/rrC:B!!%`PrrC:B!!%`5 +rrXPI!'Isp".oPnhs(.Ap[@VO!WW4MK)`I_!^H`4pm(pAir9#Ao)AgL!!'ddrr^#i +L"Z>&!SQ/trr^#iKqnJD"Qh!1!/9qB",/$`k3`0Kbk_8=k5NTcrrN0#T;_blIfKK+ +j8T1cKtmTd"S3o>!%%XE"!mpI4SJdW,ldokqu6Z2qu?aDk5>5Z4T5<\U]18nL&M&S +-0G6&rVusFU](2tfjc<.L&_1;rVuq.p\t6.r;Zi4qYpQ1rVup\rr2u'r;ZsHFG3R< +qu?h@s8P4\!!%-?rr@cN!!%->rr=AE!!&eQrrN0#9D=_PjkB_9?iWHWrr>pq!!&8L +rrC:B!!%`PrrC:B!!%`5rrXPI!'Isp".oPnhq%f/!!%M#s1A:45QE/+Q2p$prr_-Y +!5Gf="ChE3-0DB1!WW4mW;csL!!(p;rrCaO!!">E49-],!!#.\rrXPI!'KuT"!mpI +-2RWAA,QB-;>^@n4T,9Z-2dfDA,cK.4T,6^,s4:9r;[(4s8P1]!%$e%rr>pq!!#mk +rr=AE!!(^Orr?R%!!%-?rr=AE!!&8_rrCaM!!(^Nrr?R.!!#mTrrN0#9D=_PjkB_9 +?iWI"rrTrh^]"05g#h]%"6Ri-L&M&SUWgsEmf*:2rVuqPrr2uBrVuqPkPkY.s8UdO +!!#-prr\kn!8lB-!WW4MhZ!bS@lukNPi2QBP_Iom!JU.Arr\L>Ktm9[!5JMe!87&F +!87@*!5I@i!^H`4pm(pAdf0F,!!'d=rrXPI!+W/2!WW4mW;csL!!(p;rrCaG!!BM+ +s31HB!'KuT"!mpI-2RWAbl%MA^\e$24SJgU4T59\bU)u`"!uY#U](5nA+op&-2mlE +^\Ig/L&M&PL&M#OA,$$)4MUjp!%%UE!6kEA!%%UE!'L2Z!2KMn!%$V(!WW3npQbg@ +gA_4^!'n6t"6NHCU]19$^An6[k5Sp;!$sb4qu6\l;>VXEFT;Ap,lf5;rW!'I!!"U]^@jNE$,pd[4!!$NB +rr\kn!8lB-!WW4Mhu<^>!<"2F!%#DCrrI4qrr3!]-/JS&@fXaNrs$[n!$rokA,$!) +ffT96,ln!Up\t7k!<+8F!'K-rrAhn!!'d9rrN0#T;_bl +IfKK+j8T.6-2ITB-):G="!mpIL%bNK;#gSBqYpP*rVupqqYpOXp](:Vqu6`h@jV!P +"XR%.s8RfP!!'e-rr[?C!+Ya&"$?Q0g&1jNUHJJT![Tt(qu6a\!!">Crr@cP!!'e3 +rrhI1!!">(rrN0#9D=_PjkB_9?iWI*rrZ*u!%%XE!/:CP!Fn7h!!'e4rr>1V!!:jR +-2%<>-0G1+!FmGQ!!,sMrr2uBrVuqPrr2uBrVuqPr;Qf&-2ITA;>^@oUF#X7!/8,d +".oPnhq%f/!!%N,rsDU'A*3gkk(Nd]k3;mIbQ*@rrrJ@rrZ*u!%"`H +!WW4mW;csL!!(p9rrM8HrB(*jU\k&mfnG[_rrRn.g%t^K-2mlE^\[s14T5<\;>rZY +A&%g=#Nhe8;*9Q-k5G;^YpBBIo`"sFbk1o9PihfA!87@qq#:H24?TnGrrSEpZ24J& +UEq4.iVrrZ!)*'P!9Mr7!al!n^&J'prW!&Es8RfH!!#mqrr>pj!!:CE;>'ti-3!oF +bWPY#!%%XE!6kEB!/:FP!6kEB!/:CO!2K8g!)`^p!2K2e!/8,d".oPnhq%f/!!%N- +rrV=/-2[]D@fV5IrrUCEL"lV2ffT6\!6kEA!gE\=rVlmE-2IQB^AqdBrrVd<-2IQA +,piKh!^$J9i;WjD!%.K,!9MZ/"5a(Y^U!kA49,A'XT&>%!2$4i"+L:Nhn/mgL&M&P +4Sf!W4T5<\bi\p+k01@8!TrP&rrN0#9D=_PjkB_9?iWI*rrY@`!%%XE!/::M"XRY) +!!">Err=AE!"EFl^SE4T5rrUD,;60]u!!&Xirr[`N!8kEg!%%UE!2KAi!'L5\ +!6g&pp\t9p!)*'P!9Mr7!al!n^&J0s!!">Err@cN!!ssqs+LFQ-0G6\rVup\rVlrP +A!Hlj!/:CP!/:=M!+Ys-"-iicbl.SB;?$Rqbl.SBL&V)Pbl.SBL&V)PA,ZH.A,cK/ +^ErjZ"53_SA,ZH.A,ZE.o0!!P!2I7-".oPnhq%f/!!%N,rrOJm^\7[-U\uJ?!'JL( +rrHU0rZqpPA,fCP!$rqFs#_V,rrUD,!<+8F!-J5?!ehqbrZqUG!2K>h#0^T>s+LHs +rVlmE-2dcEUB$#=rrFDlo)AbR!86<1!^H`4pm(pAdf0F,!!'ccs4I>Q!!&Xirr[`N +!8kHh!5JL5!%%F?!'L5\!6g&pp\t9p!)*'P!9Mr7!al!n^&J0\!!">Err@cN!!C"9 +s+UFP"3gfF-2mlF4L+V[!0mH_!/:@N!Tk^-!!&enrrC:B!!%`PrrC:B!!%`PrrC:B +!!%`Prs'hM!'L;]^JXq0!'L8\"!mpI4T#-YL&M&Pbe=#YT)\lKf)GdO!.Wr,"bcpV +-$6ours5k04PBc7PQ3iFrsWuLA+T`l;#lj\bQ*@rrrG5.rr3Wo!/:IQju`Wts8RcQ +!0mN`PQ3$%rrRlSbl.PB,s;,*!mCXSoD\lG!+YX#!l"^thuQ!!&Xirr[`N!8kHh!%%UE!87/I!'L5\!6g&pp\t9p +!)*'P!9Mr7!al!n^&J0\!!">Err@cO!!(^Orr>1\!!(7BrrJl@qu?a[g%t^Kbl.SB +L&CrN;>pOq^]"04bl.SBL&V)Pbl.SBL&V)Pbl.SEL&_1,rVupEqu?aDL&M#Obl.SB +^\e$2L&M&Pbe=#YT)\lKf)GdO!.Wi)$e^4r,ldp-k5YH-4T,3`bQ(N?bQ)/KrrUCE +L&V)V4=1%-;#ni,h!%#k] +rr^Ik!2JEN!^H`4pm(pAdf0F,!!'dns8L5os8)`s!!&Xirr[`N!8kKi!87>O!'L#U +!'L5\!82u(p\t9p!)*'P!9Mr7!al!n^&J0\!!">Err>pq!!">Drr>1\!!(7ArrV=m +-2dfE-):A;!6kEB!'L2Z!'L5\!6kEA!6kEB!/:FP!6kEB!/:FP!6kEB",6dTL&(cM +-&)6r!6kEB!6k??!/:CP!6i.V".oPnhq%f/!!%N%rs-;$!)`d?!!)mB"TU[bK`Hi& +rrUCEL&V)U4=1%-4=0n)#)*&As+LHsrVlqQ!6k-9!egWurVlmE4T,3\bQ)/Hrr[rT +--Z#]"0j-PUYYqO5QE/+Q2p$prr_-Y!5IUp!FmGT!!4HDg#i;7U](2n,uNLu!Du_k +rrLeMrZqPup&>#%rZqSBg#W/7!!&Xirr[`N!8kHh"(MpLp4T5<\bkqDAk(P,\!!+D.r;Qc@rVup\ +r;QaZrVurBrVm#_,ldq!rr2uBrVuqPrr2uBrW!%Ss8RfN!!,3Wq>UH=rVuq?qu6YM +rVurB^&J2,!!(p-rrN0#J)UD.^P2Oa#4j,es3(HhqLo':s+LH,q>UN?!/:FP"["+2 +s#_V)rs"/WPlHF;bl.PCK`K?irrRlSbl.PB,piKh!l"_hp\t>*!'Js,rr]"r-*c8* +!^H`4pm(pAdf0F,!!'dqrrP:_4T:$:49-\Okl1Zn-2miE,uNP!!b23mr;R#T,pdYe +;#k,#rs(Xd@tf"N-/%D[!WW4mW;csL!!(ogrrLg8p&>'Tb_#lfrrN0#9D=_PjkB_9 +?iWI*rrXPI!%%XE!'L5\!/:CO!-J2?!2KAi!V8GQ!!%`NrrC:B!!#.Zrr@cP!!&8] +rrXPI!)`aq!6kEB!/:FP!6kEB",6dTPl:X`4MUam!6kHB"=4$J--Z;e!+Z!.!2I7- +".oPnhq%f/!!%N-rrP:_^\[s6494's,s:u&!mCXdr;Qqqbl>leL&V)V4=1%-;#ni< +rrus5bl<@sbl.PCK`K?irrRlSbl.PB4=0q*!egWLq#:CX!'KlQ"*=MhbhN.!5QE/+ +Q2p$prr_-Y!5I[r!gE[pr;Qh_!'KKF!B_[^rrhq'!!#.ZrrQ$t^]+67@fX:>rrRlS +L&V)R^Aq-mrrN0#T;_blIfKK+K)_JC!WW3npQbg@gA_4^!'n6t"!mpI-3!oE4T5<\ +L&M#OL&M&UL&_1,PhH$8!-J2?!/:@N!6kEB!'L2Z!5JL5!BfuQrrfSQ!!">ErrC:B +!!%`PrrC:B!!n;Ys5kU-!%!?trs.\?,lggBs'u$."XTrDs5m2W!!%_drr\kn!8lB- +!WW4MiVrtD!'L/Y#NdOrrj\ps3(Isrr30b-3+"0!-J/= +"skSqs+LHsrVlqQ!6k-9!egWurVlq@!2KMm!^%dkq>UM+!+YX#"/>iYo@j3G5QE/+ +Q2p$prr_-Y!5I[r!^$J,qu6^D-0G+)!87,H!TrPBrrG5.p&>$Fp&>$Fp&>3#,lhF$ +4T59]js<.grrUjR;>L4m;'l/?!@9&RrrN0#T;_blIfKK+K)_JC!WW3npQbg@gA_4^ +!'n6t"!mpI-3!oE4T5<\L&M#O^]"374TA:X!!">E4T,6[U\t,lbl.SB4T#-Y-2mlH +-"CF2qu?hos8U=B!!%`PrrC:B!!%`Prr?R-!!FT14=)1T!!&enrrJl@p&G(i^&J2,!!(p-rrN0#J)C8-49,B\,m"&mFT)4E +@fRf;4=(!&rVm'a!$s`R!+Z$."sj6qL&X7]rr35I,lf5R,lhHSrrRlSbl.PCK`K?i +rrRlSbl%JFUEq3K,lg(+rrpUH4TGFYq#CC@rr3*I-3+"0p](<0WP_Fgdnc&WDo?[F!)`Um!6kEB!0m?[!M^t< +!!c@`!!">Fs4RAO!5JO5!87>O!5JI3!JMir!!,3sr;QfA4So*],p`NkKt[KgT)\lK +f)GdO!.Wl*!P`aU49:/uqu6i7F?D[-g&(dPUJX-NU](2sflU)ds-/68rreQK4Cc/) +rrTrhoDS[j^P2:PrrTrhoDAOjfjd-,Pl1Obo7`G/s-3;4rr3+TL&_1fpk8_>i;WjD +!%.K,!9MZ/"5a(Y^ZGJ#F!@9kbrrUCj4T#-YU\lDhObl7VC +^LR4)!JT5%rrR9g;>:(tPYjP*FP6]oF?Hi-rrTHZU\t,nZ%\tKrs$5l@m"jtg%bRR +fnE9cKp:`Q@thSq".oPnhq%f/!!%M#s1A:45QE/+Q2p$prr_-Y!5IUp%H_aY,ldok +;=jhfPQ6sGrrtS3s8Pprbl.PF^P2^f4=0t+"XQ;2s!8uhrs-:=;?-YY-0G1+!@9&a +rrFE.rVlqQ!6kB@!^$J,p\tDl4?Oo9UZMLW!!&Xirr[`N!8l9*"2=g^U]18q^H;L< +kl1^;rrRlSbhN.# +KdA#F4T,3\;#nB1rrV=/;>L4n4=0.grrR9BPkb7^ffT6\!6idh!WW3npQbg@gA_4^ +!%UZP +,pe8!!6idh!WW3npQbg@gA_4n!"ab^LAq=9!!(RL!WW4MK)`I_!^H`4pm(pAdf0F, +!!'dsrrUk"A,?30^Aq.2493V#rrFDlq#:@W-2miI,s;4O!)`Xn"XQ;2s#_V*rrG5. +o`"q<4T59]PQ6F8rrFDlq#:?Ir;QiB!'KED!WW4mW;csL!!(p*rrR9BA+fj&@fZKS +!rs1_L@fRf$!%$=nrrlo- +s8OB-rVlrC!)`[o!b25SoD\l6!0ms+LHsci4%H!)*'P!9Mr7"-3E^pO`F# +rrREF(tJWf!!%M#s1A:45QE/+Q2p$prr_-Y!5I^s"6LmUoDAOlYlJnGK`IA8rs"_& +s8P1]g&:pSUEu]84=0t+"XQ;2s!8uhrs$4<;?-YY-2dcD4=0Y"!@9l,rrUjR;>pLr +js<.crrFDlr;Qhn!+Y0k!WW4mW;csL!!(p*rs&'@!$tL,g%t^cF9#hBs8QR/A,lSk +,pfhrs03jrs8RcQbl7VZ,s;5-fd.rLs8Th[!5JR649-\Bs8QR/;=skh,s;/+!mCXu +r;QhP!2K2d"7mfbk4S`UK`K?CrrN0#9D=_PjkB_:VZ6_KK)^W+!al!^ec,[N!.TV# +]Dhpt!%.K,!9MZ/"5a(Y^ZPOu;#i`@rVm,b493.rf`4/5rs-ao-3+"?!+Z!-"]59Q +s#_V+rrsc3s8PprU](2s;#mBks#_V*rrG5.o`"q<4T,3\4=/5NrrQ[1U\Xok;#ljZ +rrP:_^ZPOt!!&Xirr[`N!8l6)!p3u=rW!!GA&&!B!@9&irru=Hk5TN'Pl:Ud@jTh. +K`K?rrrsc3s8QR/U](2t^Aq.2s#^:drVlmE-1q3<,s;/+!mCXur;QhP!/:(F!^$I: +o`"uH!6idh!WW3npQbg@gA_8q!!&@;s+gUU(][+WrrN0#ItI^4rrPFc-MWl,jjO/2 +hZ*Ykjo5WL!$sa]Ki',rA,cK6F9"Fub`jCRU]19549/m+^LI7Rs8Ppr;0;j<,s;5- +fd-W?beI!T;?$Rr4=0q*!B_\#rrFE.r;R#,!%"Da@fSXirs_gObl@^r,liYCUHANd +jo5A^!2$4i"+L:Nhp;<1ULPSr!!%`Qs1\PUr;QtT!0mLG-0G%'!egWurr3-J4TGF- +-2[]G,piTk4=0q*!B_\#rrFE.rVlrC!/:@N!egW.p&>(U!+YX#!egWuci4%H!)*'P +!9Mr7"8^@sYpBAM,uOU?!`:8frr32H4='t--&(F[!WW4mW;csL!!(p#rs.\?!!'e6 +K`Lrq"9=/U,pi?d!egWurr3-J4TGF-4T#-^494(74=0q*!B_\#rrFE.rVlrC!/:@N +!egWLp\t?K49/m^rrRlSbg6:j!!#[dQ2p%"rrZX/!9\t6M>mZk!!(p,rrN0#ItI^4 +rrPFc-MWl,jjO/2hZ*Ykir9,6bfo5ErrUltg%bRJbfoq`!87,H!p7_Ng]%?!bi\Ns +!p7_Nir9&[!2$4i"+L:Nhp_T+Pe[(p#)*&!s+LGMqLo$ds!8udrrRlSbl7VG,s;5- +,s;))"ZueQ!!&Xirr[`N +!8l9*![RiAqu6kB!0mNG,piKh#%Jsas'l&(rVm(D!2KRJ!6kHB"slD3s%rd$rVm): +!'L;]4=0q*!B_\#rrFE.r;Qg\-0G4,!qR^#q>UQM,pge(rrRlSbg6:j!!#[dQ2p%! +rr]G)!0;a3N;j"S(]Z8=rrN0#ItI^4rrPFc-MWl,jjO/2hZ*YkK)aL'!WW4mW;csL +!!(p*rsGM$!+X7Qs4Ll^-3!oG@fU$?cUEq3K4=);-rr3!]-2dcD4=0Y"!@9l*rrus5,s3IR +A,ZE1493V*g%YONL&_1s!'L,X!egWuci4%H!)*'P!9Mi4"Le@2+Qn@VO8f<;!!#:4 +rrN0#ItI^4rrPFc-MWl,jjO/2hZ*YkK)aL'!WW4mW;csL!!(p(rs%VM;*6sNU\auo +ULQDKPihoD"m0nh4ET`ars#`0!WW4MK)`I_!^H`4pm(pAdf0F,!!'ccs4I>Q +!!&Xirr[`N!8iD.TDnrm!)*'P!9Mc2"ntOf!#X%6s-[Sd!!#Qerr[`N!2kF`T>(F-!)*'P!9Jh4K)_MDJsNp4 +!9MQ,"@)qe37ic^iVs)UGQ7^TkGJ7ZIt@Zh!!#[dQ2p#us+:9Ds+6QHQ2p$mrs%@/ +!!!:ss+:9&s+:9&s+:9&s+:9]rrMj2o)Jbe +K)^H&K)^H&K)^H&K)^H&\,QGho)Jd:K)^H&K)^H&K)^H&K)^H&\,QL')"dk/:kJ_! +s+:9&s+:9&s+:9&s0_k,O7`JQc[u1Ks+:9&s+:9&s+:9&s0_k-pDEW)!)S:IK)^H& +K)^H&K)^H&K)`1W!0?jS!7-8sK)^H&K)^H&K)^H&K)`1W!V[H,!!#iIs+:9&s+:9& +s+:9&s+:9UrrA,U!!(>ss+:9&s+:9&s+:9&s+:9UrrMj2qZ$UmK)^H&K)^H&K)^H& +K)^H&YQ"T`qZ$WBK)^H&K)^H&K)^H&K)^H&YQ"Xt)#XF7:kJ_!s+:9&s+:9&s+:9& +s/l;$O8T%Yc[u1Ks+:9&s+:9&s+:9&s/l;(pD$1 +!1NrgBS-89s+:9&s+:9&s,m<]hgtis!!"-ns+:9&s+:9&s+:95rr_-Y!-j+1T>(Fu +!$HmnK)^H&K)^H&K)^u5"5a(YT7[*8rrQR.+G0WFs+:9&s+:9&s,m<`hZ*YKK)_JC +!al!NK)^H&K)^H&K)^H&OoGO@!!&XCs.B;m?iV=$s+:9&s+:9&s+:95rr_-Y!2"lC +TDnt#!$HmnK)^H&K)^H&K)^u5"5a(YT7[*8rrQR.+G0WFs+:9&s+:9&s,m<`hZ*YK +K)_JC!al!NK)^H&K)^H&K)^H&OoGO@!!&XCs.B;m?iV=$s+:9&s+:9&s+:95rr_-Y +!2"lCTDnt#!$HmnK)^H&K)^H&K)^u5"5a(YT7[*8rrQR.+G0WFs+:9&s+:9&s,m<` +hZ*YKK)_JC!al!NK)^H&K)^H&K)^H&OoGO@!!&XCs.B;m?iUu:YlN%#s+:9&s+:9& +s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm +^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&XC +s.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H& +K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfn +K)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lC +TDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9&s+:9& +s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXN +s+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8 +rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YK[Jp8lUTjb!UQiUp!al!ApQbfnK)^H& +K)^H&K)^H&SGr]K!!&YVrr[s;L$$e_"$?P`FOC*hYrqq1!Frn1rrZa2!'J-u!al!A +pQbfnK)^H&K)^H&K)^H&SGr]K!!&YWrr@cP!!4HVk0s>4,ldp-dJj1mq#CFmk3`0N +49,@-r;QkQ,pf>0rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKli-rIqu?dE;5;\A +"!mpI4OX60bkD)<--YfW"$?P`-2miDg&:sO--Q;i?iUl7Q2nXNs+:9&s+:9&s+:9@ +rr_-Y!2&TW!'L&W!@1U!!,3sg&D.#!!#.0rrC:B +!!%`PrrJl@rVuq.n,EJP!!">CrrZ*u!+X4P!al!ApQbfnK)^H&K)^H&K)^H&SGr]K +!!&YWrrtRc!%"mI-2RZBL"cP/,ldp-df0<^rVuqPrVm#E,ldokn,EJP!!">BrrLg+ +b5VNN!#,*m!5='bK)^H&K)^H&K)_A@"5a(YTBlL_49,@-s8V4k-2[`CA*X'pbh;Xg +"!mpI4OX60L&M&PPl1O`49,@-n,EJP!!"=^rrQR.'DIdm^4QB:s+:9&s+:9&s.')k +hZ*YKli.&L!!">CrrI3fr;Zh>q#:?/re1BJk55/a;#gU$s5q(M^\[s4,ldp-q>UQ@ +P_HmLrrV>:^\Ig1UP7k%rr@cP!!(7@rrY@`!%%LA"3cIQbkh>A49,@-r;QhnKsCLS +"m0nh4Cb/arrTrhk4nrWPa(J5!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&YWrrY@` +!%%OB!R*\)!!';$rrJ?1qu?dE;;(sK!87>O!^'=+rVusFFSu.@,ldp-qu6\N-2dfE +-&)?u"Qh!1!5JC1"-`cc-1h-:L&M&Pbl.PEfd-Uu-2miFo4'*F!!,3er;Qj]!!">D +rrB>'!!(^MrrJl@qu@!KL&_1X!!">:qYpY-!!#m^rrQR.'DIdm^4QB:s+:9&s+:9& +s.')khZ*YKli.&L!!">@rr>1\!!#.Zrr?R(!!FV1s8U=:!!$O-rrXPI!'L2Z!'L&W +"*FSCPl:X_4So'X-2mlEbk1o8L&M&Pbl7VCbU*5g!/:FP!R)kc!!';&rrY@`!%%UD +!/:CP!/:CO!2K;h!d+H>rVuq.qu6Z2rVupEli.#o!#,*m!5='bK)^H&K)^H&K)_A@ +"5a(YTBlLZ49,@-q>UKX-2mlEU]18nPl1U]-2dfGFT;Bbo`,!,rr3'H!!#.[rr?R' +!!C"9jsC!,!-J/=!/:CP!'KlQ!+Z!."Ja2*;'l2A!%%UD!'L#V!%%UD"$?P`-2miD +L&M&PU]18ofd6Ut![TrTrW!!^s.fMm!3uJ%!)`^q!+Y?p!al!ApQbfnK)^H&K)^H& +K)^H&SGr]K!!&YWrrY@`!%%F?!/:CP!'L8\!%%UE!/:FP!-J2?"$HV`bkqGC4GAK! +rVupqrr3'H!!#.\rrAhm!!?)n^HDJq"&]*uL&M&Q-/&7s!%%UE!2K/c!'KuU!@>M[ +rr?R-!!?`GUF#m>!0mK_"$?P`-2miDL&M&Pbl7VB;>pOqA,cK4YpC]ks8Psq!!#.[ +rrBh5!!+D.li.#o!#,*m!5='bK)^H&K)^H&K)_A@"5a(YTBlLZ49,@-q#:T],ldok +s8S>_!!IEDs1_G0!!AJcs31EA!/:CO"!mpI-3!oH,ldp-rr2s\rVuq.rr3,m,ldok +rr2s\rVupqrr2tPrVupEo)A\Pp](=Wbl.PA-2mlEPlC[_^]"354T>?_49,@-rVljp +rW!&Es8Tk5!!#.UrrLe!rVuqPrr2sqrVupqlMgon!#,*m!5='bK)^H&K)^H&K)_A@ +"5a(YTBlLZ49,@-p\tXJ!!">Fs#^8]-1dloqu?^ZrVlsG!!#.Zrr>1\!"R6Qs!7XF +4TGHD,ldokoDS[hA,ZH1bl@^1Y!!4H/Pl1O]U](5n4T,3] +,ldokrr3'_!!">Drr>1\!!CIFs&&aq!5J7-!+Z!."""!I^\n-4^Zth#?iUl7Q2nXN +s+:9&s+:9&s+:9@rr_-Y!2&TW"$?P`-27EH,ldoks8OAF!$rrh!!+C"r;QjF!!">C +rr@cP!"$mLs!7XF4TGH*rVup\r;QbNrVurBrr2sqrW!!^s-3K_!%%18"$?P`-2u*g +k5,)XL&M&PL&CrQ49,@-rr3'_!!">Drr>1\!!^[Is!7XF-2%9=o-OA9!d+H>rVupq +l2Lfm!#,*m!5='bK)^H&K)^H&K)_A@"5a(YTBlLZ49,@-q#:T],ldoks8ODA!!+C" +qYpXD!!">Crr@cP!"$mLs!7XF4TGG8rVuqPr;QbNrVurBrr2u5r;Zkn4T5<\L%50F +,ldp-pAY+TrVurBr;Qj]!!">ErrY@`!%%UD!'L5\!mL\grVuq?o`"oFrW!!G^ErjZ +!5Idu!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&YWrrY@`!%%F?!/:CP"&]*u-2[`D +4JV]O"!mpI-2dcCFT)7Hbl@\h!!#.]s.fPn!/:@N!/:CP!6kEA!+Z!.!%%UE!%%.7 +"!mpI4SJdTA,ZH.bl%JC49,@-rr3'_!!">Drr>1\!!:CEbl.SBL%G?_49,@-rVlj[rW!#Ds4RAO!+YX#!2KAj!5Iat!al!A +pQbfnK)^H&K)^H&K)^H&SGr]K!!&YWrrXPI!%%LA!R)kh!!#.\rr>pq!!%-6rrXPI +!'KuT!87>O"XVCms78AP!!&8_rrY@`!%%UD!'L5\#L*5J,ldok^]"07k$pNKqu6XY +qu?^okPkTk!#,*m!5='bK)^H&K)^H&K)_A@"5a(YTBlLW-2mlFA&&#e!i'6Or;Zi4 +rr2u5r;[!I;2']d-2mlHPlLb0rW!$H4?Oqg!!%`PrrXPI!'L8\!/:@O!^&Rkr;Zi4 +qu6]Z-2dfDFRT53,ldp-p&>"hrW!$H4?Oqh!!">DrrY@`!%%UD!'L5\"3gfFL&CuV +;2'^6,ldokqu6Z$qu?`3kPkTk!#,*m!5='bK)^H&K)^H&K)_A@"5a(YTBlLW-1_*: +U\t,lA+fm*-0G7--2.B>4T59^,ldp-rVlj[p](;9q>UG:rVusFk3r'G +-27H?Z2O\)49,@-rVlj[rVurBrr2s\pAb1>qYpOXrVup\k5PKj!#,*m!5='bK)^H& +K)^H&K)_A@"5a(YTBlLWFS,V7-):>:!L+o+!!,48rr2sEp](:Vr;QjF!!$O-rrM7E +q>^M*q#:=krVuq.mf*Ad!!$O$rrKk\qZ$XCU\t,o49,@DrVm"S!!">-rVljpq#CFm +g%t^K-2mlEUZVRX?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2&QV!l&4kq>^RC;;(^D +#F&(J,pbZq^\n*3-2moC,lp,mqu6bn4Ak8pOq +FQEH'?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2%:2"!mpI-/AM#4T5<\UTFJ!js:!- +-0F:g!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&Y2rrXPI!%$J$!87>O!%"]G!0mH_ +!'K:^T%57^P1h0rrQR. +'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K +!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H& +K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!A +pQbfnK)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y +!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9& +s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&Y;rr^rubiXNW +ec,\Y!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT@*Z>KdH]u![Tt6k5PJE^]+66;'k&u +!l$&*qu6YMrZqSBg%PFHUHJN%!E%PErrLeMrZqPSci4&S!#,*m!5='bK)^H&K)^H& +K)_A@"5a(YT@3`G@fRfsKnWAM!0l^I!nelRrr3!r-/SY(bU!85r;R"3!)\Gl,ph7> +rs4;Y-$4iN!%$=ors.4'-$4iN!'JX.!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&Y? +rr^pS4S/OO"3`&;k3;mIbQ*@NrrfSQ!!(7ArrTq8;?$RsbU$-^rr_C04S/RP!i#`m +q>ULn!5JO5!egW=dJj8U!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT@];'c2g;;(tH,lf5;L&Y!rrVm(s4='tR;:(pbU$cjK`K?qrrFDlr;QhP!0m?[!qX1Ar;QdD-1h-<^Aq-YrrQR.'DIdm^4QB: +s+:9&s+:9&s.')khZ*YKe,KR5,lhGip\tI\!+U_:490L&rt3!l-$4i_,ph6/F9#0l +^]-DBrr3XR!%!>Q@fRh.s8Rd!4?S=O49/7Rrs&)Ws8RcQbl.PB,s;,*!mCXuoD\m, +!'KoR"6M]G^X<&_?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2%^>#GWRF!$sa]g&1jO +@fV5]rs(Xdg&M(7!5JO5#,;0.s3(Isrr33c-3+"u!'KlPrs,;!;?-ZM!'L5[![T/T +p&>)I!6kEA!@9l+rrUCE4S/RS492Y[rreQK,pf>5rrQR.'DIdm^4QB:s+:9&s+:9& +s.')khZ*YKd/O034=0t,!BeU*rrFDlr;Qu9!-J7o!'L2Z"bj5]bQ*@rrrtS3s8R0@ +U\t,r494(7K`InHrrQ$tbk:u;K`K?qrrFE.r;QiB!'KoR!^$Hmp&>2*4?NU+bgHFl +?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2%O9$,:R.!%$=uf`3>rKa)W!4TD/VL&(`M +bQ*@rrrtS3s8P1]g&1jSF9')UK`K?qrrRlSbk:u;K`K?qrrFE.r;QiB!'KuT"7nVT +A+BR#UAuUfrrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKb5VZU!)`d?!!)jA"B#2Q +!/:7K!mCXurr3-a-3+!--2[]HK`Hi,K`K?qrrRlSbk:u;K`K?qrrFE.r;QiB!/:1I +"3`%kA+0F!@fW:PrrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKe,KG24Sf!\,piT8 +!'L&V!i#aLq>UN?!/:FP#!=43s#^;7r;QtT!5JPf!6kEA!egWup&>)I!6kEA!@9&i +rrSDbL%tZMYpBCFo`"p_r;QhP!/8l$!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&Y? +rrOJH^\e$8o-HO!s!8uhrs%VMg&K7r;>gFt4Al.&!/:FP#!=43s)\79r;Qs`!87C+ +!6kEA!egWup&>)I!6kEA!`8sNrVlq/!6k9="3`&;Z1\+ubU$-arrQ[1UXK/D?iUl7 +Q2nXNs+:9&s+:9&s+:9@rr_-Y!2%a?",-_$^\n*:@fV5_s%rc\rVm+4!/:IQ4=/5N +rs$4<;?+i?FT2:E4=1%-^ApCprs-:=4TGG8!6kEA!egWup&>)I!6kEA!i#a*rr3&D +,s;#'"7mfbbk(i9,pge7rrUCj-.2_o?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2%^> +$"Er84EQ9e,lg(,rs7a5!+X6f@fSXjrt2L9-'ZW<,ph7Ef`3=?Z2Zp4rr3F;!'I%# +KdA%[s8RcQbl.PCK`K?irrRlSbl%JG49/m8UEooFrr35I,uO^BF9!Wa49/7XrrFDl +rr38!!%"DaPU-=)dJj8U!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT@*Z?KdA&E!!+C" +r;QuS;'c2B,uOU?!O4cd!!,4+rr314,lhHT;'l2@#)+?'!$tLqrr3%R--Z>f!ehrE +p&>)I--Z8d"_/hY!%"E=rrpUm;?-Ynpa,q>!@9&jrrJl@rVus]Z-`LP?iUl7Q2nXN +s+:9&s+:9&s+:9@rr_-Y!2%U;"6RhOg%YLIbfok^!nkfNqYpQKp\t<=bi[^\!p7_N +iVru4bh:;A!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXNs+:9& +s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR. +'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K +!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H& +K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!A +pQbfnK)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y +!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9& +s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7 +Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(Y +T7[*8rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H& +K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m +!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YK +K)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&XCs.B;m?iUl7Q2nXNs+:9&s+:9& +s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H&K)_A@"5a(YT7[*8rrQR.'DIdm +^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfnK)^H&K)^H&K)^H&SGr]K!!&XC +s.B;m?iUl7Q2nXNs+:9&s+:9&s+:9@rr_-Y!2"lCTDnt#!#,*m!5='bK)^H&K)^H& +K)_A@"5a(YT7[*8rrQR.'DIdm^4QB:s+:9&s+:9&s.')khZ*YKK)_JC!al!ApQbfn +K)^H&K)^H&K)^H&SGr]K!!%7q^Rr7B8,s=tQ2nXNs+:9&s+:9&s+:9@rrCr.!1Elf +'DIdm^4QB:s+:9&s+:9&s-s#g."VGg!!"\HQ2nXNs+:9&s+:9&s+:9?rrDfd^Aru% +E!0#@!"rnaDua@LDub%SQ2nXNs+:9&s+:9&s+:92rrB=d+!$HmnK)^H&K)^H&K)`L`#,`"4!"`PAlG!F/!!$uc +rrA\i!!(oGrr@d+!$HmnK)aX+!b4@- +p&>)g4L)m*"(M<2;?$Rqbk(i8g#dndK)^H&b5VV=0E;Bfjo5FTD\`ihjscL5QCf)jSo!A,ZH.4G*Tb +s+:9prr_]q!''$="SW`5!-$D:!)NOn!,oDt!f+P2l2Ljp!!%9(rr]_1!#X48!&4BP +!"cSg!gg[RK)_qP"$?P`-2.?@,ldok`r?5h!!">Fs1eL4!@?Fqrr@0>!!%_)s+:9& +s31KFT)\khir9"fJcPcM!Z5nFm/I/q!!)3Arr?_a!<)s!.%c+kY5\Sd!!">=rrXPI +!%#\c!0mH_!/:FP!2KJm!'L/Y!3uJ&!+UW\K)^H&bPqZh!!r>XrrL/2JcPcM!>rlE +rrP.[5iDYCT.kisrVusikCW`!6kEB!%#\c"$?P`-2dcCU\t/mA,ZE. +jsC!,!'Gl5K)^H&b5VNF!&0$)hu!6kEB!'KZK!R06RrrBh5!!$O+rr?R-!!%`Prr>1\!!+D.m/I+>fn06U +s+::0rrPFc5_B$krre)_!!&ASrrN0#ItI^Vrrqk!!!!;^K)`Rb!Mac7491*6rrY@` +!%%C>!6kEB"[)hbk(USFrsb`Wk5YHY!!';(k.cVbpAY--re1BJk4S`S;>pOq^\[s1 +4T,6]U]4j&!!';!rrCaOK`RFkqu7"F!!%`Qk&`^34JRN.K)^H&l2LfM!'l/9g]%E. ++92])nG`Oi!.TV#g]%AZ!!#99s1nX8UF#^9!2KPn"$?P`-27E>bl.SH4TFOi!!'e1 +rrnVe!%%ZurW!!^;'l2A!@;jarrJ?1qu?dE;;(aE!5JL5!)`Rl!V7W:!!+C"r;Zh- +q>UK14So*Z4L+kb"XO-K-)2da!!%+ms+:9&s6BUc5QF'$s4[JT^An7!nG`Oi!.TV# +gA_8"!!&@;s2+d9Z1e4uL&V)S,ldokq>UNYbbP.;!^-LIrVup\qYpOArVuuCbk;#: +A,Q?,A,$$)-0G%'!)`^q!5J=/!R)kd!!#.WrrAhg!!';'rr=A>!!+D.K)^H&K)b0: +!^H`NK)aO(")%Z7fCAkB!!%M#s4[JTpF$"aK)`^f!'L5\#:2KBF\qu?g]s5kX,!!%-=rr@cP!!5:_bk1r9^]+65Pl1U]-2dfDFSc";Z2O_' +;>1"iZ24M%-/&.p!SJdu!<"5C!!#.\rr=AB!!+AlrVuq_K)^H&K)b0:!^H`NK)aO( +"5a(YJ+?;Kk()^!)`aq!%%UE!/:FP!-J2?!'L,X!'L5\!5J4, +!/:=N!3uA"!)`^q#\3#ss03jM!%%XE!%%OC#!DMK,ldpeK)^H&K)b0:!^H`NK)aL' +!\aU>nc&Xj!.TV#g&D0C!!&@;s24j:4T5<];;(aE!%%+7!/:FP!'L5\!)`aq!/:CP +"""!Ibl%MAL&M#U,ldoks8S>_!!IEDs1_G0!!&8\rrAhn!!$O$rr>1[!!+CiqYpQK +rW!*as8V4k-2mlE;?$Rq-2dfD4T>?_,ldp-K)^H&K)b0:!^H`NK)aL'!al!Vnc&Xj +!.TV#f`)!a!.TV#_uB_Ar;ZmF;8;u-!%%F@"XPHWFG4i9!!%`PrrAhm!!C"9s!@XE +!/:FP"!mpI4T,3Z4T55Z-2mlI,s5\%bl%J@bl.SBL&M#O;>pOs4TCZF!!">D +rrXPI!%%RC!/:CP#0d)n!!";kqu?aDL&1fLL&M&PA+fj%A,-*)A,H9+4T5<\-2[`E +-"H*9rr=AE!!#.\rrC:B!!#-5s+:9&s6K[d5QF'$s4I>Q?iV>>rrN0#J'7iqg!#/( +UY1q4![%JmK)`[e!P_M0!!+C@rVlsG!!#.UrrC:B!!%`OrrBh4!!/iWrVuqPrVlsG +!!">Crr@cP!!:CE-2ITB-&)0p"nO#?!%%71rr?R-!!-Sor;Zi&r;QaZq>^RCA*3^h +!Tk^-!!&8_rrC:B!!#-5s+:9&s6K[d5QF'crrR:)U\k&nUEr%UVZ-^*!$Lh3!WW4M +c2Rgt4So*Z4L+b_!l'H(U&P0:!.TV#^]+AM@jV'R#J^<=js:!-4SSjUbl.SBL&CrN +A,ZH.-2mlE-2dcF,ldokr;Qb=rW!#Ds!@RC!Bd.Orr?R.!!%`Hrr@0>!!>@`s&&aq +!@?n,rr>1Z!!4I#k5,)Xbl%MAbl7VBbl.SB4G*Tbs+:::rrPFc5f3O'K`D*!qu6aE +!!#lnrrQR.+S#I5!!%Mnrr@cJ!!$O,rrCaO!!'d.rrO;CItI^6rrM7ErW!$ts8U=B +!!$O'rrC:B!!#.ZrrM7.qZ$VMr;QjF!!">Crr=AE!!:jR-2mlF;8;i)"Qh!1!%%@= +!2KJm!'L8\!V7W:!!#.[rr>1\!!,3Wp\t6;rVupErVm#_,ldp-K)^H&K)b0:!^H`N +_Z'T^rVuqnrVllArVupEVZ-^*!$Lh3!WW4Mc2RctrW)pDr;Zh>rVlkmrVuq_UAk9; +!.TV#_uBbjbl%J@bl.SE4TGH*rVuqPp\t6;rVup\qu6Y+qu?^Cqu6aE!!">DrrA;_ +!!=PIs&&aq!-J,<#';.;k5YHkrVuqPp\t5gr;Zg[r;Qc%r;Zh-rr2t_rVusrk5>5_ +PU.W\s31HB!%%RC"!mpI-%c/Ks+:::rrPFc5f> +rrN0#J'IuqK`D*8rr3"o-2mlEg&:pP;'e>urrO;CItI^=rrfS,!$tMAK`F77!!?*u +s31HB!/:1I!6kEB!'L/Y!Tk^,!!%- +!!#.[rr?R&!!=P0s+UFP!/:4J!Tk^-!!+Ciq>UFWr;Zr7s8Ske!!9G*bl.SB4T,3Z +4T5<\b_#kHs+::;rrPFc5fE!.TV#`;]l04S\sX-):J>!2KMn!2K8f +"!mpI4So'X;>pOqA,?3*-27H?4T#-ZPU6,*#X$f?s#^8]-0G"&!6kEB!@>tbrrL=i +rVuqPrr3#64S\sX-*dIL"!mpI4T,3ZFT)7?b_#kHs+::;rrPFc5fs8Th6!'Kj_,ldokbkqD@^LR6h!E#Wjrrc1]^]0#d,m;Hl;'i"6rrQ%D +L"H>++96nCs2+d:PW\mj!^(Ser;Qh?4Ce'a"/@t@bkqDDjs:!--0G((!%%UEr?VJ, +Pkb7`PYjOh,s6:arVlss!!$O&rrY@`-,90R"MZ5_-,9BX#GYck,pbZ`U\t,o;#ho; +r;Ql6,lg&Zs+:9&s6K[d5QF'err=AC!!B"rs'ts,!%%OB!+Yj*"$HV`bl.SB-2[`C +4N%1#?iV>>rrN0#J'IuqK`D*8rr3#64T5<\g&D!UK`D*8s8RfP!!">C!!#.Zrr?R* +!!bXds-*K`,piHh"[&"L!%$=rrr\Jc!%$7s![%JmK)_>?!+Z!.!+Yj)"!mpI-0>.- +Pa(h?!6k'7!p54!mJd42k5,)Yk0/GWK)^H&lMgoN!'nL&!6kC +rr>1[!!+AlrW!#Ds313;!-H0Z!al!Nnc&Xj!.W8n!/:CP![TrTr;Zh>rVm(U!!#.] +s31??!%%UE!6kHB!'L2[!@9&k!!:CEL&1iQ,ldokg&:sO4T,3],ldp-fDbmp!.TV# +S,WI7rVur5q>UOC!!"?_K`D*!rr3'H!!$O.rrhp>!!(6^rrQR.+S#I5!!%Mnrr@cI!!+Ci +rr30b!!#.]s1eL4%!;OL49,A8s8OAF!'L8\#)*$W-3+"!rW!@:s8U:C!%%[:,ldok +rr3'H!!#.4rrO;CItI]jrr>1\!!&ehrrXPI!%!6sK)^H&NrK/G!'nL&"=4$JFNj^a +&>LNO!+Z$k!!$O/s.]Po-0G4,",-^T4T>?_,ldqhrVlsG!!%_lrrQR.+S#I5!!%Mn +rr[rT!%%Vu!H]Xe!"(%Ds8P1]!-J8@L&M&P-3!oN49,A8s.]Po-0G4,$&&?Z4TGG8 +!!">DrrlmpU]:@JrW!"Rs-3K_!2J-F![%JmK)_DA!87>O!%%C>"!mpI-%c/Ks+:92 +rrPFc5fNa'U](5s^],S[!'L5\$bu^O!!">Fs+LFQ-2miGK`D*8rr3'H!!%`OrrY@` +!/8Dl!al!Nnc&Xj!.W8n",-^T4T,3ZPl:XhFT;A'!!%`Qs+UFP!-J5?#Wr(eL&Zi, +!%%UD$&&?Z4TGG8!!#.Urs1^e!%%5!!!#.3rrO;CItI]krrA;_!!$O'rrXPI!%!6s +K)^H&NrK/G!'nO'##P@#-3+!Bqu@-Os8S;`!%$e-K`D*8rVlu7!!#.\rrXPI!/:CO +"$?P`KuO&n?iV>>rrN0#J'IuqK`D*8qu7(7!!#.]s#^8]L&_1,rVurBrr36d!!%`Q +K`D*8rVm2=!!#.]s+LFQ4SSjUU](5n4T5<\UXfAG+96nCs.0/mjs:!-^\@a1;#gT+ +K)^H&K)^l2!^H`N`W$,g!!#.]s-3E]"(VB2g&:sTPlHF;!%%UD"3^`F-3!oH,ldq! +rVlsG!!&8&rrQR.+S#I5!!%Mnrr[rT!'L2Z&\gF.!)`dr49,A8s8QR/!%$e,rs1^e +!+Z%_!!">Drs?mL!%%[FK`D*8pAY+Tqu?^CeGfRm!.TV#SGrZQKtm<\!L/h#s+:9& +s,I$[5QF'hrs7a5!!%-@s5kX+!!'e5rrj\K!)`d2rVur5rr3>1!!">-s8OAF!/:FP +!+Z!.!85?k!al!Nnc&Xj!.W8n#_`6Y4TEX#@jV'R%);iB49,A's8P1]!%%UD"]57" +4TE1q!!'e5rs>q1!%$e-K`D*8pAY--qu?_NeGfRm!.TV#K)^H&K)^H&QN%"O!'nR( +!6kEB!0mK_!'L5\!%%UD%8d**-3*uk!!"^Mjrr39e!!#.]s'l$/-2miQK`D*!s8OAF!$u`@;'l2A +"_7Rd!!#.Srr>pq!!"=orrO;CItI]Ps+:9&s+:9:rrPFc5fWg(bl.SBbl7VBFT)7? +L&M#OL&M&Rbl=I4!!=PIs!@I@!@?mHrrQR.+S#I5!!%Mnrr@cJ!!,3srVm0d!!#mr +s+LFQ-2miJPQ1\0s8Skg!!O\KK`D*8p&>#erVuqPe,KIl!.TV#K)^H&K)^H&QN%"O +!'nR("5*YS-2miGjs:!ir;R&b,ldqhs8T>Mr;['bF?BOLs8ODA!!,sM_uBdG!$Lh3 +!WW4Mc2Rgt-2dfG,pd'9qu6u-,pfhrs-*K`;>pLsf`2!urr3#(-2dfM4EN[c-3'_? +!)`Fh"&T$u-.;ep+96nCs8;ltPb[jM!L0A,rrL@+K)^H&K)^H&hu@Yrma>rrN0#J'@omk5ENn +rrSF=k5>5\P_Ifgrr^K0PhH'9"dJ0Ls-/61rrhI1!!%`$rrO;CJ%GX\g!&a]!R/dG +rrY@`!-Io6"$?P`FOU6l,lf7Ro)A`q4T$K+A&!WqK)^H&K)bWG!^H`NU&P3@!!%_d +rrQR.+S#I5!!%M.rrcg3!%$dUrrO;CJ%P^_K`D*8q#:DL,uOI;"(M<2;;qNW,ldp- +p&>+?!!#.2rrC:B!!%`Drr=A@!!,sZU]1F+,s9DmrrIgqg]%B<;'f(ks+:9grrPFc +5b\2[,ldq!^&J.A!$Lh3!WW4MNW0),!!$NVrrO;CJ%P^\4T5<\PktC[Z2O_'A,?3* +^]"35-/nk+,ldp-p&>+?!!#.2rrAhn!!%`ErrC:;!!+Cih>[Q=Kqm9"!p533q>UGZ +rVup\ao;I-!!#mZrrTrh^\Rm0;>pOqFFsOEs2=p=5QF'CrrXPI!/8,d!al!Nnc&Xj +!.U%/!2KMn!5Hq]![%Jm]DhkQrVup\qYpOXrVupEqYpP*rVup\iVs!+!!">>rrN0#IuaO2 +;#gSBd/O.i!.VW\!87;N!87;M!2KGl!878L!%%UE!2JNQ"!mpI-2%9?,ldp-eGfN& +rVurBoD\g7rVuqPrr3"o-2mlEA)I:dbl.SB4PB`7bl.SB4So'\ju`ViUW`Z8 +!6j^-!/:CP!/::L"L06Q-/!nMK)`dh!^H`NU&P3@!!&e-rrQR.+S#I5!!%M/rrY@` +!-HTf![%Jm])MaVrVuq_r;QaZqu?`3r;Qo^,ldoki;Wm*!!">BrrQ\-g&D!R,ldp-eGfMYrVurBoD\fE +rVuq_r;Qj]!!">%rrXPI!%$:t"!mpI-0"q*g"G?a!3uD$!+Y9n!6kEB!+UW\K)`@\ +!^H`NK)aL'!al!Nnc&Xj!.TV#f`)!q!.VT["Qh!1!%%UD!0m?\!-J/=!'L5\!2KAi +"3cIQbkh>H^Qdm\s5p(u4ET`brrXPI!%%RC"$?P`-3!oH,ldp-q>UQ@P_HmFrrBh5 +K`Kg$rs.\.4=):9PW\pF!86uD!/:CP!6kB@"$?P`-3!oFUSIhg"PK#L4I#[A"3d!` +^\e$5@jNE`rW)mC!E&"VrrAhnK`Jm^rrqP,4?R,Kr;Qk/,pb\Q!<"2E;UTNUP5K*qu7"F!!%`Qk&`^34JV3A!V7W7!!#.Urrp/I4?R`#rVm#_;'dMNrW)mC +!+Z$.!p52jrVlq/;;(gG!el?jqu6Ykre1?eK)^H&hZ!XB!'l/9f`)"\!$Lh3!WW4M +K)aL'![%Jm\c2XlrVur5rr2s\qZ$UYrVllNrVupEqu6`h@jV'R!BdXcrs$4 +!H]Xc!!+BUqYpSk-2[`G-&)C!^\%R2FT;A_!!">BrrKAer;ZjEA,Q?1,ldokUF#g< +!-IQ,!+Z!."ApHF!%%F?!+Ym+"?`shs)do6%);iB49,@Ys8Ppr!'L/Y"&T$u4T59\ +F=$hb!@;6-s+::/rrPFc5_B$grrQR.+S#I5!!%M#s4I>Q+96o%rr@cP!!IEDs5kX) +!!">Drr?R.!!$O,rrL=iq#CE"rr2tPrVupEq>^kes8OAF!'L;]ff]35!/:FP"!mpI +4T,3Z4S\sWFSu.>ff]$0!-J2>!+Y^&!%%49!/:CP!6kHB!R)kh!!@rTs#fuT!87AO +!'L&W"*FSC^\%R,FT2:?4SSmV4T,3ZU\FfjFT9,K!!@?Cs#g8\!6kEA!+Yg)!'L5[ +!%%@>!@?mqrrBh5!!4J/4T5<\bkh>>A,$$*Z2\q=!"$F?s!7XF-3*ukrVur5rVm#_ +,ldokrr2s\p](:VK)^H&iVrsE!'l/9f`)"\!$Lh3!WW4MK)aL'![%Jm\c2Z_rW!$_ +s8S>_!!FT1!!">DrraVJ!%$e*rr>1V!!">Err@cL!!">E!""AZs!7XF4TEVOr;Zh- +rVlsG!!#.[rr?R'!!'e5rrM^;r;ZmF4=0t,!'L8\!/:@O"!p&l-2dfD-1_'9A,ZH2 +UWes"-2mlE-3!oE4Sf$X-2mlHbl@]QpAbE4s8Rd8,piKir]C0Xrr2t.r;cgCr;Zi4 +rr3#P-2mlG,s3LQ!!YRcs+NQ]-2diC49/7XrrbFa!%$e,rrA;X!!%`Prr=AB!!+Al +rVuq_mJd/KrW!"Rs'u$.!/:=M!0mE^!^&RkrW!.Vs8QRk,piKir]C1&rr30K!!">F +s+UFP!)`^p!-J2?"(VB2A,QE,-2dfD^OlK;s5O%[5QF'$s4I>Q?iV>>rrN0#ItI^Q +rrO;CJ%5L_,ldoks8P4\!!-S>rW!&Es8Skn!!#morr?R-!!?`GUF#m>"-iicL&:oP +A&$7e!!n;Ys!7XF4MN3@!!$O,rrXPI!'L8\!2KJm"&Yi.4T5<\;?$Rq;>gIsL&_1, +rVuqPrr2sErVuq_rVlk-rVupEo)A\PpAb4?^]+654T,6^-$7gorW!#Ds.fMm"&Yi. +4T5<\;>^@q,ldokqu6Z2rVusFU]18n4T5<\L&V)P;>pOqA,cK1YpC]kqu6aE!!">A +rrY@`!%%XE!Tk^-!!>?Jb[^VP!%%XE!%%OC#!DMK,ldpemf*9@rW!$_s8S>_!!#mn +rr=AE!!&enrr[s$4PBZ4!6kEB!'L,X$RGcQ4TGHD,ldokk5PA\-2mlGg&Jhd!!+C@ +rr2s\rVuqPK)^H&ir9'F!'l/9f`)"\!$Lh3!WW4MK)aL'![%Jm\GlPNrW!#7jsC!, +!Palu!!@rTs&&aq!5JI3!%%UE!0mK_!5JL5"$HV`L&CuRU]:A?\4T5<\A,cK5o-FA:-3+"[r;Zhmrr2tPrW!&Es8Skn!!%`MrrXPI +!'KiP!'L#V!BeU)rr>1\!!FUls8RfP!!:CE4T5<\A,cK2o-FA:-2[]E,ldokqu6Xn +rW!)+s8SiVr;ZrQs8Tk5!!#.QrrXPI!%%LA"!mpI-3!oEFT)7?4T59[;>pOtbl@\h +r;Zg[rr3'H!!#.MrrM7.rW!%qs8U=B!!">Crr@cP!!$O$rrC:B!!#.YrrCaO!!#.\ +rr>pq!!@rTs.fPn"&]*u;>pOuZ2aj!4T,6[fn06Us5O%[5QF'$s4I>Q?iV>>rrN0# +ItI^QrrO;CJ%5LY^]"36FG9\o!^-M,rW!."s5kU-!'L2Z!2KMn!'L2Z"sj6L-3+"! +rVuq?rVm'a!%$e-s!@LA!)`Um$RGcQ4TGHD,ldokoDS[hA,ZH0bl;2P!!%->rr@cP +!!^[Is'l$/-2RWD,ldp-o)A\PqZ$[D4I#aC!'L5\!3uP'$K`W74TFOi!!">:rVlk- +rVurBr;Qj]!!">BrrsbL!'L:8-2[`CA,cK.;>pOq^[qI-49,@-qYpXD!!">Err=AE +!!';&rrAhn!!@rTs!@UD!5JO5"!mpI4R`:M;>gIp4T6Z+!!+D.rVm!H!!">:oD\n= +!!#.YrrC:B!!#.\rrBh5!!=PIs&&aq$)@P#,ldp-s+Mcs!!$M\s+::0rrPFc5_B$g +rrQR.+S#I5!!%M#s4I>Q+96o$rrqO2!!#,-rW!4gs8OAF!%%YerVuq_r;QbNrVuqP +r;Qs`!!">Fs+UFP!6kB@!6kEA!%%F@!0mB\"sj6L4TGH*rVup\r;QbNrW!/Hs!7XF +-0G1+!/:CP#0d,I49,@-qYpXD!!#.PrrY@`!%%Wg!9X+W"$?P`-2[]Ebl@^erVup\ +r;QbNrVurBr;Qj]!!">CrrC:B!!+Alqu?a[U](2p,ldoko)AeS!!">ArrXPI!%%XE +"!mpI-2dcCbl.SEL&_0!rVup\rr2uBrVup\nc&XP4S/URU]18nbl.SBA+KX%,ldp- +qu6Z?rVup\rVlj[rW!5=js:!--3+"hrVusF-2[`D4JRN.K)ad/!^H`NK)aL'!al!N +nc&Xj!.TV#f`)!q!.VKX!%%LB!%%XE#UKHN-.sRE!%%OB!'L5\!6kB@#!;kc-3+"! +rVurBq#:?+V!!">?rr@cP!!%`Nrr@cP!!(7@rr>1\!!(^N +rrC:=!!,3Wr;Qc@rVuq?o)A\PrVurOqu6jH!!">Fs31HB!'L2Z!6kEB",6d;-2mlE +PlC[_bl.SB4RrFObjtf7A,cK.L&M&P^[hC,,ldokqu6Z?rVup\rVlk^rVut/A,ZH1 +L&_1sq#CFXUOrMts5*bW5QF'$s4I>Q?iV>>rrN0#ItI^QrrO;CJ%,FXA,?6+FT2:? +;>pOq;>pOqFSl(ArrXPI!'KiP"!mpI4SA^V +49,@-q#:>hrVuqPr;QbNrVurBr;QaZrVurBrVllAqZ$Xo^\[s1bl.SBL%>6D4T5<\ +bkqDI,ldoks8V4-!!#.ZrrC:B!!7lSbl%MAbl7VBbl.SB4RrFOL&M&R,s5'(K`TDm +rVupErr2tPrVurBo)AeBrrC:B!!#.ZrrXPI!%%UE!%%XE!6k:Pg'./k02'?rrSsLg"HB,?iV>>rrN0#J*-b4bfo59rrTrh +Z-<4Lg!%\2rrJ@!'KiP"!mpI4SA^V49,@-q#:?B +rr>1\!!(7ArrC:A!!-T_q#:?IrVuq.o)A\PrVurBqu6aE!!">ErrXPI!%%RC!+Z!. +!mL\grVupErVm#_,ldp-nc&S8rVuqPqYpdH!!">-s8S>_!!&ebrrXPI!%%OB!6kEB +!'L2Z!+Ym+!/:FP!6kBA!Fsf7s+::)rrPFc5jA:Mfd.sD!!4HD^[M1);#gT\rVlo\ +bh2psKdAk\,m=8K,pcE`r;QfNg&D!Rf`2!ug&D+]!$Lh3!WW4Ml2M$a,p`Nk,pd'` +n,EJ9!!(^NrrLg+f`)(a,s3J"rW!$H-"F^frrL@+rr3(b!!#mLrrO;CJ%,FXg&(gM +;>pLpbkhA?;>U:mg&:sT--ZDho0!!P"-iicL&M&PbkV2<^]"35L&V)PU\t/mPlC[b +,ldp-rr2sErVuqnrr2t.rW!$ts8QU.!!%`OrrAhn!!?a2s1eL4!0mK_!SKU7!!">9 +rrXPI!'KrS"$?P`-27E>-2mlEU]18nA,ZH.;>^@n4T5<\bl%JD,ldokPl1Ogk#!Ee +s8OAF!%#DYrr_Cn4JVfR!'L5\!6k??"!mpI-3!oE;>pOqA,cK.U](5q-3+"hrVupE +r;QjF!!">9rrA;_!!+D.qYpP*rW!%Ss8UdO!!,4ErVlu7;*<)"rrXPI!%%OB!6kEB +!'L2Z!878M!@?n,rraVJ!%!m-rr_C\,s6eZK)aj1!^H`Nl2L`nq#CD:nG`SQ!!%`P +rr]MP!'Js7!%%==%6WeQs)\5@FT;Bb!!"=urrQR.+S#I5!!%N5rr=AA!!+C@nG`S: +!!(7Brr[?C!-Hrp!6k*9!)`aq#s826Z2aiX!!#.7rrO;CJ%#@W-2dfDU\t,l-2[`C +^\Rm0;>pOt,s4:9rVupErr2tPrVurBq#:>JrVuqPrVlk>rW!0Lk5YH-!!#.\rr@cO +!!58F-2dfG^]4>Kr;Zq0^Q_Uo!!">Err>pp!!=N04=0q+!%%49"!mpI4SA^V49,@- +p\t5Ir;Zm]4=0q+!5JF2!'L5\!6kB@!/:@O"XRZ4F?ClK!!:jRL&CuV;2'^6,ldok +qu6XYrVurBqu6aE!!">ErrBh4!!4H/4T,6^L&_1srVupEr;QaCrVurOoD\eQrVuq. +q>UH0rVupErr2sqrW!'I@tfV6rVup\qu6aE!!">BrrC:B!!#.Yrr>1[!!$O,rr@cO +!!OZYKlfF'rVurOK)^H&j8T0G!'ofK!^$G_r[%LC!+YR!"$?P`L&V)PA,ZH.bhE's +-1q6Hg&M'u!!">Fs3(HC-/&;"?iV>>rrN0#J*Ht7,ldrE-2dfDU[e?d,ldqhrr3'H +!!">!rrC:9!!=PIs5s:\##YF#K`D*8g&D*r!.VHW!)`^q!@@@8rr>1[!!">?rrLe! +p](JrVuqPr;QaZrW!.Es8OAF!'L5[!'L#V!-J2>!'KoS"GQmU +jsB^$!@?n"rrXPI!'KrS"$?P`-2.?=4SSmVFSc";4T5<\bkqD?4SAaT4T>?\4SJgU +-2[]B4T5<\bkqDB,ldokrVlk-p](:Vrr2uBrVup\r;QaZrVurBo`"pErVusFk4nrV +4T5<`g&M**-2.B>;>^@q,ldokqu6Z?rVup\qu6YkrVusFk55/Y4SAaT4G*Tbs5O%[ +5QF(6rs(Xd!/:IQUHJMU!5J+)"$?P`L&V)SYpBB4g&D1$!!%,Ur6,4r4GEe7$$6.I +FT;Bb!!"=urrQR.+S#I5!!%N5rsC%P!6kKCKd?^!-1V!;,ldqhrr3(B!!%,prrgOG +!%!?sbQGV%4L+nc#s81fZ2aiX!!#.7rrO;CJ%#@WPl1R^g&1jMPl1R^L%kTJ^EraW +!@=N>rr@cP!!(^IrrCaO!!&8]rrBh5!!\/Ws!7XFA,ZE.juiJ?!+Yp+!'L)X!%%UE +!'L8\!TlN@!!FSJ!%$e!rrZ*u!+Y^%"$?P`-2.?>juiJ?!+Yj)"$?P`-2IQAF=$b` +!@;7Rrr>pl!!,sMqu6a\!!">ArrZ*u!'L2Z!+Yj*!'L2Z"!mpI4T,3ZFT)7?bk(i: +,ldpep\tB2!!">-rr3#C4Sf$Y-"HfO"!mpI4So'[,ldpTqYpXD!!#mlrrI3fq>^OB +@tO`4s5EtZ5QF(6rrY@`!/:CO"$?P`A+KX%49,A8rVlo\bh2pt,ldqho`"sFbl7VE +bQ%Vhg&D+]!$Lh3!WW4Ml2Li3!!(7BrrgOl!!&ebrrXPI!6kEA!SP]Mrr^IF!%%7: +!R06rrr[rT!'Js7![%Jm[Jp>+,pd[1rrhI1!!#.SrrM7lr?VJSk5>5]^EikBpAY2J +4GEY3!i%kfrr3(q4Ak8UJj4T6W2;5=/r,pfhorsHMN4=):9FP0M; +L%50DKn]1!",/$IFS,S5L&E:u;8;o+"/@.gFSPkAk(Po[,pb[-k5,)YUJ^t9!Frn? +rr]#B-$9"`"6O*'g&(dMUHJN%!Bd.SrrZ*u-):D<"2?,^4S&LRk(T&mrrTH&^\e$3 +PW\mj!HdK"rrZaW-*d=H!l%TSq>UQ@4Ajf,rs7b@4?Oo94GDpLs+::/rrPFc5jA:N +49,A8rVltR!!#.PrrY@`!/8l$"!mpIbjYQ6bQ%Vhg&D+]!$Lh3!WW4Ml2Li3!!(7A +rrY@`!/:"D"!mpIbgZRobQ%Vhmf*BC!!#.7rrO;CJ#`MNfnG.Bk5PG7OT,@Dk2H=? +k2ZIAk4JZRk2H=@bi\d%!TqVWrrD3RrrD25s+:9ZrrPFc5jA:N,ldq?rVltA!!#.Z +rreR.4GCQJrrY@`!/:FP!mEc(qu6i7;'dMNPl:U_FCY.H!b5a&p&>+?!!(79rrSrX +FT2:BbQ%Vhqu6l8F?DZ_Pih-.!al!Nnc&Xj!.X;6"O$iG-0G1+"$?P`L&M#Tk(R;B +L$&=5"!mpIbl7VDUHEYqrro/[,pcE`rr3&Q@tjdZ!ngG)p&>-;rrR:)U]18q +K`D*8qu6hp@luk`UZMLW+96nCs+:9&s+:9&s-EZd5QF(6rrXPI!6kHB"O&.l!0mK_ +!L+o.!!%->rrY@`!/:FP"$?P`L&M#OU\b#q-):KM!!#mnrr[rT!)`Fh"=4$J@m'`: +"$A\Cg&:pW,ldqhs8U:C!%%RC!+Ym+!@=N(rrQR.+S#I5!!%N6rr^IF!%%UD!2KMn +!87AO!H]Xd!!+C@rVlsG!!(7BrrXPI!6kEA!+Ym+#!CT=49,A8qu6aq!!&8WrrpUH +!$u_LrZqV.4Ce?i"3^`F-3!oHK`D*8rVloO4So*Z--YQP![%JmK)^H&K)^H&K)_/: +!^H`Nl2M5>!!(7Ck(P)]!%$e-s+U7K!0mK_"$?P`L&V)S49,A8rr2u5r;ZgDrW!!G +s)e5?!0mH^"Qh!1!)`Fh!%%@>!'L5[#pfQObl@^e!!">Drr?R(!!(^9rrQR.+S#I5 +!!%N6rs-aJ!%%[Ffjk!]!'L8\!)`Rm!@?FurrXPI!6kHB"!mpIbl7VBL&M&Q,piNj +##YC_!!"=urVlkmrVuq_pAY-:p&G)&rr3)E!!">Err[rT!'L5[!'L&W!%$h.![%Jm +K)^H&K)^H&K)_/:!^H`Nl2Lf2!!*!Er;[;%s8Uau!!"!'L5[#pfQObl@^e!!">E +rrAhn!!d#Xb`jCR!/9Y:!al!Nnc&Xj!.X;6!6kEB!@9&j!!FV$s8S>_!!4HgA,ZH. +;?$Rt,ldqhrr3TW!!(7Cs4J[u!'KE+UEonos1eO5!)`^p"$?P`-2%9&Q&N.--ZDhbU!5h^]4>rrN0#J*R%6U\Olj4O!g)$7,ZP4S/UQPQ1\0rr30K!!(7Cs31HB#0d,I;#gSY +r;QcMrr2t.rW!&*s8Skn!!%`GrrC:B!!+BUr.P-8rVltR!!">Ert0qb!'L;]js:!- +PlLc;,ldokkPkT+!.TV#K)^H&K)^H&QN%"O!'oiL!6k?@"!o78k5G;^,ldpTrVm0d +!!%`Qs#^8]L&V)Y,ldq?s8OAF!+Yd'#!;kc-0G5;rVur5o`#">!!(7:rtETV!%$e- +s3(HC-3+"u!!"=hKdHZt!+Y3l!al!Nnc&Xj!.X;6!/:=N![TsnrVllArVuqnrVmWZ +!!(7Cs!7XFbl@^e!!">-s5kU-!2K>h$K`W7!'L;]49,@-o`#$;!!">> +bl.SBbl.PJ49,A8s8P1]!/:FP#pfQObl?>r!%$e%rrB>'!!Qm4,ldpBoD\n=!!(7: +rr^IF!%%XE$HrJM-3+"[!!";kr;Zj\UZVRX?iV>>rrN0#J*R%;K`D*8bfoq`",-^T +-2dcX,ldqhs8OAF!6kKCbQ%Vhs8S;`!%%@=!-J2?!MdF/!!%`Frr^IF!%%=<",-^T +4T>?fK`D*8s8R0@!$rri!!,s3k5PK*!.TV#K)^H&K)^H&QN%"O!'oiL"3^`F-2@K? +bl.SBbl.PJ49,A8s8P1]!/:FP#UKHNbl>le!%%=<"Ao.!-"HoS!5J.*"!mpIbkD&= +bQ%Vhrr32H!!">Fs+U=M!Bd.,J!!#.\rs"/W!'L;] +4T#0\,uMGErs$[I!%%[FPl:Xa +,uMG:rrQR.+S#I5!!%N6rr[rT!'L&V"-`cc-2miZjs:!-g&M'u!!(7Cs3(HC-3+"! +!!#mhrr@cM!!$O#rr^IF!%%=<",-^T4T>?bK`D*8s8Psq!!4HVk2QCB+96nCs+:9& +s+:9&s-EZd5QF(7rr^IF!%%C>"!mpIA,cK8UAt9?k5YHD!!%`Prs9tO!6kK*,ldq? +rVlr]KtmQc!+Yp,!2K,b"!mpIbkD&=bQ%Vhrr3>L!!">Fs4IAP-'\?-!l&6!kl1]l +!$Lh3!WW4MlMgs?!!#.VrrCaO!!&8_rrZa2!%%XE&1%;Vbl@^e!!">Fs.]Po--Z>f +!l'HOr;QaZr;ZjEk4ATTbQ%Vhp&>,J!!#.\rsFG[!'L;]PQ1\0^\n*5UJ\;[rrO;C +ItI]Ps+:9&s+:9:rrPFc5jJ@ObQ%Vhp\t5'rW!!sKk()^!)`aq"$?P`L&V)V,ldq! +s8Psq!!d#K^LJPi-0G1+!Tk^-!!#.OrrXPI!6k0:!6kEB#0d,IbQ%Vhrr2s\rVupq +re1G:!!">/rrQR.+S#I5!!%N6rr[rT!'L#U!'L5\!b6p]rVuqPrr30K!!(7Cs31HB +%F"kP,ldokFNgLW!!#.ZrrAhm!!$O"rr^IF!%%=<",-^T-3!oWK`D*8s8V4-!!"^OBk5PA_49,A8 +rr33L!!%`Qs4J^o!!+D.r;Qb,rVuqnnc&\;!!(7:rrC:B!!^[Is3(HC-3!oFfd6Cn +!)_t[!al!Nnc&Xj!.X;6",-^T4SSjVbU*)c!'L5["sj6Lbl@^erW!&Es8Skh!!#.Y +rraVJ!%$durr^IF!%%=<",-^T-3!oHK`D*8rr2tnpAb2Ikl1],!.TV#K)^H&K)^H& +QN%"O!'oiL"6Lm0;>1"jff]04!BeU)rrZ*u!5JO5"&T$ug&D!PbWPb&!E%PIrrY@` +!'KcN"!mpIbk:u;,lf7jrr^pS!'L5[!p3?+qu?aDA*>rrN0#J*R%9YlFcX +pAY/u-2[`C;>gFq,lf7irrOJH-2miEUF#gaRE!$Lh3!WW4MZ2XnP!!#mbrrM9+_>aQZ!.TV#K)^H&K)^H& +QN%"O!'mji"Qh!1!/7QT!al!Nnc&Xj!.V-XoAH1!$Lh3!WW4MZMt"h!!"=HrrO;CItI]Ps+:9&s+:9:rrPFc +5dLCl,ldpBXT&?0!$Lh3!WW4MZi:0j,ldq!XT&>E!.TV#K)^H&K)^H&QN%"O!'mji +"!mpIUTFIs?iV>>rrN0#J$].XbQ%Vhk,eRa+96nCs+:9&s+:9&s-EZd5QF'TrrQ[V +4KJJ`?iV>>rrN0#J$T(U4=+LQ+96nCs+:9&s+:9&s-EZd5QF'$s4I>Q?iV>>rrN0#ItI^QrrO;CItI]P +s+:9&s+:9:rrPFc5_B$grrQR.+S#I5!!%M#s4I>Q+96nCs+:9&s+:9&s-EZd5QF'$ +s4I>Q?iV>>rrN0#ItI^QrrO;CItI^crr>R2!!"*ms+:9&s+::6rrPFc5_B$grrQR. ++S#I5!!%M#s4I>Q+96nCs6BUb*>6OK!>kfgs+:9&s+::6rrPFc5_B$grrQR.+S#I5 +!!%M#s4I>Q+96nCs6BUb*@/g8!A=G)s+:9&s+::6rrQ!s5_B$grrQR.+S#I5&-.33 +s4I>Q#QT@+s6BUb*@/g8!A=G)s+:9&s+::6rrQj6+G0XGrrP^k5k4jU-idY,s4I>Q +!!%e+s6BUb*@/g8!A=G)s+:9&s+::6rr[`N!9\t6gA_9L&--,.rrPFc."_KPrr]_1 +!2kGKlMgl*,g0Nq0*$V(K)^H&K)b$6"2=g9LP#Q[rr]G)!2oAe"+L:Na+F?FrrZ@' +#k*BFlMgl*,g0Nq0*$V(K)^H&K)b!5""4-Tf7O%Xrrhd-!#YJ#rrh3b!%@Sns4mVV +^An71K)b*8!?EH/?NDe[K)^H&K)^H&k5PP0#QQi9s4mVV?iU2!n,EKV!!%7qs5!\X +pE0GIkCW`urrF,cb?k9'!.t6&s+:9&s5j7`IfKI>kCW`lrrhdu!!#RWrrbRe!-n6i +s5qHlrrIl\JcO^/!BA\_s5j7]*@/g8!A=G9rrE*H +b=r!X*J4K!J:Nj!!#'3s.')i*@/g8!A=GrrrTq8;p0%Z +!%,l`!?E24s+:9&s0D[=!!!nZrrs+::2rrF,cb?k9'!6bBD^At.S +h#RL&b=r!X*J4pP#*P\M%0E;)lf`).0!!#96\#90)#CO:A?jH`md!!*Agf`(rTnGiQ.K)^H&ir9$",g0Nq +0*'2q!l"`4bM<1!-Hf*a*?Bb3K)^H&K)bWG!7139!-$Nh!&4!E!=7k?s+::1rrF,c +b?k9'!6bBD^At.Sh#RL&b=r!X*J4oDel1eGfM&o`,!ukCW_c +s5EtY*@/g8!>baZ0ENL"I*:=H!%,l`!?E2KrrBfcJ"1ug[t=Y#rr>mh!!*AgeGfNP +o`+u2K)^H&i;Wfu,g0Nq(BDXo!g!D0bM<1!-Hf*a*?CUK!3^tSRK*>kK)`pl!71?= +!-$Bd!&4-I!=7k?s+::/rrF,cb?k8d!6`.ZO8s[Oh#RL&b=r!X*Ld!.It@Zh!!%M# +s2Y->;"t"k#j9Y9!3c+s!-!PiK)aa.!?EH/?NCrCbJ41@!.;uG!<=Ii9`Z7TRfba\^]r$0X?`?= +j3?B\!%,l`!?E2LrrRZM!.t6BrrN0#ItI^?rr>ml!!*Agd/O*Lq#CD6K)^H&hZ!Ts +,g0Nq(BDt#"O>ren+l\W"T7uamc;mR!<=Ii9`Z7TRf^M7cMmkuqZ$X&kCW_cs5*bV*@/g8!>bag^]VO-l20iI"9%iVhq6`c!%,l`!?E2L +rrRZM!.t6BrrN0#ItI^>rr>mn!!*AgcMmmJqZ$V8K)^H&h>[Kr,g0Nq(BE4*!lEOQ +jo5D]oB=oa!<=Ii9`Z7TRfbal^]MC0qr%JTr9E(n!<=Ii9`Z7TRfbam^]E$\pAY9I[srm8r'1BmIt+rZpAY0h +k2+np!%,l`!?E2LrrRZM!.t6BrrN0#ItI^=rrCCE!!$u\rrb"U!!qb>s+::+rrF,c +b?k8d!8tWn`pNR$!lodMn,NMTLX5bq!V5.+h#RL&b=r!X*Ld!0IfKJ#s.95l!!%M# +s24j=:]Ldab5VRI!!$tis+::*rrF,cb?k8d!9(]of_bOF!nV)kl2Ul&Gh;fl!W;-> +h#RL&b=r!X*Ld!0IfKJ#s.95l!!%M#s24jbaq +^]bar^]S!!3@2Y3OU>Ti(Xd!>*TTrrD`Sh#RL&b=r!X +*Ld!0IfKK?rr^q#-"H':"2=g94QHGAL&M&PbjbW849-[)^UjFHUQjojrrN0#J!L$7 +T-4(4"!D9,LP!:>^BD#qIom9\!!+dgK)`C]!?EH/?NCrCkJ.)\r;Qf4&GlG.0=Bro +!N74>!!*YWr;QcbkM6.=-Hf*a*?CUK!e11MoD\efrVurOk5PO;!!">*rr@cP!!(75 +rrA;]!!,s3^&J4F!!">-ec,[N!.U@8!T,=)!!49^c[u1hrrTZC)#aL98FM01]DhmP +,g0Nq(BE[7!8.5L!P\p^CUAF +(nZE[RfrrL^_qu?aT[G]X;W$;->!?gk0 +rrN&Ul.l@?-Hf*a*?CUK!e11MoD\eQrVurBk5PNG!!#.Arr@cP!!(75rr@cJ!!+Bf +_>aKtrVurOec,[N!.UF:!13Zb!Isiqs-N`hmoTPi&@[8k^&J*R,g0Nq(BE^8!:Tmd +!Uh0/!!,4/p"'8fTn`J\!f`o#p"'5e./X&G3;^)!Bea(f)s0?6Oi_h!uk*l +d.l2nasd/f!.XqH!9WS&!<=Ii9`Z7TRfY:'^Pf#)lWSa!Q,BF!!#RfrrD9K +h#RL&b=r!X*Ld!0IfKK?rr>1\!!(76rrKlEr?VJdk5G;`49,@D@jV'R!@=!*rrJ?H +r?VJS^\n*3L&M&Pbjk]5L&M&Pbl%J@L&CuP--Z5c!M`Nk,lqN#A +rrN0#J"6N@Du]m)K)^i1")%Z7O+RDIrrF,cb?k8d!:7K%_YO01!0@$X!0m<2!++jh +!-n=k!-nDA!3cA$!;Ys:!<=Ii9`Z7TRfaNV,g0Nq(BEg;!8.8M!V[H0!!#C_f)a5c +q>^U/:k,,8^B:*X:^Hmt!*B!J!%@dG!&4?N!9WY(!<=Ii9`Z7TRf!R)kh!!&8_ +rrM7.q#CFAg&D!R,ldoko)Jb:r;Qb,pAb1Urr2uBrVup\rr2sEp&G30s8Skk!!">E +!!#.PrrN0#J"?TA:]LLAK)^c/"0V\)O+RDJrrF,cb?k8d!:7K$n,<7dO8T%Z#/'ib +!RNt+!!,'Wp&>*fT-4"2!)`UE!3#eq!5JL4!:oL4!<=Ii9`Z7TRf-s8P4[!!GEZbfjSr!!+D.rr2sqrW!'IFG5EGrVupqrr2tP +rVurBnc&TCrVurBq>UGKrVup\rr2s\r;ZmF4=0t,!)`aq!%%LB!'L/Z![V>&rVurB +rr2tnr;ZpGFKo?T!!$O.rrC:B!!%`Prr=AB!!.2+rW!%Ss8R3?!!d#Xg&J<'!/:"D +!WW4MT)SoM!!#iIs,$aW0E;rAs2"^9*@/g8!>bb'^];IRrr=bO!!$@%f)T.T!!+4W +nG`N]&GuM.Er+Af6i?ub;#UCprnd%u!<=Ii9`Z7TRf-s.fMm$^C\kbU!5h-0G7--2[`DL!9Jq"&\4\FT)7?PlC[_-2mlI +4S/UQL&M&PU]18n^]"35L&V)P-2[`LU]:??!!#mrs'u$.!0mH^!SO7U +!!*;,qpth;r;Zj(kPbD\l0[:-!%,l`!?E2LrrRZM!;$3m,ldokp&>"1\ +!!:CE;>pOqFT)4>FT)7BU]:??r;Zn`s31HB!'L8\!6kEB",6dTPl:X_4T59[L&M&P +bl7VBL&M&PL&V)P-2dfDFT2:E,ldp-s8Skm!!,3WmJd4f!.UU?!^H_sK)^Z,"5a(Y +BS-9$rrF,cb?k8d!:@Q%n,<7d@/U'*0Da9#0DtkO&D-dY#5R`J^Y\\_qYpT2#lO`' +./MNq'`A"3L].5Qo'P66!%,l`!?E2LrrRZM!;$3m,ldokpAY-:rVup\r;QjF!!#.\ +rrY@`!'L,X$TnCh-3*uk!!"=!4T#0[-):G=!/:CP!6k!5!/:CP!6k6-rVllArW!%Ss8ODE!!?a2s4RAO!'L8\!87>O"$HV`4T5<\Z2O\&L&M&Pbl7VB +L&M&PL&V)P-2mlE-3!oIjs:!-4T>?\A,H<-4JVBF!WW4MTDo#^!!$DYs+gUU2uk@Y +s2+d:*@/g8!>bb(^];=NrrTQ!.?_49,@DqYpa^!!">Fs!@I@!@1\!!UU/,ldok +r;Qc@rW!.Vs8OAF!%%UD"!mpI4T59d,ldp-s8OAF!%%RC!/:CP!6kHB!/:CP!/:FP +!%%UE!+Z$.!6kEB!'L5[!H]Xc!!,sZnc&Xj!.UX@"4$rIYCce0rrRZM!.t6frrF,c +b?k8d!:IW&eG]CI^\n-5#138!!(6\b!*K1!!U%>u^]KStI/Vk%i:[$J!&4?O!(6Y8 +!5/40!8mbT!93G&!<=Ii9`Z7TRfFs!7XF-2dcCL&M&Pbl7VBL&M&SL&_1sr;Zi4 +rr2uBrVup\r;Qi\@jV'R!@?FirrN0#J"Q`C[f?ESeGfS[4L+SZ!jOkAW;ck[n,NC2 +"2@\qg&(dOk#"7UqYpZN4=,^-rr\kn!9\t6_uB`X,g0Nq(BEm=!9!hU!/LLQ!&+6$ +!Q,-?!!(@DrrMZ,r4iAq!.=_#!T*\OrrB8#!!'G(f)QN`!!&qqrrDCrrAhn!!]4us!7XF-2miG,ldok +rVm0d!!">-s!7XF-2dcC^]"35bl7VBL&M&SL&_1srVusFk5PA\bl.SB4Sf!XKdH]u +!)`=e!WW4MTDo"c!!)34rr?R.!!%`IrrAhn!!&dorrR9B4S/RSk$o_7!!#mnrrY@` +!%%LA!'L5\!5Hn\"1J71c[u27rrF,cb?k8d!:IW&li$h`=T&4"?Mi=SGl7UB;#L=n +bko0WO8s\*h#Q[:rr=bO!!%9@f)S2:!!%9BrrDQVh#RL&b=r!X*Ld!0IfKK@rrC:B +!!#.Xrrh#/U]8R;!!#.ZrrY@`!%%XE"$?P`4T,3[o0!!P#F,8g,ldokU\k&mk*2,0 +rr@cP!!(75rr>1\!!(7>rrAhm!!B"rs!@XE!5JL4$9S:g-0G7-,ldokrVls^!!">D +rr>1\!!:CE4T5<\^]"04bl.SBL&V)PL&M&SL&_1srVupEr;QjF!!">?rrgOl!!">9 +rrN0#J"Q`BIfKJurr>pp!!&8ZrrAhm!!&7arrAhn!!&8VrrJl@q#CC@r;Qblr;Zhm +r;QcMr;Zh-d/O3g!!'ccs24j;*@/g8!>bb(^]=!)rr=bO!!&#Uf)Rr3!!'5$rrDB] +^]KStI/;Y!q>L\rFEr>t<;#UCoo^:N9!%,l`!?E2LrrRZM!;-9kbl.SB +FT2:Bb`ksNrW!"Rs!@XE!0mK_!L+o0!!B"rs#g8\"XS9*b]G01!!#.\rr@cP!"C6. +g&M)rFDrr>1\!!(7Brr@0?!!8qqPl:Xd4Qc\Dfhq_K!'L8\!/:CP",6dTbl.SB-2dcL +,ldoks8R1'FMIhT"MZ5_!%%49!WW4MTDntB!$Kek!SJdt!!'e2rrL=irVup\X8`4R +-2mlEA+op&U\=`g-2dcC;>gIp;>gFoPl1R^-.)YohZ*YkK)`ag!?EH/?NCrCm_Ai" +rVlj'r;Zi*r7:tr#5nN%hu3QTde^`\O8s\)h#Qd>rrBh4!!"5?f)V<=!!"GGrrDl_ +h#RL&b=r!X*Ld!0IfKK@rrBh5!!=N0,piBf!^-Kmr;ZmF4=0n*"&]*u4S8[S^]"04 +-2[`D,piHh"2Fm9L&M&Pbjk]54T,6[-2fq+-2dfE-/&7s!%%C?!@?FurrXPI!%%UD +!-J2?!6kHB!/:CP",6d;-2mlG,s3LN!!C"9s+UFP",6dTbl.SB-2dcC4T5<]bfp"c +r[%LC!)`=e!WW4MTDntB!$Kbj!R)kh!!+D;r;QaZrVusFk,\L^4T,6[4SSjUU\k)n +;2',k!!">Crr=AD!!">Crr>pp!!"=lrr_-Y!5F-c_uB`X,g0Nq(BEp>!65!;!8%,K +!7:Yq!3#hr!#YY6!6"`L!g!D0qV;/1rVlllqu?`Dr7:qVqu?`krr2usmbImD-Hf*a +*?CUK!e11Mo`"odo)Jlts8P4S!!:jR4SJgV-*dCJ!R*\#!!$O.rr@cP!!(75rr?R$ +!!+Cir;Qf4-2@N@U](2p49,@-rVlkOrVuqnrr2u5rW!%1s8Ske!!?*us-3K_#DN3X +js:!-4T,3Z;>pOsbiU5H!!+D!o)Aak!.UX@!e11mdf0<^r;Zg[rVlk-rVusFbcCaD +L&:oN-2@K@bU*5g!@>M[rrZa2!'L5[!Tk^,!!">Crr=AC!!(6jrr_-Y!5F-c_uB`X +,g0Nq(BEp>!6G-=!5JI4!#5=^!0-pW!(d(g!;60'!g!D0q:u&JrVljGr;Zi#r7:qq +qu?`SrVuO!)`aq!O4cb!!PK[49,@krr3'_!%$e,rrXPI!)`[o!0mH_ +"53^h4So*[,uN@crrN0#J"Q`BIfLV=rrA;^!!?a2s+UCO!0ljM"5-OKg&D!Q^P0nS +rrLe!qZ$W?q>UFWrVusFbl%JBFCX#&rrBh2!!(7BrrCaL!!'d]rr_-Y!5F-c_uB`X +,g0Nq(BEp>!7(QC!5JI4!%@`r!-8#-KtldGrrhJZKnZ<$rrUl-^]"06 +k5YJ[bk1og!&g_"I)"p,lmoj!Frnbu*C]+55J,TBIi;(.iO8s\(h#R0Irr>=_!!&_if)Qcg!!(pT +s6e\D!%,l`!?E2LrrRZM!1*Wck02W\!l'H([/U1-!.UX@!e11mci3u-r;ZgDrVusF +oD8IfbWP\$!+Z!-"=4$J,s;&)!'KWJ!0mH_!6jX+!/:CP!Bc)8!!$O+rrM7.rVuq_ +oD\eQqZ$V+rr2s\qZ$V+dJj=+!!'ccs24j;*@/g8!>bb)^];a[rrBh4!!"nRf)TUb +!!%NIrrD!Q^]KStI/2RupAP!k5lCZ_U&3FA)uTa:hu3TCh#RL&b=r!X*Ld!0IfKJ# +s.95l!!%M@rrRZM+O9ue4Sf$X^\[s2jsBa%!2KPn!%%==!5Iq$!/:CP!6j[,!Tk^- +!!0@KrVupEqu6Y+rVupqo)A\9qZ$aFs8V4-qZ$UYdJj=+!!'ccs24j;*@/g8!>bb) +^];a[rrBh4!!"nRf)TUb!!%NIrrD!Q^]KStI/2RupAP!k5lCZ_U&3FA)uTa:hu3TC +h#RL&b=r!X*Ld!0IfKJ#s.95l!!%M@rrRZM+O9ufbU*/e!0mpq!!Z=#s!7XF-2[]B-2mlE^[qI*g%k[N +-3+"0rW!'`,ldokdJj=+!!'ccs24j;*@/g8!>bb,^]W$Cn+6MX!5JI4!&aZ*!,MN5 +!.XtI!;HgIp4Sf!W^]"3:4S/UQ^HDJq!+Z$.!%%OC#,D4u +,ldpBnc&T2r?_FCr?VGcmJd0krW!'Ik5YHDrVur5rVlkmrVup\o)A]SrVus]4T5<^ +^]-Fq!!/bb.^]DaRq>UH0r;ZgTqptg`r;ZhI +jSo3Fr;Zhkqptfer;ZiTq>UKfj7M..!%,l`!?E2LrrRZM!.t6BrrN0#J"Q`BIfLV: +rr?R+!!';#rr?R.!!C"9UJ^ph!5JO5!%%RD!-J5?"!mpI4S&LQjsB[#!6jm2!'L5\ +"B!BsKdH]u!/:CO!+Z!.!0m'S!'L5\!L.^*!!dW.,ldoks'u$.!2J!B"5a(Y^OlL' +rrF,cb?k8d!;=2/_WU[n!5JI4!&aZ*!,MN5!.X)0!'pJ_!29;A!#tk:!8mPN!:BI8 +!<=Ii9`Z7TRf^OBoDAOk,ldokKfo85!@=N> +rr=AE!!">ErrhI1!!#.Orr>1T!!">6rrM7lo`+tSrVlj[rVurBo)A\9rVuuP^]"36 +4I#gF!`Au^rVuq.df0F,!!'ccs24j;*@/g8!>bb0^]<]orrBh4!!"nRf)TUb!!%N0 +rr>=_!!&_if)Qcg!!(pMrrM`JpY>iM-Hf*a*?CUK!e11MK)_GB!WW4MTDntB!$KYg +!2KJm!B_\-!!#mnrr=A@!!+C"qu6XBrVuq.rr2uBrVup\nG`U7KnX%9!!K(@b_>3J +rr>1R!!">Drr>1\!!(77rrBh5!!ahMs!7XF,piNj!i,e>rVupEdf0F,!!'ccs24j; +*@/g8!>bb1^]<*]rrBh4!!"nRf)TUb!!%N0rr>=_!!&_if)Qcg!!(pLrrDZbh#RL& +b=r!X*Ld!0IfKJ#s.95l!!%M@rrRZM+OU2hU\t/o-1eD?!!&8]rr=AB!!+C"qYpQ> +r;Zi4rr2uBrVup\mJd0?rVurBli-rIquH[A!B_\-!!(7Brr>1\!!'e0rrSsL^]+65 +A,ZH1;?-YYqZ$UBrr3*I!!">-e,KO-!!'ccs24j;*@/g8!>bb2^]DIRr;QeQ+LV7O +5aV6CrrD-Th#RL&b=r!X*Ld!0IfKJ#s.95l!!%M@rrRZM+O^8jbU*5g"=;:ls'u$. +!@>tgrr=AD!!,3Wq#:?f!'L5\!'L5["=4$J-):A;"m2&6s8U=B!!">CrrXPI!%%%4 +"0hh+-0tR2;>pOq4So'X^]"354T>?\g&1mNA,ZE.KdHZt"3gf--2mlHbl@^rqZ$W2 +rr2tPrVupqe,KO-!!'ccs24j;*@/g8!>bb2^]=91rr?H2!!#:_rrN,Vq:u&O-Hf*a +*?FVK!8"@Q!e11MK)_GB!WW4MnG`L?Z2XlT!$Kek!R)kg!!';%rrBh4!!#mqrr@cP +!":0-g&M)rFCrrXPI!%%"3!l'HOm/I+K-2mlEU\Xoi-2mlEg&D!O +A,QB0,s4:9qu?g]s8U=B!!">Drr=AD!!">DrrBh5!!"=orr_-Y!5F-c_uB`X,g0Nq +(BF9H!6kEA!8"@R!8mbT!9a16!<=Ii9`Z7Tnc&Z_+LeKQ!e11MK)_GB!WW4Mo)Acp +0UK'E!e11mec,[4-2dfDU\aujL&CuOA,cK.-2[`D,piHh!l+cZrVupEr;QaZrVurB +ec,VkrVup\q#:>9rVuq?rVlj[p&G)&rr2tPrVupErVlk-r;Zh-r;QaCrVurBeGfX. +!!'ccs24j;*@/g8!>bb3^]<$crr@a!!'5$rrD?[h#RL&b=r!X*V9:5 +T-++NXT&?O!!("1[!!M!Ts3*V"!!d$6s5kU-!'L2Z!)`^q!6j!n!)`^q!2K>h"Qh!1!'L2Z!'L&W +!BdXcrr@cP!!#.[rrBh4!!'e3rr>1\!!%`&rr_-Y!5F-c_uB`X,g0Nq(BF9H!8.8M +!+>a*!2$e$!+>a*!2'5i!:'C9!<=Ii9`Z7Tp&>&b+T;?@E30'@IfKJgrrAhi!!+C1 +K)ap3!WW4MpAY/s0`D%P:pBs$IfLVArrA;_!!&efrr>1\!!(^NrrIg"qu?dE;6g*" +"!mpI;>gFoPl:X_g"$*)ffUQjpAY5i,pg>'rrJlWr?VJAU\k&k^]"35U\t,o49,A' +qu6YMrVuq_eGfX.!!'ccs24j;*@/g8!>bb3^]<$crr?I*!!&YjrrMB.]u9tDr;Zhi +rVll_q:u&O-Hf*a*?FnS!M:M4!!(?HrrRZM!65$=L%bQJ4P>>dk5PJ_!.XeD!O"3T +!!'4,rrRZM+OpDmKfl.'rr_ji-&)3q"PM"QPg'"(!l$j-qYpV,4L)j)!9WSH!i&Vf +qYpSkbk_8?Fa*"/#Vn`Oh'/2#RCS +TDecilM96:!%,l`!?E3VrrJ`7qZ$U5X8`6N!!(%=!/:CP!@9&h!!+C@K)b$6!WW4M +qYpT"0_tbLpTXZ!IfLUCs+^OUhZ*YkK)`ag!?EH/?NCrCq7m!_rVlk*r;Zqls7_Sd +MuY^5!!&YirrD?[h#RL&b=r!X*W,j;T-3q0!'mUb!e11M`r?$mrW!)Fs3-]iqu?`3 +K)b'7!WW4Mr;Qf$0_k\K+KteHIfLUCs+^OUhZ*YkK)`ag!?EH/?NCrCq7m!_rVlk* +r;Znks7!UY!&XWS!2'5i!:'C9!<=Ii9`Z7TrVlnj+SPj9@&s;/IfKJgrr@cP!!(7A +rrJ?1rVupEK)b'7!WW4Mrr3#&0_YPI5d11hIfLUCs+^OUhZ*YkK)`ag!?EH/?NCrC +q7m!_rVlk*r;Znks7!UY!&XWS!2'5i!:'C9!<=Ii9a)OXs8S]6RfLJ.!/:CP!6kB@ +!R)kh!!&8Js8:(@k3`0Lbi\d%!R0^"rrLg+q#:EKbfo2Kr6,0'ir9/^!.Y$P0Ve[O +0W0C#+G0WJrr_-Y!5F-c_uB`X,g0Nq(BF9H!8.8M!+>a*!h]M^\r6VGr;ZhirVll_ +q:u&O-Hf*c*?CapR/l+D!^%c+m/I'>rVurBqu6Y\rVup\qu6]3A,R\S4I#^B!i%k( +qu?aDZ2=P%UJ_":!Ft9irrXPI-/&4r&L@E'Z2aj!,s9l\UHBh&!'Js4rrKAerW!!G +;8;u-!P`.C,lp,mqYpVl4=0n*!@>#2rrW6$="p9I!cn>aK)^T*"5a(Y^OlL'rrF,c +b?k8d!;XD1f_tgM@/U',TE"DlMuY^5!!&YirrD?[h#RL&b=r$Y&eLE1hu<\@rVurB +mJd/`rVurBqYpXD!!#.Zrr@0:!!+CirVlk-p](:VrVloO4So*Z-):J>!2KMn!/:CO +!6kEB#DN3X,ldpB4So*Y;>pLpU\OliA,Q?,FSPn;--Z>f!+Yd(!'Kbb3^]<$crr?I*!!8emn@FPY2#RCSTDecilM96: +!%,l`"pAb1Urr2tnqZ$UB +rVup\rr3#]-2@ND-/&=uL&M&PL&M#OL&M&SL&_0!pAb1>rr2u'pAb3;rr2t?pAb1U +rr2tnqZ$UBrVup\j8T5^!.0bDU&Y9,HN51?s+^OUhZ*YkK)`ag!?EH/?NCrCq7m!_ +rVlk*r;Znks7!UY!&XWS!2'5i!:'C9!<=Ii9a2UYs8VP;&G?)(33.N156(]@rr@cP +!!(71rr>1\!!(7ArrM7lr;Zh>rr2u5r;ZstKnXUprW!&Rs8R3?!!d#Xg&J<'!/:FP +!'L2[![TrTrW!$ts8Psq!!&emrr@cP!!@rTs!@RC"XRY)!!">Err=AE!"*5[b]G-2 +!87DP^\n-8;2'^G-2mlHg&M(orW!15bh<$$,liYZrrrH'J,f8()"mq0.'\7)Qfihu ++G0WJrr_-Y!5F-c_uB`X,g0Nq(BF9H!8.8M!+>a*!h]M^\r6VGr;ZhirVll_q:u&O +-Hf*a*?G+Y!q1UMp](:rX8`6N!!)'Z!-J/crW)mC!-Ic2!'L5\"a#HP@lu(9!!+D; +rr2sqrVuq_rr2tPrW!'Ik5YHkrVuq_rVloOU]18nU\t0"PlLd-,ldokk5RRC!!(7A +rr@cP!!@rTs!@UD$&/EZ49,@-s8RfP!!#mprrUl-^]+65;>pOqPlC[_L&M&T-0G7- +A,ZH.Pl:U_fq[R,!WW4Mrr3&oNu7Wl!'%1^!e11mK)^T*"5a(Y^OlL'rrF,cb?k8d +!;XD1f_tgM@/U',TE"DlMuY^5!!&YirrD?[h#RL&b=r!X*W,jthrs7a5!!#mrk&_pJ!!#mqrrAhm!!,3WqYpOmrVuq? +rVlk>rW!"ps#g8\!6kEA!/:CP",6dT-2mlEPlC[i@fQKks8OAF!%$e&rs7a5!!#mr +k&_pJ!!#mqrrAhm!!,3WhZ!WW!.XqH!r%`mq>^L4YQ"ZR!$HmnLAqA5!!'ccs24j; +*@/g8!>bb3^]<$crr?I*!!8emn@FPY2#RCSTDecilM96:!%,l`!?E3VrrVY=&GuM/ +&GN:+!e11Mj8T*Ap&G(=nc&SOpAb7@A*3ai!2KMn!d%ouqu?^or;Qb,qu?a[U\t,p +,ldokk5G;[bl.SDL&X:7!!(7Arr@cP!!^4bb3^]<$crr?I*!!8emn@FPY2#RCSTDecilM96:!%,l`!?E3TrrVY=&H)S/ +YH7a*IfKK.rr^K!Kk()^"Ja2bL$%q*!'L#V!@>#Jrr@cJ!!,s3qYpS<-2[`K;R +hZ*YkK)`ag!?EH/?NCrCq7m!_rVlk*r;Znks7!UY!&XWS!2'5i!:'C9!<=Ii9`Z7T +p&>3aIh2S[:osZuIfKK+rr@cP!!(71rr>1\!!">B!!+Bfr;QbNqZ$[D;8;l*!p3u= +r;ZpGg&K:q!!#.ZrrC:B!!7lSFT)7?bl.PAL&M&Vbl@\h!!#.VrrY@`!%%@=!/::M +![U^Yp\t +!2oeq!:'C9!<=Ii9`Z7ToD\s^Ih2nSXoAHP!!(pV!/:CP!86c>!'L5\"52@;-2[`D +4PB`6!/:@O![V@=o)A`E-2mlK;?-YB!!">CrrAhn!!8qqL&M&P^]"04L&M&Vbl@\h +!!#.VrrY@`!%%@=!/:@O![V@=o)A`E-2mlE;<.ZX!!%N@rri(W(]`0mrrRZM+Og>k +jsBd&!-IW."!mpI4T59_fd-UuFI)q,Pl:X_Z-rXShZ*YkK)`ag!?EH/?NCrCq7m!Y +rVllDXoJIJrVllYq:u&O-Hf*a*?F\M!q1W:XoAHP!!(pV"0hh+-1(X34T5Qs.fPn!'L,X!l'HBq#:TC,ldoks8ODE!!'e4rrtRc!%$e-Pl:X_L&M#O +L&M&Vbl@\h!!#.Vrr@0?!!&ekrrgR!s8Skn!!#.XrrTrhg%bRMbU!5h-0,",!!%N> +rrVqUO0S]dIfLV?rrC::!!$NsrrXPI!'L5[!/:CP!%!s2!'L5\!)_2E"5a(Y^OlL' +rrF,cb?k8d!;XD2_YsH5!'mag!$M4>!9!\/!<=Ii9`Z7TRfrUJV!k4TGG'4ES@;rs-:b!!">Fs+UFP"=9he +^HDJq"&]*ubl.SG4MT+TKfo>7#0d,I,ldp-q#:?/rVusFPlC[fUHAMVZ2ahMrW!I+ +^]4>rUJV!k4TGG'4ES@;rrg(_!!">*rrN0#J"Q`BIfLV?rrC:B!!IDfbbI0j8JuYh[$Lf +!>+/errD]dh#RL&b=r!X*Ld!0IfKJgrr>1\!!(7?rr?R-!!>@`s+U@Nr[%LC!^-M, +r;cgCr;Zgprr2sEp](=@g&D!O-2%pp!<+;C!!@rTs+U@Nr[%LC +!^-M,r;cgCr;Zgpj8T/\!.UX@!e11me,KElrVuqPrVlk-rVup\n,EJ9!!#.ZrrSrX +A!HupKfk(:rr_-Y!5F-c_uB`X,g0Nq(BF6G!6kB@!S9<=!!3F.fDPXKj7qF2!%,l` +!?E2LrrRZM!65$=4T5<\bkh>>U](5n4T>?\FS>b<--ZDO-27H@-/&:t!P]rV!!&em +rr@07!!\/Ws!7XF4SJdT4SSmW-/&:t!-Ir8"=;:ljsBd&!@?FZrrN0#J"Q`BIfLV? +rrA;_!!%`NrrY@`!%%+6"!mpI4G*Ucrr_-Y!5F-c_uB`X,g0Nq(BF3F!9O+X!T-HH +!!@G[^UM1U!+c$.!I+#0rrDQ_h#RL&b=r!X*Ld!0IfKJgrr]MP!'L&V"0jsNbl.PC +^JQE!!\\fs!7XFFS5Y7 +F=$hb!@gFrKdA%?rr314!!">FUF#m> +!@=N:rrJm:r]C48k3rO!/9h?!/:CP +!6kEA!-J2?!)`^p!JMis!!#.ZrrXPI!'L5["?ZYa-0G.*!'L)X"!u1kA,ZH.Z24J& +,ldokoD\qj!!"5[KdHTr!@a*"/#VnoYoD^LA_)PTDecimI]38!%,l`!?E2LrrRZM!.t6BrrN0#J"Q`B +IfLVXrrC:B!!%`?rr@cP!!LOGs4Lo\!!'e5rr@09!!$O-rrXPI!'L5[!'L5\!6kEA +!'L#V!^-L)rVusFoDJUgL&M&P4S/RQ4SAaYbl8sh!%%RC"sj6L-3+"!p&G1Ws8U=: +!!">DrrXPI!%%XE!'KrT!-J2>!'KuU!'KfO"5a(Y^OlL'rrF,cb?k8d!;+&,kPbD\ +@/U'-TE"r``Rb*Er;ZhirVll_o\BNJ-Hf*a*?CUK!e11MK)_GB!WW4MTDntB!$LY. +!6kEB!/9h?!'L5\!^&Rkqu?_,rr2u'r;ZmF4=0q+!5JO5"!mpI4T59^49,@-rVlkO +rW!9OUWfJq!!#mrjsC!,!+Ys,!%%UE!2K/c!'L/Z![U]@rVuuCg&:sO-2dcI,ldok +s8RfM!!k]^49,@-s8U=?!!4I2A,ZH.bl7VE,ldp-rr2s\qZ$e0UEom?4T>?\4T,6^ +4GAJdrVupEnc&^K!!'ccs24j;*@/g8!>bb.^]Drr=AE!!'e4rrJ@Krr2tPr;Zi4 +rr2tPrVupEo)A\Pr;Zq0oDaOD!!1Fs+U@N"$HV`L&M&Rg&K:o +!!=Oks31HB!0mK_"!mpI4T>?\4T#0cA,lQk!!">Fs-3K_!@>MZrrXPI!%%18"5a(Y +^OlL'rrF,cb?k8d!;+&,kPbD\@(61:TDecilL`m5!%,l`!?E2LrrRZM!.t6BrrN0# +J"Q`BIfLV\rr=A1W!!+C1rVllNrVusFk5G;^,ldokrr3'H!!#.[rrXPI +!%%XE!/:CP!-Ir7!'L5\!)`aq!%%UE!/:"D!'L5\!+Z$."eu%t-0EGN!!#.ZrrsbL +!%%[FL&CuS-0G7-L&M&Rbl>ob!!BM+s31HB",6dTbl.SB4T>?\4T,6[4T>?b49,@- +s8ODE!!'e3rrXPI!%%18"5a(Y^OlL'rrF,cb?k8d!;+&,kPbD\@(61:TDecilL`m5 +!%,l`!?E2LrrRZM!.t6BrrN0#J"Q`BIfLV\rr@06!!'e)rr>1\!<,(]A#&r$!/:CP +!+Ys,"$?P`-3!oH,ldp-rVlsG!!">ErrXPI!%%=: +rVm"S4L+q1rVup\r;QsI!!#.]s+UCO!/:FP!+Z!.!mL\gr;Zgprr2tnrW!%Ss8U=B +!!#.\rr>1[!!'e5rrj\K!%%ZurVup\r;Qo^,ldp-nc&^K!!'ccs24j;*@/g8!>bb. +^]Fs5kU-!)`Cg!)`^q!^-K/rVuqPnc&\R!!">?rrC:B!!#.ZrrsbL!'L;]L&M&Q +-0G4,!'L5\!mL\gr;Zhmrr2tPrW!%Ss8U=B!!#.\rr>1\!!">Drrj\K!%%Z?rVuqP +r;Qc@rVuq.nc&^K!!'ccs24j;*@/g8!>bb.^]1\ +!!(7@rrY@`!%%XE"!mpI4T59a,ldoks8U=B!!%`FrrBh4!!#mq!!">7rrY@`!%%C> +"!mpI4T,3`,ldp-s8P4\!!#.[rr>1\!!:CEL&M&P-2miDL&M&SL&_1srVup\rr2sE +rVuq?rVm$I!!">FL&M&PL&CrNL&M&PL%50FhZ*YkK)`ag!?EH/?NCrCoY:IirVlk* +r;Zqls8V`1f)UR(!!&YirrD?Vh#RL&b=r!X*Ld!0IfKJ#s.95l!!%M@rrRZM+RK+. +bl.SBPjSJQ,ldp-pAY,HrVuqnr;QjF!!">ErrXPI!'L5["sj6L-3+"hrVuqPoD\f# +q>^MLnG`SQ!!">>rrXPI!'L2Z"sj6L4TGFDrVuq.rVlj[rW!#Ds+UFP!%%UD!/:CP +",6dTbl.SB4T>?\-2mlEU](2r,ldoks+UFP!/:@N!'L5\!2K)a"5a(Y^OlL'rrF,c +b?k8d!;+&,kPbD\@/U'-TE"r``Rb*Er;ZhirVll_o\BNJ-Hf*a*?CUK!e11MK)_GB +!WW4MTDntB!$LY."Qh!1!86c>"!mpI4SJdTU](5n;>pLpPl:X_A,cK1,ldp-rVlsG +!!">ErrXPI!'L/Y!TqW'rrM7.qu?^Cn,EJP!!">>rrXPI!%%RC"sj6L4TGFDrVuqP +rVlkOrW!"as+UFP!'L5[!6kEB"&]*ubl.SB4T>?\-2mlEbl.PA4T5<]ft[Ld!+Z!- +!0mE^!6k!5"5a(Y^OlL'rrF,cb?k8d!;+&,kPbD\@/U'-TE"r``Rb*Er;ZhirVll_ +o\BNJ-Hf*a*?CUK!e11MK)_GB!WW4MTDntB!$LV-!p53Om/I/6!!#.Srr=AE!!?`T +b_>uq!5JO5"!mpI4T59^,ldokrr2sqrW!4$g&M*7@jM+;qu6Y+qu?_Nn,EJP!!">> +rr>1\!!J#"b`m5K!!>@`s#g8\!/:CO!/:CP!d+HrrVup\rVllArW!$_s8U=B!!#.\ +rr=AE!!(7Arr>1\!"$F?,ldok^]4=uqu?`@nc&^K!!'ccs24j;*@/g8!>bb.^]P +rr3"/;;M6Rjuh>orrg)64?S>jrrM8(r]C1Fo)Acr4I#aC"MZ89s7?)@!5I7f!WW4M +TDntB!$Kbj"!mpI4SA^SL%bQIA,ZE0,ldp-rVlsG!!">ErrBh3!<+;D!!">BrrM^; +rVusFk3rgFu,ldoks8U=B +!!#.\rr=AE!!(^Nrr@cP!!7lSFSu1?,piEg!86oB"5a(Y^OlL'rrF,cb?k8d!;+&, +kPbD\@/U'-:Odk?`G5H@r;ZhirVll_o\BNJ-Hf*a*?CUK!e11MgA_5L!!*!\"!mpn +^Zb\!o/qa+rrG5.h>[O=!6kB@#GV8F4?NU+oD&=jYpBB44='tio`#$b,liYrrrdEi +s8U=>!!%`,rrN0#J"Q`BIfLV?rrXPI!'KoR!)`Ol!'L2Z"!mpI4T59^,ldokrVlkm +pAb2'qYpOXrVuq.mf*AO!!">>rrM7.pAb:As8QU.!!(7ArrCaO!!5:_U](5nL&CrT +,ldoks8UdO!!#.\rrXPI!%%RC!0mH_",6dT4Sf$[,ldoknG`UJ!!'ccs24j;*@/g8 +!>bb.^]O!@?mrrrZ*u!'KuT!R*\(!!aer!!">Fs-3K_!87;M"XO-K +;?,>K!!&8]rrZ*u!%%XE"&T%EZ2Xb*;#gSBr;QcMrVuq_rr3"@-2dfH;02d<-1Lp: +hZ*YkK)`ag!?EH/?NCrCoY:IirVlk*\,ZN$rVll_o\BNJ-Hf*a*?CUK!e11Mg]%>> +!-J,,pi9b"I&mK +!/:@N#Nd>-s8PqBk1'D4!!%M@rrRZM+Me!\k*1RRPihfA!R06orrM9Eq>UWOKlggh +k4nrVA,ZH.A*s9uk$qoSo`#6NP_Fh8s3*Sf^]+67F?Hi*rrTGfA,cK0PWXZsrr^qO +;;(pJ!87;M"6NHXg&(dNKfk(drs6AnL"ZJg!!">7rr_-Y!5F-c_uB`X,g0Nq(BF*C +!9a=\!+>a*"/#VnoYoD^LA_)PTDecilL`m5!%,l`!?E2LrrRZM!8IMTK`H5lrrTrh +^]"09UHBhbA(ge[&E[Ib,s7t&s'n.k,s7Fl@o<4)"m0;W,s7Fjrs+ccs._\&4I#U? +#0['0^P)[3rVlm\-2dcEK`InErrTrWPl1O^4=0b%"kb23K`Hi)rrJ?1rr3!F-.Dkq +!!%M@rrRZM+Hla*jsC!,!83M7"!mpI4Ri@QhZ*YkK)`ag!?EH/?NCrCoY:IirVlk* +r;Zqls8V`1f)UR(!!&YirrD?Vh#RL&b=r!X*Ld!0IfKK'rr^pS-):26#@d`[4?Oo9 +U]19*YpBB44='u;s'n.k,s7Fl4=1",#GWRF4?Oni4T>?dKdC4T4?OniFSPk?fq\TI +K`K?qrrFDlr;Qi5!/:%E!p1dTp\tCZ4TC*8L&CrO;*=jX"slCH@m"89f`)!Q!.UX@ +!dF\NP5bN9rVupqOoGEVrVuq.nG`U:!!'ccs24j;*@/g8!>bb/^]DaTrVlk*r;Zql +s8V`1f)UR(!!&YirrMiOp"]WK-Hf*a*?CUK!e11MgA_A!!!"<-L!9Go!egVarr38J +,ph^Rs!8u+rr31"!5JQX!/:FP##`L-Hf*a*?CUK!e11Mg&D,g;'l2A!@;7SrrOJm +oDS[nUB$PYUB#E7rs$5#Z2`#JL&V)V4=1%-PQ6F8rrsbqk5U,8Pl:U`493UurrRlS +bl.PB,s;,*!mCX,o`"u&!'L&V#JU7ms8RcQL&M#]bQ->rs-*LG^]4>K,lj^orrN0# +J"Q`C[f?ESPlC`urVupERK!EC,lf5;r]L,Z!'K`M".oPnkCW`OrrF,cb?k8d!;F80 +b5M5;!+>a*"/#VnoYoD^LA_)PTDSWhrSdM,!<=Ii9`Z7TRfsL%bQJ--YiX!dF\FK)`^f!?EH/?NCrCpV6e%r;QiULEZTr +""6E"4iK8Y,5hKC18!b-rrMuQptYrN-Hf*a*?CUK!e11Me,KU649/mkbkM/@4T@MD +bk_8?bQ*@rrrkM2s8P2-qu6kS!/:H,!6kEA!egWup&>)I!6kEA!@9l+rrUCEFS>_9 +;#i`QrrQ[Vbl7VDK`Hi*rrG5ZpAY.>-//A#!!%M@rr_]i!+;&k!+Z!.!83e?!SJdp +!!,48mf*>:!%RbQ'd%bQQW!;#ni9rrUCEL&V)V4=1%-4=0.frs"/WU]6#J +bl.PCK`K?irrRlSbl.PB,piKh!i#aLq#:HY49/mbrrFDGr$;RJ,pe9Fjs?errrFDl +gA_3S!.UU?"$chtpQY[Z;'g=MrrJm:r]C6ZL"Ykn"5a(YG_5t4rrF,cb?k8d!;O>0 +oDS[hVm$.$TDeciqY8kI!%,l`!?E2LrrRZM!8IMT,ph^Mrrj\ps8OAkqu6iQs8RcQ +U\t,q;3_+)!/:FP#!=43s'l&Dr;Qsu!6kIs!6kEA!egWup&>)I!6kEA!^%dkrVlq@ +!5J@0"7mf=FS5Y6;>`N^,lf5RPlIL)k5PA^@m&oOrrFDlgA_3S!.UU?".&uf[t=X: +rr\#V!5F-c_Z'WW,g0Nq(BF9H!6G-=!V[G8!!*AorVllWq:u&O-Hf*a*?CUK!e11M +g]%@c!'KlNrs+5XA,lQk!5JL4#)*%es1\P2rVm(s!-J7b!/:FP#!=43s.]R(rVm,b +,piTkK`K?qrrRlSbk:u;K`K?qrrSDbL&M#P,pi?d!^$IXmf*?B!/:FP!Fn7jrrQ[1 +L&M#QPQ54IrrN0#J"HZBk5YKYK)^`."8=JL(kVe(rrF,cb?k8d!;XD1f)>UKVlg"" +\,H=,kPL4nK`Hi+rrFEfrVm2d,lj20s-*L0k1]h:!!%M> +rr[3?!7-8sMuNm?!!&(3s2"^9*@/g8!>bb3^]<$crr?I*!!8Men@FPY2#RCSTDeci +lM96:!%,l`!?E2LrrRZM!87AQ;'l,?!E%PKrs,;F!$rok--Z>f##P@H,lf78rr30b +!!%-@4=0t+##P@H,lf6Urr3%R!6kEA!egWup&>)I!6kB@#0]10,p`P$rVm%T!/:IQ +4S\sW-3!oF,piBe#DE/3s8UaPbl%JG^Eik+,lg'Og&D*R!.UR>"6Tpi:kJ_+rri'5 +!#YH^s2"^9*@/g8!>bb3^]<$crr?I*!!8emn@FPY2#RCSTDecilM96:!%,l`!?E2L +rrRZM!8.;Tk+dWaPhGm4"2BPD^\[s4fnG-Tqu6i7PhH)ibl%JCfnG-Tr;Qfhbl%JA +o??k,!V=P2rr]$ML"ZD("nTt0s8UdIbl7VCbfon_#4p(1s8Tifq>UQ3Kn[:nrrN0# +J"6N@Du]m!K)^i1"(2*/YCceirrF,cb?k8d!;XD1f_tgM@/U',TE"DlMuY^5!!&Yi +rrD?[h#RL&b=r!X*Ld!0IfKJ#s.95l!!%M=rrhL-!!'K[s,[0^NrT/FK)`Uc!?EH/ +?NCrCq7m!_rVlk*r;Znks7!UY!&XWS!2'5i!:'C9!<=Ii9`Z7TRfR&C5t.OoGQf!!"/1K)`Uc!?EH/?NCrCq7m!_rVlk*r;Znks7!UY!&XWS +!2'5i!:'C9!<=Ii9`Z7TRfa*!h]M^ +\r6VGr;ZhirVll_q:u&O-Hf*a*?CUK!e11MK)_GB!WW4MR/[?)&-)\IT7[*3rs&4I +&-)\Yf7O%8rrF,cb?k8d!;XD1f_tgM@/U',TE"DlMuY^5!!&YirrD?[h#RL&b=r!X +*Ld!0IfKJ#s.95l!!%M8rrM"*rW!!BE6j.9TDnu%BGg^K!D)[2s1A:3*@/g8!>bb3 +^]<$crr?I*!!8emn@FPY2#RCSTDecilM96:!%,l`!?E2LrrRZM!.t6BrrN0#J!L$7 +T-4(4"!D!$ItGG6^BBUIIo$^T!!+dgK)`C]!?EH/?NCrCq7m!_rVlk*r;Znks7!UY +!&XWS!2'5i!:'C9!<=Ii9`Z7TRfbb3^]<$crr?I*!!8emn@FPY2#RCSTDecilM96:!%,l`!?E2LrrRZM!.t6B +rrN0#J!'a5f7-%FJcMSH":.7`Qf!Dp[Jp7J,g0Nq(BF9H!8.8M!+>a*!h]M^\r6VG +r;ZhirVll_q:u&O-Hf*a*?CUK!e11MK)_GB!WW4MK)^H&K)^H&h>[Kr,g0Nq(BF9H +!8.8M!+>a*"/#VnV7VZd2#RCSTDecilM96:!%,l`!?E2LrrRZM!.t6BrrN0#ItI]P +s+:9&s5!\U*@/g8!>bb3^]<$crr?I*!!Jqos81$QW;o0]!!&YirrD?[h#RL&b=r!X +*Ld!0IfKJ#s.95l!!%M#s+:9&s+::,rrF,cb?k8d!;XD1f_tgM@/U'*T=Fn$@/U'* +TDecilM96:!%,l`!?E2LrrRZM!.t6BrrN0#ItI]Ps+:9&s5!\U*@/g8!>bb3^]<$c +rr?I*!!&(irr?I*!!&YirrD?[h#RL&b=r!X*Ld!0IfKJ#s.95l!!%M#s+:9&s+::, +rrF,cb?k8d!;XD1f)>UKVlg""\,H=,l1s-9!%,l`!?E2LrrRZM!.o]lIf]TMItI]P +s+:9&s5!\U*@/g8!>bb3^];ISrrMj2YQ+\0n,<7djS@U4!%,l`!?E2Lrr@h+!1Elf +ItI]Ps+:9&s5!\U*@/g8!>bb2^]=!)rrA[q!!&YirrDulh#RL&b=r!X*Ld!/f,0)> +S,`R,c[u1Ks+:9&s5!\U*@/g8!>bb2^];m^rrJ/dZiC+4L]%/PnG(f?!%,l`!?E24 +s+:9&s+:9&s+:90rrF,cb?k8d!;F8/p&+gkhg\2,5QXKKkPY>\r87;*!<=Ii9`Z7T +K)^H&K)^H&K)^H&N;io!,g0Nq(BF3F!QtA@rrN,^pY>iM-Hf*a*?Bb3K)^H&K)^H& +K)^f0!?EH/?NCrCp:p[\X8`5"kP!^4!%,l`!?E24s+:9&s+:9&s+:90rrF,cb?k8d +!;4,.deBpE!Vk[Ih#RL&b=r!X*J4bb.^]MC0pTjf" +p?;,(!<=Ii9`Z7TK)^H&K)^H&K)^H&N;io!,g0Nq(BF!@!QrpJhu^uM^>A8Zl/pjm +h#RL&b=r!X*J4baZ^]KStI*:=H!%,l`!?E24s+:9& +s+:9&s+:90rrF,cb?k8d!6`.ZO8s[Oh#RL&b=r!X*J4baZ^]KStI*:=H!%,l`!?E24s+:9&s+:9&s+:90rrF,cb?k8d!6`.ZO8s[Oh#RL& +b=r!X*J4baZ^]KStI*:=H!%,l`!?E24s+:9&s+:9& +s+:90rrF,cb?k8d!6`.ZO8s[Oh#RL&b=r!X*J4baZ +^]KStI*:=H!%,l`!?E24s+:9&s+:9&s+:90rrF,cb?k8d!6`.ZO8s[Oh#RL&b=r!X +*J4baZ^]KStI*:=H!%,l`!?E24s+:9&s+:9&s+:90 +rrF,cb?k8d!6`.ZO8s[Oh#RL&b=r!X*J4baZ^]KSt +I*:=H!%,l`!?E24s+:9&s+:9&s+:90rrF,cb?k8d!6`.ZO8s[Oh#RL&b=r!X*J4baZ^]KStI*:=H!%,l`!?E24s+:9&s+:9&s+:90rrF,c +b?k8d!6`.ZO8s[Oh#RL&b=r!X*J4baZ^]KStI*:=H +!%,l`!?E24s+:9&s+:9&s+:90rr=Bt!1s5k*eOEDs+:9&s+:9&s,?sXYKD=qDbnQ+ +!ddFabC9OkB?G](YCce+s+:9&s+:9Grr +~> +grestore +currentdict /inputf undef +currentdict /pstr undef diff --git a/docs/src/user.tex b/docs/src/user.tex index 19c6c3851a..923b3ae7da 100644 --- a/docs/src/user.tex +++ b/docs/src/user.tex @@ -2060,6 +2060,988 @@ iptables: iptables -A INPUT -p tcp -{}-destination-port 8002 -j REJECT \end{verbatim} +%% Chapter Xen Mandatory Access Control Framework +\chapter{sHype/Xen Access Control} + +The Xen mandatory access control framework is an implementation of the +sHype Hypervisor Security Architecture +(www.research.ibm.com/ssd\_shype). It permits or denies communication +and resource access of domains based on a security policy. The +mandatory access controls are enforced in addition to the Xen core +controls, such as memory protection. They are designed to remain +transparent during normal operation of domains (policy-conform +behavior) but to intervene when domains move outside their intended +sharing behavior. This chapter will describe how the sHype access +controls in Xen can be configured to prevent viruses from spilling +over from one into another workload type and secrets from leaking from +one workload type to another. sHype/Xen depends on the correct +behavior of Domain0 (cf previous chapter). + +Benefits of configuring sHype/ACM in Xen include: +\begin{itemize} +\item robust workload and resource protection effective against rogue + user domains +\item simple, platform- and operating system-independent security + policies (ideal for heterogeneous distributed environments) +\item safety net with minimal performance overhead in case operating + system security is missing, does not scale, or fails +\end{itemize} + +These benefits are very valuable because today's operating systems +become increasingly complex and often have no or insufficient +mandatory access controls. (Discretionary access controls, supported +by of most operating systems, are not effective against viruses or +misbehaving programs.) Where mandatory access control exists (e.g., +SELinux), they usually deploy complex and difficult to understand +security policies. Additionally, multi-tier applications in business +environments usually require different types of operating systems +(e.g., AIX, Windows, Linux) which cannot be configured with compatible +security policies. Related distributed transactions and workloads +cannot be easily protected on the OS level. The Xen access control +framework steps in to offer a coarse-grained but very robust security +layer and safety net in case operating system security fails or is +missing. + +To control sharing between domains, Xen mediates all inter-domain +communication (shared memory, events) as well as the access of domains +to resources such as disks. Thus, Xen can confine distributed +workloads (domain payloads) by permitting sharing among domains +running the same type of workload and denying sharing between pairs of +domains that run different workload types. We assume that--from a Xen +perspective--only one workload type is running per user domain. To +enable Xen to associate domains and resources with workload types, +security labels including the workload types are attached to domains +and resources. These labels and the hypervisor sHype controls cannot +be manipulated or bypassed and are effective even against rogue +domains. + +\section{Overview} +This section gives an overview of how workloads can be protected using +the sHype mandatory access control framework in Xen. +Figure~\ref{fig:acmoverview} shows the necessary steps in activating +the Xen workload protection. These steps are described in detail in +Section~\ref{section:acmexample}. + +\begin{figure} +\centering +\includegraphics[width=13cm]{figs/acm_overview.eps} +\caption{Overview of activating sHype workload protection in Xen. + Section numbers point to representative examples.} +\label{fig:acmoverview} +\end{figure} + +First, the sHype/ACM access control must be enabled in the Xen +distribution and the distribution must be built and installed (cf +Subsection~\ref{subsection:acmexampleconfigure}). Before we can +enforce security, a Xen security policy must be created (cf +Subsection~\ref{subsection:acmexamplecreate}) and deployed (cf +Subsection~\ref{subsection:acmexampleinstall}). This policy defines +the workload types differentiated during access control. It also +defines the rules that compare workload types of domains and resources +to provide access decisions. Workload types are represented by +security labels that can be attached to domains and resources (cf +Subsections~\ref{subsection:acmexamplelabeldomains} +and~\ref{subsection:acmexamplelabelresources}). The functioning of +the active sHype/Xen workload protection is demonstrated using simple +resource assignment, and domain creation tests in +Subsection~\ref{subsection:acmexampletest}. +Section~\ref{section:acmpolicy} describes the syntax and semantics of +the sHype/Xen security policy in detail and introduces briefly the +tools that are available to help create valid security policies. + +The next section describes all the necessary steps to create, deploy, +and test a simple workload protection policy. It is meant to enable +anybody to quickly try out the sHype/Xen workload protection. Those +readers who are interested in learning more about how the sHype access +control in Xen works and how it is configured using the XML security +policy should read Section~\ref{section:acmpolicy} as well. +Section~\ref{section:acmlimitations} concludes this chapter with +current limitations of the sHype implementation for Xen. + +\section{Xen Workload Protection Step-by-Step} +\label{section:acmexample} + +What you are about to do consists of the following sequence: +\begin{itemize} +\item configure and install sHype/Xen +\item create a simple workload protection security policy +\item deploy the sHype/Xen security policy +\item associate domains and resources with workload labels, +\item test the workload protection +\end{itemize} +The essential commands to create and deploy a sHype/Xen security +policy are numbered throughout the following sections. If you want a +quick-guide or return at a later time to go quickly through this +demonstration, simply look for the numbered commands and apply them in +order. + +\subsection{Configuring/Building sHype Support into Xen} +\label{subsection:acmexampleconfigure} +First, we need to configure the access control module in Xen and +install the ACM-enabled Xen hypervisor. This step installs security +tools and compiles sHype/ACM controls into the Xen hypervisor. + +To enable sHype/ACM in Xen, please edit the Config.mk file in the top +Xen directory. + +\begin{verbatim} + (1) In Config.mk + Change: ACM_SECURITY ?= n + To: ACM_SECURITY ?= y +\end{verbatim} + +Then install the security-enabled Xen environment as follows: + +\begin{verbatim} + (2) # make world + # make install +\end{verbatim} + +\subsection{Creating A WLP Policy in 3 Simple Steps with ezPolicy} +\label{subsection:acmexamplecreate} + +We will use the ezPolicy tool to quickly create a policy that protects +workloads. You will need both the Python and wxPython packages to run +this tool. To run the tool in Domain0, you can download the wxPython +package from www.wxpython.org or use the command +\verb|yum install wxPython| in Redhat/Fedora. To run the tool on MS +Windows, you also need to download the Python package from +www.python.org. After these packages are installed, start the ezPolicy +tool with the following command: + +\begin{verbatim} + (3) # xensec_ezpolicy +\end{verbatim} + +Figure~\ref{fig:acmezpolicy} shows a screen-shot of the tool. The +following steps show you how to create the policy shown in +Figure~\ref{fig:acmezpolicy}. You can use \verb|-h| to pop up a +help window at any time. The indicators (a), (b), and (c) in +Figure~\ref{fig:acmezpolicy} show the buttons that are used during the +3 steps of creating a policy: +\begin{enumerate} +\item defining workloads +\item defining run-time conflicts +\item translating the workload definition into a sHype/Xen access + control policy +\end{enumerate} + +\paragraph{Defining workloads.} Workloads are defined for each +organization and department that you enter in the left panel. Please +use the ``New Org'' button (a) to create the organizations ``Avis'', +``Hertz'', ``CocaCola'', and ``PepsiCo''. + +You can refine an organization to differentiate between multiple +department workloads by right-clicking the organization and selecting +\verb|Add Department| (or selecting an organization and pressing +\verb|-a|). Create department workloads ``Intranet'', +``Extranet'', ``HumanResources'', and ``Payroll'' for the ``CocaCola'' +organization and department workloads ``Intranet'' and ``Extranet'' +for the ``PepsiCo'' organization. The resulting layout of the tool +should be similar to the left panel shown in +Figure~\ref{fig:acmezpolicy}. + +\paragraph{Defining run-time conflicts.} Workloads that shall be +prohibited from running concurrently on the same hypervisor platform +are grouped into ``Run-time Exclusion rules'' on the right panel of +the window. + +To prevent PepsiCo and CocaCola workloads (including their +departmental workloads) from running simultaneously on the same +hypervisor system, select the organization ``PepsiCo'' and, while +pressing the \verb||-key, select the organization ``CocaCola''. +Now press the button (b) named ``Create run-time exclusion rule from +selection''. A popup window will ask for the name for this run-time +exclusion rule (enter a name or just hit \verb||). A rule will +appear on the right panel. The name is used as reference only and does +not affect the hypervisor policy. + +Repeat the process to create a run-time exclusion rule just for the +department workloads CocaCola.Extranet and CocaCola.Payroll. + +\begin{figure}[htb] +\centering +\includegraphics[width=13cm]{figs/acm_ezpolicy.eps} +\caption{Final layout including workload definition and Run-time Exclusion rules.} +\label{fig:acmezpolicy} +\end{figure} + +The resulting layout of your window should be similar to +Figure~\ref{fig:acmezpolicy}. Save this workload definition by +selecting ``Save Workload Definition as ...'' in the ``File'' menu +(c). This workload definition can be later refined if required. + +\paragraph{Translating the workload definition into a sHype/Xen access + control policy.} To translate the workload definition into a access +control policy understood by Xen, please select the ``Save as Xen ACM +Security Policy'' in the ``File'' menu (c). Enter the following policy +name in the popup window: \verb|example.chwall_ste.test-wld|. If you +are running ezPolicy in Domain0, the resulting policy file +test-wld\_security-policy.xml will automatically be placed into the +right directory (/etc/xen/acm-security/ policies/example/chwall\_ste). +If you run the tool on another system, then you need to copy the +resulting policy file into Domain0 before continuing. See +Section~\ref{subsection:acmnaming} for naming conventions of security +policies. + +\subsection{Deploying a WLP Policy} +\label{subsection:acmexampleinstall} +To deploy the workload protection policy we created in +Section~\ref{subsection:acmexamplecreate}, we create a policy +representation (test-wld.bin) that can be loaded into the Xen +hypervisor and we configure Xen to actually load this policy at +startup time. + +The following command translates the source policy representation +into a format that can be loaded into Xen with sHype/ACM support. +Refer to the \verb|xm| man page for further details: + +\begin{verbatim} + (4) # xm makepolicy example.chwall_ste.test-wld +\end{verbatim} + +The easiest way to install a security policy for Xen is to include the +policy in the boot sequence. The following command does just this: + +\begin{verbatim} + (5) # xm cfgbootpolicy example.chwall_ste.test-wld +\end{verbatim} + +\textit{Alternatively, if this command fails} (e.g., because it cannot +identify the Xen boot entry), you can manually install the policy in 2 +steps. First, manually copy the policy binary file into the boot +directory: + +\begin{scriptsize} +\begin{verbatim} + # cp /etc/xen/acm-security/policies/example/chwall_ste/test-wld.bin \ + /boot/example.chwall_ste.test-wld.bin +\end{verbatim} +\end{scriptsize} + +Second, manually add a module line to your Xen boot entry so that grub +loads this policy file during startup: + +\begin{scriptsize} +\begin{verbatim} + title Xen (2.6.16.13) + root (hd0,0) + kernel /xen.gz dom0_mem=2000000 console=vga + module /vmlinuz-2.6.16.13-xen ro root=/dev/hda3 + module /initrd-2.6.16.13-xen.img + module /example.chwall_ste.test-wld.bin +\end{verbatim} +\end{scriptsize} + +Now reboot into this Xen boot entry to activate the policy and the +security-enabled Xen hypervisor. + +\begin{verbatim} + (6) # reboot +\end{verbatim} + +After reboot, check if security is enabled: + +\begin{scriptsize} +\begin{verbatim} + # xm list --label + Name ID Mem(MiB) VCPUs State Time(s) Label + Domain-0 0 1949 4 r----- 163.9 SystemManagement +\end{verbatim} +\end{scriptsize} + +If the security label at the end of the line says ``INACTIV'' then the +security is not enabled. Verify the previous steps. Note: Domain0 is +assigned a default label (see \verb|bootstrap| policy attribute +explained in Section~\ref{section:acmpolicy}). All other domains must +be labeled in order to start on this sHype/ACM-enabled Xen hypervisor +(see following sections for labeling domains and resources). + +\subsection{Labeling Domains} +\label{subsection:acmexamplelabeldomains} +You should have a Xen domain configuration file that looks like the +following (Note: www.jailtime.org or www.xen-get.org might be good +places to look for example domU images). The following configuration +file defines \verb|domain1|: + +\begin{scriptsize} +\begin{verbatim} + # cat domain1.xm + kernel = "/boot/vmlinuz-2.6.16.13-xen" + memory = 128 + name = "domain1" + vif = [ '' ] + dhcp = "dhcp" + disk = ['file:/home/xen/dom_fc5/fedora.fc5.img,sda1,w', \ + 'file:/home/xen/dom_fc5/fedora.swap,sda2,w'] + root = "/dev/sda1 ro" +\end{verbatim} +\end{scriptsize} + +If you try to start domain1, you will get the following error: + +\begin{scriptsize} +\begin{verbatim} + # xm create domain1.xm + Using config file "domain1.xm". + domain1: DENIED + --> Domain not labeled + Checking resources: (skipped) + Security configuration prevents domain from starting +\end{verbatim} +\end{scriptsize} + +Every domain must be associated with a security label before it can +start on sHype/Xen. Otherwise, sHype/Xen would not be able to enforce +the policy consistently. The following command prints all domain +labels available in the active policy: + +\begin{scriptsize} +\begin{verbatim} + # xm labels type=dom + Avis + CocaCola + CocaCola.Extranet + CocaCola.HumanResources + CocaCola.Intranet + CocaCola.Payroll + Hertz + PepsiCo + PepsiCo.Extranet + PepsiCo.Intranet + SystemManagement +\end{verbatim} +\end{scriptsize} + +Now label domain1 with the CocaCola label and another domain2 with the +PepsiCo.Extranet label. Please refer to the xm man page for further +information. + +\begin{verbatim} + (7) # xm addlabel CocaCola dom domain1.xm + # xm addlabel PepsiCo.Extranet dom domain2.xm +\end{verbatim} + +Let us try to start the domain again: + +\begin{scriptsize} +\begin{verbatim} + # xm create domain1.xm + Using config file "domain1.xm". + file:/home/xen/dom_fc5/fedora.fc5.img: DENIED + --> res:__NULL_LABEL__ (NULL) + --> dom:CocaCola (example.chwall_ste.test-wld) + file:/home/xen/dom_fc5/fedora.swap: DENIED + --> res:__NULL_LABEL__ (NULL) + --> dom:CocaCola (example.chwall_ste.test-wld) + Security configuration prevents domain from starting +\end{verbatim} +\end{scriptsize} + +This error indicates that domain1, if started, would not be able to +access its image and swap files because they are not labeled. This +makes sense because to confine workloads, access of domains to +resources must be controlled. Otherwise, domains that are not allowed +to communicate or run simultaneously could share data through storage +resources. + +\subsection{Labeling Resources} +\label{subsection:acmexamplelabelresources} +You can use the \verb|xm labels type=res| command to list available +resource labels. Let us assign the CocaCola resource label to the domain1 +image file representing \verb|/dev/sda1| and to its swap file: + +\begin{verbatim} + (8) # xm addlabel CocaCola res \ + file:/home/xen/dom_fc5/fedora.fc5.img + Resource file not found, creating new file at: + /etc/xen/acm-security/policies/resource_labels + # xm addlabel CocaCola res \ + file:/home/xen/dom_fc5/fedora.swap +\end{verbatim} + +Starting \verb|domain1| now will succeed: + +\begin{scriptsize} +\begin{verbatim} + # xm create domain1.xm + # xm list --label + Name ID Mem(MiB) VCPUs State Time(s) Label + domain1 1 128 1 r----- 2.8 CocaCola + Domain-0 0 1949 4 r----- 387.7 SystemManagement +\end{verbatim} +\end{scriptsize} + +The following command lists all labeled resources on the +system, e.g., to lookup or verify the labeling: + +\begin{scriptsize} +\begin{verbatim} + # xm resources + file:/home/xen/dom_fc5/fedora.swap + policy: example.chwall_ste.test-wld + label: CocaCola + file:/home/xen/dom_fc5/fedora.fc5.img + policy: example.chwall_ste.test-wld + label: CocaCola +\end{verbatim} +\end{scriptsize} + +Currently, if a labeled resource is moved to another location, the +label must first be manually removed, and after the move re-attached +using the xm commands \verb|xm rmlabel| and \verb|xm addlabel| +respectively. Please see Section~\ref{section:acmlimitations} for +further details. + +\begin{verbatim} + (9) Label the resources of domain2 as PepsiCo.Extranet + Do not try to start this domain yet +\end{verbatim} + +\subsection{Testing The Xen Workload Protection} +\label{subsection:acmexampletest} +We are about to demonstrate how the workload protection works by +verifying: +\begin{itemize} +\item that domains with conflicting workloads cannot run + simultaneously +\item that domains cannot access resources of other workloads +\item that domains cannot exchange network packets if they are not + associated with the same workload type +\end{itemize} + +\paragraph{Test 1: Run-time exclusion rules.} We assume that domain1 +with the CocaCola label is still running. While domain1 is running, +the run-time exclusion set of our policy says that domain2 cannot +start because the label of domain1 includes the CHWALL type CocaCola +and the label of domain2 includes the CHWALL type PepsiCo. The +run-time exclusion rule of our policy enforces that PepsiCo and +CocaCola cannot run at the same time on the same hypervisor platform. +Once domain1 is stopped or saved, domain2 can start but domain1 can no +longer start or be resumed. The ezPolicy tool, when creating the +Chinese Wall types for the workload labels, ensures that department +workloads inherit the organization type (and with it any organization +exclusions). + +\begin{scriptsize} +\begin{verbatim} +# xm list --label +Name ID Mem(MiB) VCPUs State Time(s) Label +domain1 2 128 1 -b---- 6.9 CocaCola +Domain-0 0 1949 4 r----- 273.1 SystemManagement + +# xm create domain2.xm +Using config file "domain2.xm". +Error: (1, 'Operation not permitted') + +# xm destroy domain1 +# xm create domain2.xm +Using config file "domain2.xm". +Started domain domain2 + +# xm list --label +Name ID Mem(MiB) VCPUs State Time(s) Label +domain2 4 164 1 r----- 4.3 PepsiCo.Extranet +Domain-0 0 1949 4 r----- 298.4 SystemManagement + +# xm create domain1.xm +Using config file "domain1.xm". +Error: (1, 'Operation not permitted') + +# xm destroy domain2 +# xm list +Name ID Mem(MiB) VCPUs State Time(s) +Domain-0 0 1949 4 r----- 391.2 +\end{verbatim} +\end{scriptsize} + +You can verify that domains with Avis label can run together with +domains labeled CocaCola, PepsiCo, or Hertz. + +\paragraph{Test2: Resource access.} In this test, we will re-label the +swap file for domain1 with the Avis resource label. We expect that +Domain1 will no longer start because it cannot access this resource. +This test checks the sharing abilities of domains, which are defined +by the Simple Type Enforcement Policy component. + +\begin{scriptsize} +\begin{verbatim} +# xm rmlabel res file:/home/xen/dom_fc5/fedora.swap +# xm addlabel Avis res file:/home/xen/dom_fc5/fedora.swap +# xm resources +file:/home/xen/dom_fc5/fedora.swap + policy: example.chwall_ste.test-wld + label: Avis +file:/home/xen/dom_fc5/fedora.fc5.img + policy: example.chwall_ste.test-wld + label: CocaCola + +# xm create domain1.xm +Using config file "domain1.xm". + file:/home/xen/dom_fc4/fedora.swap: DENIED + --> res:Avis (example.chwall_ste.test-wld) + --> dom:CocaCola (example.chwall_ste.test-wld) +Security configuration prevents domain from starting +\end{verbatim} +\end{scriptsize} + +\paragraph{Test 3: Communication.} In this test we would verify that +two domains with labels Hertz and Avis cannot exchange network packets +by using the 'ping' connectivity test. It is also related to the STE +policy.{\bf Note:} sHype/Xen does control direct communication between +domains. However, domains associated with different workloads can +currently still communicate through the Domain0 virtual network. We +are working on the sHype/ACM controls for local and remote network +traffic through Domain0. Please monitor the xen-devel mailing list +for updated information. + +\section{Xen Access Control Policy} +\label{section:acmpolicy} + +This section describes the sHype/Xen access control policy in detail. +It gives enough information to enable the reader to write custom +access control policies and to use the available Xen policy tools. The +policy language is expressive enough to specify most symmetric access +relationships between domains and resources efficiently. + +The Xen access control policy consists of two policy components. The +first component, called Chinese Wall (CHWALL) policy, controls which +domains can run simultaneously on the same virtualized platform. The +second component, called Simple Type Enforcement (STE) policy, +controls the sharing between running domains, i.e., communication or +access to shared resources. The CHWALL and STE policy components can +be configured to run alone, however in our examples we will assume +that both policy components are configured together since they +complement each other. The XML policy file includes all information +needed by Xen to enforce the policies. + +Figures~\ref{fig:acmxmlfilea} and \ref{fig:acmxmlfileb} show a fully +functional but very simple example policy for Xen. The policy can +distinguish two workload types \verb|CocaCola| and \verb|PepsiCo| and +defines the labels necessary to associate domains and resources with +one of these workload types. The XML Policy consists of four parts: +\begin{enumerate} +\item policy header including the policy name +\item Simple Type Enforcement block +\item Chinese Wall Policy block +\item label definition block +\end{enumerate} + +\begin{figure} +\begin{scriptsize} +\begin{verbatim} +01 +02 +03 +04 +05 example.chwall_ste.test +06 Wed Jul 12 17:32:59 2006 +07 +08 +09 +10 +11 SystemManagement +12 PepsiCo +13 CocaCola +14 +15 +16 +17 +18 +19 SystemManagement +20 PepsiCo +21 CocaCola +22 +23 +24 +25 +26 CocaCola +27 PepsiCo +28 +29 +30 +31 +\end{verbatim} +\end{scriptsize} +\caption{Example XML security policy file -- Part I: Types and Rules Definition.} +\label{fig:acmxmlfilea} +\end{figure} + +\subsection{Policy Header and Policy Name} +\label{subsection:acmnaming} +Lines 1-2 (cf Figure~\ref{fig:acmxmlfilea}) include the usual XML +header. The security policy definition starts in Line 3 and refers to +the policy schema. The XML-Schema definition for the Xen policy can be +found in the file +\textit{/etc/xen/acm-security/policies/security-policy.xsd}. Examples +for security policies can be found in the example subdirectory. The +acm-security directory is only installed if ACM security is configured +during installation (cf Section~\ref{subsection:acmexampleconfigure}). + +The \verb|Policy Header| spans lines 4-7. It includes a date field and +defines the policy name \verb|example.chwall_ste.test|. It can also +include optional fields that are not shown and are for future use (see +schema definition). + +The policy name serves two purposes: First, it provides a unique name +for the security policy. This name is also exported by the Xen +hypervisor to the Xen management tools in order to ensure that both +enforce the same policy. We plan to extend the policy name with a +digital fingerprint of the policy contents to better protect this +correlation. Second, it implicitly points the xm tools to the +location where the XML policy file is stored on the Xen system. +Replacing the colons in the policy name by slashes yields the local +path to the policy file starting from the global policy directory +\verb|/etc/xen/acm-security/policies|. The last part of the policy +name is the prefix for the XML policy file name, completed by +\verb|-security_policy.xml|. Consequently, the policy with the name +\verb|example.chwall_ste.test| can be found in the XML policy file +named \verb|test-security_policy.xml| that is stored in the local +directory \verb|example/chwall_ste| under the global policy directory. + +\subsection{Simple Type Enforcement Policy Component} + +The Simple Type Enforcement (STE) policy controls which domains can +communicate or share resources. This way, Xen can enforce confinement +of workload types by confining the domains running those workload +types. The mandatory access control framework enforces its policy when +domains access intended ways of communication or cooperation (shared +memory, events, shared resources such as block devices). It builds on +top of the core hypervisor isolation, which restricts the ways of +inter-communication to those intended means. STE does not protect or +intend to protect from covert channels in the hypervisor or hardware; +this is an orthogonal problem that can be mitigated by using the +Run-time Exclusion rules described above or by fixing the problem in +the core hypervisor. + +Xen controls sharing between domains on the resource and domain level +because this is the abstraction the hypervisor and its management +understand naturally. While this is coarse-grained, it is also very +reliable and robust and it requires minimal changes to implement +mandatory access controls in the hypervisor. It enables platform- and +operation system-independent policies as part of a layered security +approach. + +Lines 9-15 (cf Figure~\ref{fig:acmxmlfilea}) define the Simple Type +Enforcement policy component. Essentially, they define the workload +type names \verb|SystemManagement|, \verb|PepsiCo|, and +\verb|CocaCola| that are available in the STE policy component. The +policy rules are implicit: Xen permits a domain to communicate with +another domain if and only if the labels of the domains share an +common STE type. Xen permits a domain to access a resource if and +only if the labels of the domain and the resource share a common STE +workload type. + +\subsection{Chinese Wall Policy Component} + +The Chinese Wall security policy interpretation of sHype enables users +to prevent certain workloads from running simultaneously on the same +hypervisor platform. Run-time Exclusion rules (RER), also called +Conflict Sets, define a set of workload types that are not permitted +to run simultaneously. Of all the workloads specified in a Run-time +Exclusion rule, at most one type can run on the same hypervisor +platform at a time. Run-time Exclusion Rules implement a less +rigorous variant of the original Chinese Wall security component. They +do not implement the *-property of the policy, which would require to +restrict also types that are not part of an exclusion rule once they +are running together with a type in an exclusion rule (please refer to +http://www.gammassl.co.uk/topics/chinesewall.html for more information +on the original Chinese Wall policy). + +Xen considers the \verb|ChineseWallTypes| part of the label for the +enforcement of the Run-time Exclusion rules. It is illegal to define +labels including conflicting Chinese Wall types. + +Lines 17-30 (cf Figure~\ref{fig:acmxmlfilea}) define the Chinese Wall +policy component. Lines 17-22 define the known Chinese Wall types, +which coincide here with the STE types defined above. This usually +holds if the criteria for sharing among domains and sharing of the +hardware platform are the same. Lines 24-29 define one Run-time +Exclusion rule: + +\begin{scriptsize} +\begin{verbatim} + + CocaCola + PepsiCo + +\end{verbatim} +\end{scriptsize} + +Based on this rule, Xen enforces that only one of the types +\verb|CocaCola| or \verb|PepsiCo| will run on a single hypervisor +platform at a time. For example, once a domain assigned a +\verb|CocaCola| workload type is started, domains with the +\verb|PepsiCo| type will be denied to start. When the former domain +stops and no other domains with the \verb|CocaCola| type are running, +then domains with the \verb|PepsiCo| type can start. + +Xen maintains reference counts on each running workload type to keep +track of which workload types are running. Every time a domain starts +or resumes, the reference count on those Chinese Wall types that are +referenced in the domain's label are incremented. Every time a domain +is destroyed or saved, the reference counts of its Chinese Wall types +are decremented. sHype in Xen covers migration and live-migration, +which is treated the same way as saving a domain on the source +platform and resuming it on the destination platform. + +Reasons why users would want to restrict which workloads or domains +can share the system hardware include: + +\begin{itemize} +\item Imperfect resource management or control might enable a rogue + domain to starve another domain and the workload running in it. +\item Redundant domains might run the same workload to increase + availability; such domains should not run on the same hardware to + avoid single points of failure. +\item Imperfect Xen core domain isolation might enable two rogue + domains running different workload types to use unintended and + unknown ways (covert channels) to exchange some data. This way, they + bypass the policed Xen access control mechanisms. Such + imperfections cannot be completely eliminated and are a result of + trade-offs between security and other design requirements. For a + simple example of a covert channel see + http://www.multicians.org/timing-chn.html. Such covert channels + exist also between workloads running on different platforms if they + are connected through networks. The Xen Chinese Wall policy provides + an approximation of this imperfect ``air-gap'' between selected + workload types. +\end{itemize} + +\subsection{Security Labels} + +To enable Xen to associate domains with workload types running in +them, each domain is assigned a security label that includes the +workload types of the domain. + +\begin{figure} +\begin{scriptsize} +\begin{verbatim} +32 +33 +34 +35 SystemManagement +36 +37 SystemManagement +38 PepsiCo +39 CocaCola +40 +41 +42 SystemManagement +43 +44 +45 +46 +47 PepsiCo +48 +49 PepsiCo +50 +51 +52 PepsiCo +53 +54 +55 +56 +57 CocaCola +58 +59 CocaCola +60 +61 +62 CocaCola +63 +64 +65 +66 +67 +68 +69 SystemManagement +70 +71 SystemManagement +72 +73 +74 +75 +76 PepsiCo +77 +78 PepsiCo +79 +80 +81 +82 +83 CocaCola +84 +85 CocaCola +86 +87 +88 +89 +90 +\end{verbatim} +\end{scriptsize} +\caption{Example XML security policy file -- Part II: Label Definition.} +\label{fig:acmxmlfileb} +\end{figure} + +Lines 32-89 (cf Figure~\ref{fig:acmxmlfileb}) define the +\verb|SecurityLabelTemplate|, which includes the labels that can be +attached to domains and resources when this policy is active. The +domain labels include Chinese Wall types while resource labels do not +include Chinese Wall types. Lines 33-65 define the +\verb|SubjectLabels| that can be assigned to domains. For example, the +virtual machine label \verb|CocaCola| (cf lines 56-64 in +Figure~\ref{fig:acmxmlfileb}) associates the domain that carries it +with the workload type \verb|CocaCola|. + +The \verb|bootstrap| attribute names the label +\verb|SystemManagement|. Xen will assign this label to Domain0 at +boot time. All other domains are assigned labels according to their +domain configuration file (see +Section~\ref{subsection:acmexamplelabeldomains} for examples of how to +label domains). Lines 67-88 define the \verb|ObjectLabels|. Those +labels can be assigned to resources when this policy is active. + +In general, user domains should be assigned labels that have only a +single SimpleTypeEnforcement workload type. This way, workloads remain +confined even if user domains become rogue. Any domain that is +assigned a label with multiple STE types must be trusted to keep +information belonging to the different STE types separate (confined). +For example, Domain0 is assigned the bootstrap label +\verb|SystemsManagement|, which includes all existing STE types. +Therefore, Domain0 must take care not to enable unauthorized +information flow (eg. through block devices or virtual networking) +between domains or resources that are assigned different STE types. + +Security administrators simply use the name of a label (specified in +the \verb|| field) to associate a label with a domain (cf. +Section~\ref{subsection:acmexamplelabeldomains}). The types inside the +label are used by the Xen access control enforcement. While the name +can be arbitrarily chosen (as long as it is unique), it is advisable +to choose the label name in accordance to the security types included. +While the XML representation in the above label seems unnecessary +flexible, labels in general can consist of multiple types as we will +see in the following example. + +Assume that \verb|PepsiCo| and \verb|CocaCola| workloads use virtual +disks that are provided by a virtual I/O domain hosting a physical +storage device and carrying the following label: + +\begin{scriptsize} +\begin{verbatim} + + VIO + + CocaCola + PepsiCo + + + VIOServer + + +\end{verbatim} +\end{scriptsize} + +This Virtual I/O domain (VIO) exports its virtualized disks by +communicating both to domains labeled with the \verb|PepsiCo| label +and domains labeled with the \verb|CocaCola| label. This requires the +VIO domain to carry both the STE types \verb|CocaCola| and +\verb|PepsiCo|. In this example, the confinement of \verb|CocaCola| +and \verb|PepsiCo| workload depends on a VIO domain that must keep the +data of those different workloads separate. The virtual disks are +labeled as well (see Section~\ref{subsection:acmexamplelabelresources} +for labeling resources) and enforcement functions inside the VIO +domain must ensure that the labels of the domain mounting a virtual +disk and the virtual disk label share a common STE type. The VIO label +carrying its own VIOServer CHWALL type introduces the flexibility to +permit the trusted VIO server to run together with CocaCola or PepsiCo +workloads. + +Alternatively, a system that has two hard-drives does not need a VIO +domain but can directly assign one hardware storage device to each of +the workloads (if the platform offers an IO-MMU, cf +Section~\ref{s:ddsecurity}. Sharing hardware through virtualization +is a trade-off between the amount of trusted code (size of the trusted +computing base) and the amount of acceptable over-provisioning. This +holds both for peripherals and for system platforms. + +\subsection{Tools For Creating sHype/Xen Security Policies} +To create a security policy for Xen, you can use one of the following +tools: +\begin{itemize} +\item \verb|ezPolicy| GUI tool -- start writing policies +\item \verb|xensec_gen| tool -- refine policies created with \verb|ezPolicy| +\item text or XML editor +\end{itemize} + +We use the \verb|ezPolicy| tool in +Section~\ref{subsection:acmexamplecreate} to quickly create a workload +protection policy. If desired, the resulting XML policy file can be +loaded into the \verb|xensec_gen| tool to refine it. It can also be +directly edited using an XML editor. Any XML policy file is verified +against the security policy schema when it is translated (see +Subsection~\ref{subsection:acmexampleinstall}). + +\section{Current Limitations} +\label{section:acmlimitations} + +The sHype/ACM configuration for Xen is work in progress. There is +ongoing work for protecting virtualized resources and planned and +ongoing work for protecting access to remote resources and domains. +The following sections describe limitations of some of the areas into +which access control is being extended. + +\subsection{Network Traffic} +Local and remote network traffic is currently not controlled. +Solutions to add sHype/ACM policy enforcement to the virtual network +exist but need to be discussed before they can become part of Xen. +Subjecting external network traffic to the ACM security policy is work +in progress. Manually setting up filters in domain 0 is required for +now but does not scale well. + +\subsection{Resource Access and Usage Control} + +Enforcing the security policy across multiple hypervisor systems and +on access to remote shared resources is work in progress. Extending +access control to new types of resources is ongoing work (e.g. network +storage). + +On a single Xen system, information about the association of resources +and security labels is stored in +\verb|/etc/xen/acm-security/policy/resource_labels|. This file relates +a full resource path with a security label. This association is weak +and will break if resources are moved or renamed without adapting the +label file. Improving the protection of label-resource relationships +is ongoing work. + +Controlling resource usage and enforcing resource limits in general is +ongoing work in the Xen community. + +\subsection{Domain Migration} + +Labels on domains are enforced during domain migration and the +destination hypervisor will ensure that the domain label is valid and +the domain is permitted to run (considering the Chinese Wall policy +rules) before it accepts the migration. However, the network between +the source and destination hypervisor as well as both hypervisors must +be trusted. Architectures and prototypes exist that both protect the +network connection and ensure that the hypervisors enforce access +control consistently but patches are not yet available for the main +stream. + +\subsection{Covert Channels} + +The sHype access control aims at system independent security policies. +It builds on top of the core hypervisor isolation. Any covert channels +that exist in the core hypervisor or in the hardware (e.g., shared +processor cache) will be inherited. If those covert channels are not +the result of trade-offs between security and other system properties, +then they are most effectively minimized or eliminated where they are +caused. sHype offers however some means to mitigate their impact +(cf. run-time exclusion rules). + \part{Reference} %% Chapter Build and Boot Options From 33ac7e69c847749e3c58a94b0648adc3131f68a0 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 31 Jul 2006 18:12:53 +0100 Subject: [PATCH 030/111] [ACM] A wxPython GUI tool for sHype/ACM in Xen. It is used and described in the user guide to demonstrate how to quickly create, enforce, and test workload protection policies in Xen. The tool is aimed to improve usability of sHype/ACM for Xen.It is included in a single file to make it easy to try it out on different platforms (it inherits the look and feel of the base platform). It is tested on Linux and Windows. Please read the new user guide section about how to start and use the tool (section 10.2). Requirements: python (www.python.org), wxPython (www.wxpython.org or try 'yum install wxPython'). Signed-off by: Reiner Sailer --- tools/security/Makefile | 2 + tools/security/xensec_ezpolicy | 1628 ++++++++++++++++++++++++++++++++ 2 files changed, 1630 insertions(+) create mode 100644 tools/security/xensec_ezpolicy diff --git a/tools/security/Makefile b/tools/security/Makefile index 824135f5f7..cd0835a910 100644 --- a/tools/security/Makefile +++ b/tools/security/Makefile @@ -32,6 +32,7 @@ SRCS_XML2BIN = secpol_xml2bin.c secpol_xml2bin.h OBJS_XML2BIN := $(patsubst %.c,%.o,$(filter %.c,$(SRCS_XML2BIN))) ACM_INST_TOOLS = xensec_tool xensec_xml2bin xensec_gen +ACM_EZPOLICY = xensec_ezpolicy ACM_OBJS = $(OBJS_TOOL) $(OBJS_XML2BIN) $(OBJS_GETD) ACM_SCRIPTS = python/xensec_tools/acm_getlabel @@ -56,6 +57,7 @@ all: build install: all $(ACM_CONFIG_FILE) $(INSTALL_DIR) -p $(DESTDIR)/usr/sbin $(INSTALL_PROG) -p $(ACM_INST_TOOLS) $(DESTDIR)/usr/sbin + $(INSTALL_PROG) -p $(ACM_EZPOLICY) $(DESTDIR)/usr/sbin $(INSTALL_DIR) -p $(DESTDIR)$(ACM_CONFIG_DIR) $(INSTALL_DIR) -p $(DESTDIR)$(ACM_POLICY_DIR) $(INSTALL_DATA) -p policies/$(ACM_SCHEMA) $(DESTDIR)$(ACM_POLICY_DIR) diff --git a/tools/security/xensec_ezpolicy b/tools/security/xensec_ezpolicy new file mode 100644 index 0000000000..34af952bbe --- /dev/null +++ b/tools/security/xensec_ezpolicy @@ -0,0 +1,1628 @@ +#!/usr/bin/env python +#=========================================================================== +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006 International Business Machines Corp. +# Author: Reiner Sailer +#============================================================================ +# use 'yum install wxPython' to get wx or download from www.wxpython.org +import sys, time, string +import wx +import wx.lib.buttons as buttons +""" +This program creates a default policy based on names of organizations and departments. +The resulting policy can be refined using the policy generation tool (xensec_gen). +""" + +helpprovider = wx.SimpleHelpProvider() +wx.HelpProvider_Set(helpprovider) + +ID_CS_START=1000 + +realm_bmp = None +workload_bmp = None +conflict_bmp = None +realm_icon = None +workload_icon = None + +class orgTreeCtrl(wx.TreeCtrl): + + event = None + + def __init__(self, parent, id, pos, size, style, validator, name): + wx.TreeCtrl.__init__(self, parent, id, pos, size, style, + validator, name) + self.parent = parent + orgs_root = self.AddRoot(text="Organization / Department") + rootfont = wx.Font(pointSize=12, family=wx.FONTFAMILY_DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_LIGHT) + self.SetItemFont(orgs_root, rootfont) + self.SetItemBackgroundColour(orgs_root, wx.LIGHT_GREY) + + + def LabelExists(self, label, item): + for i in iterchildren(self.GetItemParent(item)): + if (self.GetItemText(i) == label) and (i != item): + return True + return False + + + def _OrgEdt(self, event): + item = self.event.GetItem() + self.OrgEdt(item) + + + def OrgEdt(self, item): + oldlabel= self.GetItemText(item) + #get new name + dlg = wx.TextEntryDialog(self, "Please enter org/dept name:", + "Naming a Workload", + style=wx.CANCEL | wx.OK | wx.CENTRE | wx.TE_NOHIDESEL) + dlg.SetValue(oldlabel) + ret = dlg.ShowModal() + newlabel = dlg.GetValue() + dlg.Destroy() + if (ret == wx.ID_CANCEL) or (newlabel == ''): + return False + + #now check if the new name is permissible + if self.LabelExists(newlabel, item): + dlg = wx.MessageDialog(self, 'Item with name ' + newlabel + ' already exists!', + 'Rename', style=wx.OK) + dlg.ShowModal() + dlg.Destroy() + return False + + #all checkspassed, change item and adapt runtime exclusion rules + self.SetItemText(item, newlabel) + app.win.LabelReplaceInConflictsets(item, oldlabel, newlabel) + return True + + + def _OrgRAdd(self, event): + self.OrgRAdd() + + + def OrgRAdd(self): + new = self.AppendItem(self.GetRootItem(), text="") + self.SetItemBold(new, True) + self.SetItemImage(new, realm_icon, wx.TreeItemIcon_Normal) + self.EnsureVisible(new) + if not self.OrgEdt(new): + self.Delete(new) + + + def _OrgWAdd(self, event): + item = self.event.GetItem() + self.OrgWAdd(item) + + + def OrgWAdd(self, item): + new = self.AppendItem(item, text="") + self.Expand(item) + self.SetItemImage(new, workload_icon, wx.TreeItemIcon_Normal) + self.EnsureVisible(new) + if not self.OrgEdt(new): + self.Delete(new) + + +class OrgsPanel(wx.Panel): + ID_CONSADDBTN = 145 + ID_REALMADDBTN = 144 + + def __init__(self, parent, ID): + global realm_icon, workload_icon + + wx.Panel.__init__(self, parent, -1) + + #create image list + imagelist = wx.ImageList(16, 17, True) + #define generic function and use it for all input + realm_icon = imagelist.Add(realm_bmp) + workload_icon = imagelist.Add(workload_bmp) + + #left tree control for organizations / workload definitions + orgshdrbox = wx.StaticBox(self, -1, "") + orgshdrboxsizer = wx.StaticBoxSizer(orgshdrbox, wx.HORIZONTAL) + orgshdr = wx.StaticText(self, -1, "Organization / Department Definition", + style=wx.ALIGN_CENTER) + orgshdr.SetHelpText(RealmWorkloadPanelHelp) + points = orgshdr.GetFont().GetPointSize() # get the current size + hdrfont = wx.Font(points + 2, family=wx.DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.BOLD) + orgshdr.SetFont(hdrfont) + orgshdr.SetForegroundColour('MEDIUMBLUE') + orgshdr.SetBackgroundColour('SNOW') + orgshdrboxsizer.Add(orgshdr, proportion=1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_LEFT, border=5) + addorgsbutton = wx.Button(self, self.ID_REALMADDBTN, "New Org", style=wx.BU_EXACTFIT) + addorgsbutton.SetToolTipString("Add A New Organization") + addorgsbutton.SetHelpText(NewRealmButtonHelp) + addorgsbutton.SetForegroundColour('MEDIUMBLUE') + addfont = wx.Font(points, family=wx.DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.BOLD) + addorgsbutton.SetFont(addfont) + orgshdrboxsizer.Add(addorgsbutton, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=0) + + self.orgs = orgTreeCtrl(self, -1, + pos=wx.DefaultPosition, + size=wx.DefaultSize, + style=wx.TR_HAS_BUTTONS | wx.TR_HIDE_ROOT | wx.TR_NO_LINES + | wx.TR_MULTIPLE, + validator=wx.DefaultValidator, + name="orgs") + self.orgs.AssignImageList(imagelist) + self.orgs.SetHelpText(RealmWorkloadPanelHelp) + + self.addconsbutton = wx.Button(self, self.ID_CONSADDBTN, + "Create run-time exclusion rule from selection -->", + style=wx.BU_EXACTFIT) + self.addconsbutton.SetToolTipString("Create New Exclusion rule From Above Workload Selection") + self.addconsbutton.SetHelpText(CreateRunTimeButtonHelp) + self.addconsbutton.SetForegroundColour('MEDIUMBLUE') + addfont = wx.Font(points, family=wx.DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.BOLD) + self.addconsbutton.SetFont(addfont) + self.addconsbutton.Bind(wx.EVT_BUTTON, self._AddConflict, id=self.ID_CONSADDBTN) + + orgsvbox = wx.BoxSizer(wx.VERTICAL) + orgsvbox.Add(orgshdrboxsizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + orgsvbox.Add(self.orgs, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + orgsvbox.Add(self.addconsbutton, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.SetSizer(orgsvbox) + addorgsbutton.Bind(wx.EVT_BUTTON, self.orgs._OrgRAdd, id= self.ID_REALMADDBTN) + + + def _AddConflict(self, event): + app.win.conspanel._AddNewConflict(event) + + +class ConsPanel(wx.Panel): + ID_CONSSELECT = 151 + ID_CONSADD = 152 + ID_CONSRENAME = 153 + ID_CONSDEL = 154 + ID_CONSSELECTSUB= 155 + + conflictMAX = ID_CS_START + + def __init__(self, parent, ID): + self.conflictsets = [] + self.parent = parent + wx.Panel.__init__(self, parent, -1) + #header + conshdrbox = wx.StaticBox(self, -1, "") + conshdrboxsizer = wx.StaticBoxSizer(conshdrbox, wx.HORIZONTAL) + conshdr = wx.StaticText(self, -1, "Run-time Exclusion Rules", style=wx.ALIGN_CENTER) + conshdr.SetHelpText(RunTimeExclusionPanelHelp) + points = conshdr.GetFont().GetPointSize() # get the current size + hdrfont = wx.Font(points + 2, family=wx.DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.BOLD) + conshdr.SetFont(hdrfont) + conshdr.SetForegroundColour('ORANGERED') + + #context help button + ctxHelp = wx.ContextHelpButton(self) + ctxHelp.SetHelpText("Context Help Button.") + ctxHelp.SetToolTipString("Context Help: Press this button, then press any other button or panel to get help.") + + + conshdrboxsizer.Add(conshdr, proportion=1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_LEFT, border=5) + conshdrboxsizer.Add(ctxHelp, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=0) + #scrolledwindow for all the run-time exclusion rules + conflictspanel = wx.ScrolledWindow(self, -1, (0,0), + style = wx.FULL_REPAINT_ON_RESIZE | + wx.VSCROLL ) + conflictspanel.SetVirtualSize((1000, 1000)) + conflictspanel.SetScrollRate(5,5) + self.conflictsboxsizer = wx.BoxSizer(wx.VERTICAL) + + #self.conflictsboxsizer.Fit(self) + conflictspanel.SetSizer(self.conflictsboxsizer) + consvbox = wx.BoxSizer(wx.VERTICAL) + consvbox.Add(conshdrboxsizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + consvbox.Add(conflictspanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + self.SetSizer(consvbox) + self.consvbox = consvbox + self.conflictspanel=conflictspanel + + self.cmenu = wx.Menu() + self.cmenu.Append(self.ID_CONSRENAME, "Rename Run-time Exclusion Rule", "Rename Run-time Exclusion Rule") + self.cmenu.AppendSeparator() + self.cmenu.Append(self.ID_CONSDEL, "Delete Run-time Exclusion Rule", "Delete Run-time Exclusion Rule") + self.Bind(wx.EVT_MENU, self._CSRename, id=self.ID_CONSRENAME) + self.Bind(wx.EVT_MENU, self._CSDelete, id=self.ID_CONSDEL) + + + #Helper methods called from anywhere + def New(self): + #delete all run-time exclusion rules + for i in self.conflictsets: + i.Disable() + i.Destroy() + self.conflictsets = [] + self.conflictsboxsizer.Layout() + size=self.GetSize() + self.Fit() + self.SetSize(size) + + + def DelCSById(self, delid): + #delete CS representation + delpos, item = self.GetCSBox(delid) + if item: + self.DelCSByItem(item) + + + def DelCSByItem(self, item): + #delete CS representation + self.conflictsets.remove(item) + exists = self.conflictsboxsizer.Detach(item) + if exists: + item.Destroy() + self.RefreshMe() + + + def RefreshMe(self): + size=self.parent.GetSize() + self.parent.Fit() + self.parent.SetSize(size) + + + def GetOrgSelection(self): + (tree, selection) = GetOrgsSelection() + if not len(selection): + dlg = wx.MessageDialog(self, 'You must select first at least one Organization/Department workload!', + 'Creating A New Run-time Rule', wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return None,None + # now rewrite selection (realm.workload extension, check consistency) + alist = [] + for i in selection: + if isRealm(i): + alist.append(tree.GetItemText(i)) + else: + alist.append(tree.GetItemText(tree.GetItemParent(i)) + + "." + tree.GetItemText(i)) + + if isRealm(i): + for j in selection: + if tree.GetItemParent(j) == i: + violation = ("[ " + tree.GetItemText(i) + ", " + + tree.GetItemText(i) + "." + tree.GetItemText(j) + " ]") + dlg = wx.MessageDialog(self, + 'Invalid Selection ' + violation + '.\n\n' + + 'You can only select EITHER an Organization OR specific Department!', + 'Creating A New Run-time Exclusion Rule', wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return None,None + return (alist, selection) + + + def AddConflict(self, name, types): + csbox = myCSPanel(self, self.conflictMAX, name, types) + self.conflictsboxsizer.Add(csbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) + self.conflictsets.append(csbox) + self.conflictMAX = self.conflictMAX+3 + self.RefreshMe() + csbox.RefreshMe() + + + def GetCSBox(self, id): + pos = -1 + i = 0 + while self.conflictsboxsizer.GetItem(i): + item = self.conflictsboxsizer.GetItem(i).GetWindow() + if ((item.cbmp.GetId() == id) or + (item.add_selection.GetId() == id) or + (item.del_selection.GetId() == id)): + pos = i + box = item + break + i = i + 1 + if pos < 0: + print "Run-time Exclusion Rule Not Found ERROR!" + return (None, None) + else: + return (pos, box) + + + #bind methods + def _AddNewConflict(self, event): + # first get the conflicting workload types with current selection + types, items = self.GetOrgSelection() + if not types: + return + #get name for conflict set + dlg = wx.TextEntryDialog( + self, 'Please enter a name for the Run-time Exclusion Rule:', 'Creating A New Run-time Exclusion Rule') + dlg.SetValue("") + ret = dlg.ShowModal() + name = dlg.GetValue() + dlg.Destroy() + if ret != wx.ID_OK: + return + self.AddConflict(name, types) + + + def _OnClick(self, event): + self.event = event + app.win.SetStatusText("") + self.PopupMenu(self.cmenu) + + + def _CSRename(self, event): + delpos, item = self.GetCSBox(self.event.GetId()) + if not item: + return + #allow to name the conflict set + dlg = wx.TextEntryDialog( + self, 'Please enter a new name for the Conflict Set:', 'Renaming A Run-time Exclusion Rule') + dlg.SetValue(item.box.GetLabel()) + ret = dlg.ShowModal() + name = dlg.GetValue() + dlg.Destroy() + if ret != wx.ID_OK: + return + item.box.SetLabel(name) + item.box.SetFont(wx.Font(item.GetFont().GetPointSize(), family=wx.DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.BOLD)) + + + def _CSDelete(self, event): + delid = self.event.GetId() + self.DelCSById(delid) + + + def _AddOrgSelection(self, event): + addid = event.GetId() + addpos, item = self.GetCSBox(addid) + alist, items = self.GetOrgSelection() + if not alist: + return + existing = [] + for i in range(0, item.clb.GetCount()): + existing.append(item.clb.GetString(i)) + + #now make sure that we don't get realm + workload into the same CS + for i in items: + if isRealm(i): + #ensure no workload of this realm is already in CS + realm = app.win.orgs.GetItemText(i) + for j in iterchildren(i): + workload = app.win.orgs.GetItemText(j) + try: + idx = existing.index (realm + "." + workload) + except: + #ok, does not exist + continue + #nok, exists already + violation = ("[ " + realm + ", " + + realm + "." + workload + " ]") + dlg = wx.MessageDialog(self, + 'Invalid Selection ' + violation + '.\n\n' + + 'You can only have EITHER an Organization OR a specific Department workload\n' + + 'in a single Run-time Exclusion Rule', + 'Adding Orgs/Depts workloads to a Run-time Exclusion Rule', + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + else: + #ensure realm of this workload is not in CS + realm = app.win.orgs.GetItemText(app.win.orgs.GetItemParent(i)) + try: + idx = existing.index(realm) + except: + #ok, does not exist + continue + #nok, exists already + violation = ("[ " + realm + "." + app.win.orgs.GetItemText(i) + + ", " + realm + " ]") + dlg = wx.MessageDialog(self, + 'Invalid Selection ' + violation + '.\n\n' + + 'You can only have EITHER an Organization OR a specific Department workload\n' + + 'in a single Run-time Exclusion Rule', + 'Adding Orgs/Depts workloads to a Run-time Exclusion Rule', + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + #check if any of the selections are already in the conflict set + overlap=[] + for l in alist: + for e in existing: + if l == e: + overlap.append(str(l)) + if len(overlap): + if len(overlap) == 1: + message = "Selected item " + str(overlap) +\ + " is already in the Run-time Exclusion rule and will be ignored.\n\n Continue?" + else: + message = "Selected items " + str(overlap) +\ + " are already in the Run-time Exclusion rule and will be ignored.\n\n Continue?" + dlg = wx.MessageDialog(self, + message, 'Adding Orgs/Depts workloads to a Run-time Exclusion rule', + wx.YES | wx.NO | wx.ICON_EXCLAMATION) + ret = dlg.ShowModal() + dlg.Destroy() + if ret != wx.ID_YES: + return + + for s in alist: + try: + existing.index(s) + except Exception: + # s not yet in list box, add it + item.AddTypes([s]) + self.RefreshMe() + + + def _DelConSelection(self, event): + eventid = event.GetId() + pos, item = self.GetCSBox(eventid) + idtuple = item.clb.GetSelections() + idlist = [] + for i in idtuple: + idlist.append(i) + #delete reverse, otherwise item mubers get messed up while deleting + idlist.reverse() + for i in idlist: + item.clb.Delete(i) + item.RefreshMe() + if item.clb.GetCount() < 2: + dlg = wx.MessageDialog(self, + """Run-time exclusion set has less than two types.\n\n + Do you want to delete this rule?""", + 'Deleting Orgs/Depts workloads from a Run-time Exclusion rule', + wx.YES| wx.NO | wx.ICON_QUESTION) + ret = dlg.ShowModal() + dlg.Destroy() + if ret == wx.ID_YES: + self.DelCSById(eventid) + return + else: + for i in item.clb.GetSelections(): + item.clb.Deselect(i) + self.RefreshMe() + + +class myCSPanel(wx.Panel): + def __init__(self, parent, ID, title, list=[]): + wx.Panel.__init__(self, parent.conflictspanel, -1) + self.parent = parent + cspansizer = wx.BoxSizer(wx.VERTICAL) + self.box = wx.StaticBox(self, -1, title) + csboxsizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL) + #left: type add/del + typesizer = wx.BoxSizer(wx.VERTICAL) + self.add_selection = wx.Button(self, ID+1, "--> Add", style=wx.BU_EXACTFIT) + self.add_selection.SetToolTipString("Add Workload Selection To Run-time Exclusion rule") + self.add_selection.SetHelpText(AddToExclusionButtonHelp) + self.add_selection.SetForegroundColour('MEDIUMBLUE') + points = self.add_selection.GetFont().GetPointSize() + addfont = wx.Font(points, family=wx.DEFAULT, + style=wx.FONTSTYLE_NORMAL, weight=wx.BOLD) + self.add_selection.SetFont(addfont) + self.box.SetFont(addfont) + typesizer.Add(self.add_selection, proportion = 0, flag = wx.EXPAND | wx.ALL,border=0) + typesizer.Add((5,5)) + self.del_selection = wx.Button(self, ID+2, "<-- Del", style=wx.BU_EXACTFIT) + self.del_selection.SetToolTipString("Delete Workload Selection From Run-time Exclusion Rule") + self.del_selection.SetHelpText(DelFromExclusionButtonHelp) + self.del_selection.SetForegroundColour('ORANGERED') + self.del_selection.SetFont(addfont) + typesizer.Add(self.del_selection, proportion = 0, flag = wx.EXPAND | wx.ALL, border=0) + csboxsizer.Add(typesizer, proportion = 0, border=0) + csboxsizer.Add((5,5)) + #middle: types + self.clb = wx.ListBox(self, id=-1, choices=list, + style= wx.LB_MULTIPLE | wx.LB_SORT ) + self.clb.SetHelpText(ExclusionSetHelp) + csboxsizer.Add(self.clb, proportion=1, flag=wx.EXPAND | wx.ALL, border=0) + csboxsizer.Add((5,5)) + #right: Conflictset-global ops button + bmpsizer = wx.BoxSizer(wx.VERTICAL) + self.cbmp = buttons.GenBitmapButton(self, ID, conflict_bmp, style=wx.BU_EXACTFIT) + self.cbmp.SetHelpText(ManageExclusionButtonHelp) + self.cbmp.SetToolTipString("Rename/Delete\nAssociated Run-time Exclusion Rule") + bmpsizer.Add(self.cbmp, proportion = 0, flag = wx.EXPAND | wx.ALL, border=0) + csboxsizer.Add(bmpsizer, proportion=0, border=5) + cspansizer.Add(csboxsizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=0) + self.csboxsizer=csboxsizer + self.cspansizer=cspansizer + self.SetSizer(cspansizer) + self.cbmp.Bind(wx.EVT_LEFT_DOWN, parent._OnClick, id=ID) + self.add_selection.Bind(wx.EVT_BUTTON, parent._AddOrgSelection, id=ID + 1) + self.del_selection.Bind(wx.EVT_BUTTON, parent._DelConSelection, id=ID + 2) + + # append and delete an item to get rid of + # the ugly vertical scroll bar on the Listbox on Linux + def RefreshMe(self): + x = self.clb.Append(" ") + app.win.conspanel.RefreshMe() + self.clb.Delete(x) + self.Layout() + app.win.conspanel.Layout() + + + def AddTypes(self, list): + for i in list: + self.clb.Append(i) + self.RefreshMe() + + + def GetTypes(self): + alist = [] + for i in range(0, self.clb.GetCount()): + alist.append(self.clb.GetString(i)) + return alist + + + def GetBoxName(self): + return self.box.GetLabel() + + + def Replace(self, oldlabel, newlabel): + index = self.clb.FindString(oldlabel) + if index != wx.NOT_FOUND: + self.clb.SetString(index, newlabel) + + + def Delete(self, label): + index = self.clb.FindString(label) + if index != wx.NOT_FOUND: + self.clb.Delete(index) + + +class myHelpPanel(wx.Panel): + def __init__(self, parent, ID): + wx.Panel.__init__(self, parent, -1) + + +class ezFrame(wx.Frame): + + ID_ABOUT = 101 + ID_NEW = 102 + ID_OPEN = 103 + ID_SAVE = 104 + ID_SAVEAS = 105 + ID_EXIT = 106 + ID_HELP = 107 + + ID_ITRENAME = 111 + ID_ITADD = 112 + ID_ITDEL = 113 + + ID_COLLAPSEALL = 121 + ID_EXPANDALL = 122 + ID_SORTALL = 123 + + ID_TRANSLATE = 131 + + ID_ORGEDT = 141 + ID_ORGADD = 142 + ID_ORGDEL = 143 + + def __init__(self, parent, ID, title): + global realm_bmp, workload_bmp, conflict_bmp + + wx.Frame.__init__(self, parent, ID, title, + wx.DefaultPosition, + wx.Size(700,450) + ) + + realm_bmp = GetIconBitmap('Organization') + workload_bmp = GetIconBitmap('Department') + conflict_bmp = GetIconBitmap('Conflict') + self.SetHelpText(GetHelp) + self.orgfilename = None + self.CreateStatusBar() + self.SetStatusText("") + self.bkg = wx.Panel(self) + + self.orgswin = wx.SashLayoutWindow( + self.bkg, -1, wx.DefaultPosition, (300, 150),wx.SW_3DSASH | wx.SW_BORDER) + + self.orgswin.SetDefaultSize((300,150)) + self.orgswin.SetOrientation(wx.LAYOUT_VERTICAL) + self.orgswin.SetAlignment(wx.LAYOUT_LEFT) + self.orgspanel = OrgsPanel(self.orgswin, -1) + self.orgs = self.orgspanel.orgs + + self.realm_menu = wx.Menu() + self.realm_menu.Append(self.ID_ORGADD, "Add Department\tctrl-a", "Add Department Workload") + self.realm_menu.AppendSeparator() + self.realm_menu.AppendSeparator() + self.realm_menu.Append(self.ID_ORGEDT, "Rename Organization\tctrl-r", "Rename Organization Workload") + self.realm_menu.Append(self.ID_ORGDEL, "Delete Organization\tctrl-d", "Delete Organization Workload") + self.realm_menu.Bind(wx.EVT_MENU, self.orgs._OrgEdt, id= self.ID_ORGEDT) + self.realm_menu.Bind(wx.EVT_MENU, self.orgs._OrgWAdd, id= self.ID_ORGADD) + self.realm_menu.Bind(wx.EVT_MENU, self._ItemDel, id=self.ID_ORGDEL) + + self.workload_menu = wx.Menu() + self.workload_menu.Append(self.ID_ORGEDT, "Rename Department\tctrl-r", "Rename Department Workload") + self.workload_menu.Append(self.ID_ORGDEL, "Delete Department\tctrl-d", "Delete Department Workload") + self.workload_menu.Bind(wx.EVT_MENU, self.orgs._OrgEdt, id= self.ID_ORGEDT) + self.workload_menu.Bind(wx.EVT_MENU, self._ItemDel, id=self.ID_ORGDEL) + + self.orgs.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self._OrgRightClick) + self.orgs.Bind(wx.EVT_TREE_SEL_CHANGED, self._OrgSelectionChanged) + + self.conswin = wx.SashLayoutWindow( + self.bkg, -1, wx.DefaultPosition, (300, 150), + #wx.NO_BORDER | wx.SW_3D + wx.SW_3DSASH | wx.SW_BORDER + ) + self.conswin.SetDefaultSize((300,150)) + self.conswin.SetOrientation(wx.LAYOUT_VERTICAL) + self.conswin.SetAlignment(wx.LAYOUT_RIGHT) + self.conswin.SetSashVisible(wx.SASH_LEFT, True) + self.conswin.SetSashVisible(wx.SASH_RIGHT, False) + + #right tree control for non-concurrent workload execution + self.conspanel = ConsPanel(self.conswin, -1) + self.conspanel.RefreshMe() + self.bkg.Bind(wx.EVT_SASH_DRAGGED_RANGE, self._OnSashDrag, id=self.conswin.GetId(), + id2=self.conswin.GetId()) + self.bkg.Bind(wx.EVT_SIZE, self._OnSize) + + # Main Menu + # -File + fmenu = wx.Menu() + fmenu.Append(self.ID_OPEN, "Open Workload Definition...\tctrl-o", "Open current workload definition") + fmenu.Append(self.ID_SAVE, "Save Workload Definition\tctrl-s", "Save workload defintion") + fmenu.Append(self.ID_SAVEAS, "Save Workload Defintion as...\talt-s", "Save into new file") + fmenu.AppendSeparator() + fmenu.Append(self.ID_TRANSLATE, "Save as Xen ACM Security Policy ...\talt-t", "Create Xen ACM security policy") + fmenu.AppendSeparator() + fmenu.Append(self.ID_NEW, "New\tctrl-n", "Create a new oganization definition") + fmenu.AppendSeparator() + fmenu.Append(self.ID_EXIT, "Exit\tctrl-x", "Terminate the program") + self.fmenu = fmenu + + # -Edit + emenu = wx.Menu() + emenu.Append(self.ID_ITRENAME, "Rename\tctrl-r", "Rename Selected Organization/Department") + emenu.Append(self.ID_ITADD, "Add\tctrl-a", "Add Child to Selected Organization/Department") + emenu.Append(self.ID_ITDEL, "Delete\tctrl-d", "Delete Selected Organization/Department") + self.emenu = emenu + # -Help + hmenu = wx.Menu() + hmenu.Append(self.ID_HELP, "Step-By-Step Help\tctrl-h", "More information about this program") + hmenu.Append(self.ID_ABOUT, "About", "More information about this program") + self.hmenu = hmenu + + # -View + vmenu = wx.Menu() + vmenu.Append(self.ID_SORTALL, "Sort All", "Sort Entries In All Trees") + vmenu.Append(self.ID_COLLAPSEALL, "Collapse All\tctrl-c", "Collapse All Trees") + vmenu.Append(self.ID_EXPANDALL, "Expand All\tctrl-e", "Expand All Trees") + self.vmenu = vmenu + + menuBar = wx.MenuBar() + menuBar.Append(fmenu, "&File"); + menuBar.Append(emenu, "&Edit"); + menuBar.Append(vmenu, "&View"); + menuBar.Append(hmenu, "&Help"); + + self.SetMenuBar(menuBar) + + self.Bind(wx.EVT_MENU, self._OpenSpec, id=self.ID_OPEN) + self.Bind(wx.EVT_MENU, self._SaveSpec, id=self.ID_SAVE) + self.Bind(wx.EVT_MENU, self._SaveAsSpec,id=self.ID_SAVEAS) + self.Bind(wx.EVT_MENU, self._NewSpec, id=self.ID_NEW) + self.Bind(wx.EVT_MENU, self._TimeToQuit,id=self.ID_EXIT) + self.Bind(wx.EVT_MENU, self._TranslateSpec, id=self.ID_TRANSLATE) + + self.Bind(wx.EVT_MENU, self._ItemRename, id=self.ID_ITRENAME) + self.Bind(wx.EVT_MENU, self._ItemAdd, id=self.ID_ITADD) + self.Bind(wx.EVT_MENU, self._ItemDel, id=self.ID_ITDEL) + + self.Bind(wx.EVT_MENU, self._SortAll, id=self.ID_SORTALL) + self.Bind(wx.EVT_MENU, self._CollapseAll,id=self.ID_COLLAPSEALL) + self.Bind(wx.EVT_MENU, self._ExpandAll, id=self.ID_EXPANDALL) + + self.Bind(wx.EVT_MENU, self._Help, id=self.ID_HELP) + self.Bind(wx.EVT_MENU, self._OnAbout, id=self.ID_ABOUT) + self.Bind(wx.EVT_CLOSE, self._TimeToQuit) + + + def RefreshMe(self): + size=self.GetSize() + self.Fit() + self.SetSize(size) + + #helper methods + def Load(self, file): + self.orgfilename = file + dictname = 'ezpolicy' + d = {} + # read in the config file + globs = {} + locs = {} + execfile(file, globs, locs) + for (k, v) in locs.items(): + if k == dictname: + d = v + break + dict2org(d) + self.orgspanel.orgs.UnselectAll() + self.SetTitle("ezPolicy: " + self.orgfilename) + self._ExpandAll(None) + + + def Save(self, file): + dictname = 'ezpolicy' + d = org2dict() + fd = open(file, "w") + fd.write(dictname + " = ") + fd.write(str(d)) + fd.close() + + + def New(self): + self.orgspanel.orgs.DeleteChildren(self.orgspanel.orgs.GetRootItem()) + self.conspanel.New() + + + def LabelReplaceInConflictsets(self, item, oldlabel, newlabel): + if isRealm(item): + replace = [[ oldlabel, newlabel]] + for i in iterchildren(item): + replace.append([(oldlabel + "." + self.orgs.GetItemText(i)), + (newlabel + "." + self.orgs.GetItemText(i))]) + else: + parent = self.orgs.GetItemParent(item) + replace = [ + [(self.orgs.GetItemText(parent) + "." + oldlabel), + (self.orgs.GetItemText(parent) + "." + newlabel)] + ] + for r in replace: + for i in self.conspanel.conflictsets: + if r[0] in i.GetTypes(): + i.Replace(r[0], r[1]) + + + def OrgDelItem(self, item): + label = self.orgs.GetItemText(item) + if isRealm(item): + delset = [label] + for i in iterchildren(item): + delset.append(label + "." + self.orgs.GetItemText(i)) + else: + parent = self.orgs.GetItemParent(item) + delset = [self.orgs.GetItemText(parent) + "." + label] + for i in self.conspanel.conflictsets: + for l in delset: + i.Delete(l) + #need to run in reverse order when deleting items + rev = [] + for i in self.conspanel.conflictsets: + rev.append(i) + rev.reverse() + for i in rev: + if len(i.GetTypes()) < 1: + self.conspanel.DelCSByItem(i) + self.orgs.Delete(item) + + + def _OnSashDrag(self, event): + if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE: + return + w = event.GetEventObject() + if w is self.conswin: + self.conswin.SetDefaultSize((event.GetDragRect().width, 1000)) + wx.LayoutAlgorithm().LayoutWindow(self.bkg, self.orgswin) + self.RefreshMe() + + + def _OnSize(self, event): + wx.LayoutAlgorithm().LayoutWindow(self.bkg, self.orgswin) + + + def _OrgSelectionChanged(self, event): + self.orgs.event = event + item = self.orgs.event.GetItem() + if not item.IsOk() or not self.orgs.IsSelected(item): + self.emenu.Enable(self.ID_ITRENAME, False) + self.emenu.Enable(self.ID_ITADD, False) + self.emenu.Enable(self.ID_ITDEL, False) + return + self.SetStatusText("") + #enable/disable edit menu functions + if isRealm(item): + self.emenu.Enable(self.ID_ITRENAME, True) + self.emenu.Enable(self.ID_ITADD, True) + self.emenu.Enable(self.ID_ITDEL, True) + elif isWorkload(item): + self.emenu.Enable(self.ID_ITRENAME, True) + self.emenu.Enable(self.ID_ITADD, False) + self.emenu.Enable(self.ID_ITDEL, True) + if len(self.orgs.GetSelections()) > 1: + self.emenu.Enable(self.ID_ITRENAME, False) + self.emenu.Enable(self.ID_ITADD, False) + + + def _OrgRightClick(self, event): + self.SetStatusText("") + self.orgs.event = event + item = self.orgs.event.GetItem() + #del not permitted on root items + if isWorkload(item): + self.workload_menu.Enable(self.ID_ORGDEL, True) + self.workload_menu.Enable(self.ID_ORGEDT, True) + if len(self.orgs.GetSelections()) > 1: + self.workload_menu.Enable(self.ID_ORGEDT, False) + self.PopupMenu(self.workload_menu) + else: + self.realm_menu.Enable(self.ID_ORGDEL, True) + self.realm_menu.Enable(self.ID_ORGEDT, True) + self.realm_menu.Enable(self.ID_ORGADD, True) + if len(self.orgs.GetSelections()) > 1: + self.realm_menu.Enable(self.ID_ORGEDT, False) + self.realm_menu.Enable(self.ID_ORGADD, False) + self.PopupMenu(self.realm_menu) + + + def _OpenSpec(self, event): + filediag = wx.FileDialog(self, defaultFile="myspec.wld", + wildcard="*.wld", style=wx.OPEN | wx.OVERWRITE_PROMPT, + message="Select Workload Definition file name") + ret = filediag.ShowModal() + name = filediag.GetPath() + filediag.Destroy() + if ret not in [wx.ID_OK]: + return + self.orgfilename = name + self.Load(self.orgfilename) + self.SetTitle("ezPolicy: " + self.orgfilename) + + + def _SaveSpec(self, event): + if not self.orgfilename: + filediag = wx.FileDialog(self, defaultFile="myspec.wld", + wildcard="*.wld", style=wx.SAVE | wx.OVERWRITE_PROMPT, + message="Select Workload Definition file name") + ret = filediag.ShowModal() + name = filediag.GetPath() + filediag.Destroy() + if ret not in [wx.ID_OK]: + return + self.orgfilename = name + self.Save(self.orgfilename) + self.SetTitle("ezPolicy: " + self.orgfilename) + + + def _SaveAsSpec(self, event): + if not self.orgfilename: + self.orgfilename = "DEFAULT.wld" + filediag = wx.FileDialog(self, defaultFile=self.orgfilename, + wildcard="*.wld", style=wx.SAVE | wx.OVERWRITE_PROMPT, + message="Select Workload Definition file name") + ret = filediag.ShowModal() + name = filediag.GetPath() + filediag.Destroy() + if ret not in [wx.ID_OK]: + return + self.orgfilename = name + self.Save(self.orgfilename) + self.SetTitle("ezPolicy: " + self.orgfilename) + + + def _NewSpec(self, event): + self.orgfilename = None + #reset trees etc + self.New() + self.SetTitle("ezPolicy: *New File*") + + + def _TranslateSpec(self, event): + policyname = transInfo() + if not policyname: + return + path="/etc/xen/acm-security/policies/" + nameparts=string.split(policyname, ".") + if len(nameparts) > 1: + path = path + "/".join(nameparts[0:len(nameparts)-1]) + deffile = nameparts[len(nameparts) - 1] + "-security_policy.xml" + filediag = wx.FileDialog(self, defaultDir=path, defaultFile=deffile, + wildcard="*.xml", message="Select Policy File Name", + style=wx.SAVE | wx.OVERWRITE_PROMPT) + ret = filediag.ShowModal() + filename = filediag.GetPath() + filediag.Destroy() + if ret not in [wx.ID_OK]: + return + #translate data into default policy + timestamp = time.asctime() + d = org2dict() + types = [] + for i in d['orgs']: + types.append(str(i[0])) + for j in i[1]: + types.append(str(i[0]) + "." + str(j)) + f = open(filename, "w") + printPolicyHeader (f, policyname, timestamp) + printPolicy(f, types, d['cons']) + printLabels(f, d, types)#, d['cons']) + printTrailer(f) + f.close() + + + def _ItemRename(self, event): + #ensure only 1 item is selected + sels = self.orgs.GetSelections() + if len(sels) != 1: + return + self.orgs.OrgEdt(sels[0]) + + + def _ItemAdd(self, event): + #ensure only 1 item is selected + add figure + sels = self.orgs.GetSelections() + if len(sels) != 1: + return + self.orgs.OrgWAdd(sels[0]) + + + def _ItemDel(self, event): + sels = self.orgs.GetSelections() + for i in sels: + self.OrgDelItem(i) + + + def _CollapseAll(self, event): + for i in iterchildren(self.orgs.GetRootItem()): + self.orgs.Collapse(i) + + + def _ExpandAll(self, event): + for i in iterchildren(self.orgs.GetRootItem()): + self.orgs.Expand(i) + + + def _SortAll(self, event): + #would be nice to also sort the organizations + for i in iterchildren(self.orgs.GetRootItem()): + if self.orgs.GetChildrenCount(i) > 0: + self.orgs.SortChildren(i) + + + def _OnAbout(self, event): + dlg = wx.MessageDialog(self, + "This program helps you to define the structure\n" + "of organizations and their departments.\n\n" + "It translates this \'Workload Definition\' into\n" + "a simple workload protection policy for the\n" + "Xen Access Control Module.\n\n\n" + "Copyright (c) 2006: IBM Corporation\n" + "Author:\nReiner Sailer ", + "About Me", wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + + def _Help(self, event): + hpopup = wx.Frame(self,-1, "HELP: Creating a Xen Security Policy in 3 Steps" ) + HelpHtmlWindow(hpopup, -1) + hpopup.SetSize((650,650)) + hpopup.Show(True) + + + def _TimeToQuit(self, event): + self.Bind(wx.EVT_CLOSE, None) + self.orgs.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, None) + self.orgs.Bind(wx.EVT_TREE_SEL_CHANGED, None) + self.Close(True) + + +class ezApp(wx.App): + + def OnInit(self): + self.win = ezFrame(None, -1, title="EZ Workload Protection Policy Tool") + self.win.Show(True) + self.SetTopWindow(self.win) + return True + + + def Load(self, file): + self.win.Load(file) + + + def New(self): + self.win.New() + + +def isRealm(it): + if not it: + return False + return (app.win.orgspanel.orgs.GetItemParent(it) == app.win.orgspanel.orgs.GetRootItem()) + + +def isWorkload(it): + if not it or not app.win.orgs.GetItemParent(it): + return False + return (app.win.orgspanel.orgs.GetItemParent(app.win.orgspanel.orgs.GetItemParent(it)) + == app.win.orgspanel.orgs.GetRootItem()) + + +def GetOrgsSelection(): + return (app.win.orgspanel.orgs, app.win.orgspanel.orgs.GetSelections()) + + +def transInfo(): + info = wx.TextEntryDialog(app.win, message="POLICYNAME", + caption="Translate: Creating The Xen/ACM Policy") + ret = info.ShowModal() + name = info.GetValue() + info.Destroy() + if ret in [wx.ID_OK]: + return name + return None + + +def iterchildren(node): + cid, citem = app.win.orgspanel.orgs.GetFirstChild(node) + while cid.IsOk(): + yield cid + cid, citem = app.win.orgspanel.orgs.GetNextChild(node, citem) + + +def dict2org(d): + # release old structure + app.New() + # fill them with dict content + for i in d['orgs']: + orgnode = app.win.orgspanel.orgs.AppendItem(app.win.orgspanel.orgs.GetRootItem(), text=i[0]) + app.win.orgspanel.orgs.SetItemBold(orgnode, True) + app.win.orgspanel.orgs.SetItemImage(orgnode, realm_icon, wx.TreeItemIcon_Normal) + for j in i[1]: + wlnode = app.win.orgspanel.orgs.AppendItem(orgnode, text=j) + app.win.orgspanel.orgs.SetItemImage(wlnode, workload_icon, wx.TreeItemIcon_Normal) + for i in d['cons']: + app.win.conspanel.AddConflict(i[0], i[1]) + + +def org2dict(): + global app + dic = {} + o= [] + for i in iterchildren(app.win.orgs.GetRootItem()): + d = [] + for j in iterchildren(i): + d.append(str(app.win.orgspanel.orgs.GetItemText(j))) + o.append([str(app.win.orgspanel.orgs.GetItemText(i)) , d]) + dic['orgs'] = o + c=[] + for i in app.win.conspanel.conflictsets: + c.append([i.GetBoxName() , i.GetTypes()]) + dic['cons'] = c + return dic + + +def dict_read(dictname, filename): + """Loads and returns the dictionary named from + the file. + """ + dic = {} + + # read in the config file + globs = {} + locs = {} + execfile(filename, globs, locs) + + for (k, v) in locs.items(): + if k == dictname: + dic = v + break + return dic + +#==================== Policy Generation/Translation functions + +def printPolicyHeader (fd, policyname, timestamp): + fd.write( """ + + + + %s + %s + +""" % (policyname, timestamp)) + + + +def printPolicy(fd, types, cons): + fd.write(""" + + + SystemManagement\n""") + + # add dynamically created type definitions org.dept + for i in types: + fd.write(""" %s\n""" % i) + + fd.write(""" + + + + + SystemManagement\n""") + + #add dinamically created cw types + for i in types: + fd.write(""" %s\n""" % i) + + fd.write(""" \n\n""") + + if len(cons): + fd.write(""" \n""") + for i in cons: + if len(i[1]) < 2: + print "Ignoring Run-time exclusion set %s (less than 2 types}" % i[0] + continue + #name is optional but must be set + if i[0]: + rer_name = str(i[0]) + else: + rer_name = str("RER") + fd.write(""" \n""" % rer_name) + for j in i[1]: + fd.write(""" %s\n""" % str(j)) + fd.write(""" \n""") + fd.write(""" \n""") + + fd.write(""" \n\n""") + + + +def printLabels(fd, d, types): #, cons): + fd.write( """ + """) + + # create default boot label for dom0 + fd.write("""\n + SystemManagement + + SystemManagement\n""") + # add dynamically created type definitions org.dept + for i in types: + fd.write(""" %s\n""" % i) + + fd.write(""" + + SystemManagement + + \n""") + + # create one Udom label for each type ste type + for i in d['orgs']: + organization = i[0] + fd.write("""\n + %s + + %s + + + %s + + \n""" % (organization, organization, organization)) + for j in i[1]: + workload = organization + "." + j + fd.write("""\n + %s + + %s + + + %s + %s + + \n""" % (workload, workload, organization , workload)) + + fd.write(""" \n\n""") + + #create resource labels for each type + fd.write(""" """) + for i in ['SystemManagement'] + types: + fd.write("""\n + %s + + %s + + \n""" % (i, i)) + fd.write(""" + \n""") + +def printTrailer(fd): + fd.write( """\n""") + +#============== the icons/bitmaps ====================================== +# to ensure the program runs anywhere, we include the buttons right here +# while this makes the file even bigger, it also makes it easier to use +import cStringIO + +def GetIconBitmap(name): + return wx.BitmapFromImage(GetIconImage(name)) + +def GetIconImage(name): + if name == 'Organization': + iostream = cStringIO.StringIO(GetOrganizationIconData()) + elif name == 'Department': + iostream = cStringIO.StringIO(GetDepartmentIconData()) + elif name == 'Conflict': + iostream = cStringIO.StringIO(GetConflictIconData()) + else: + sys.exit("UNKNOWN ICON NAME") + return wx.ImageFromStream(iostream) + +def GetOrganizationIconData(): + return \ +'\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\ +\x00\x00\x00\x10\x00\x00\x00\x11\x08\x02\x00\x00\x00\x5b\xcd\xbb\ +\x93\x00\x00\x00\x03\x73\x42\x49\x54\x08\x08\x08\xdb\xe1\x4f\xe0\ +\x00\x00\x02\x7b\x49\x44\x41\x54\x28\x91\x5d\xd1\xcb\x4f\x13\x51\ +\x14\x06\xf0\x73\x1f\x74\x3a\x33\x9d\x96\x87\x0a\x14\x30\x3c\xd4\ +\x60\x34\xf1\xb1\x70\xa5\x26\x2e\xfc\x87\x4d\xdc\x18\x17\x26\x08\ +\x26\x44\x01\xc1\x07\x10\x52\x1e\x96\xb6\x94\x4a\x87\x0e\x33\x73\ +\xef\xdc\x7b\xcf\x71\x01\x31\x81\x6f\x73\x36\xe7\xb7\xf8\xf2\x31\ +\x22\x82\xab\x50\x51\x68\xa5\xd2\x6e\x77\xbf\xdd\xf8\x36\x52\x1b\ +\x5f\x78\xfc\xc6\x0f\x6b\x70\x3d\xf2\xea\x97\x28\x8e\xbb\xfd\x7e\ +\xd7\xb9\xb4\x3e\xe9\xe3\x99\x1d\x34\x3f\x34\xb9\xaa\x2f\xbe\x0d\ +\x2a\xa3\x8c\xb1\xff\x80\x5f\x1e\x63\x4c\x9a\x1e\x23\xaa\x24\xd1\ +\x8c\x91\xe0\xae\x04\xb1\xed\x7e\x6a\xff\x7e\x7f\x11\xb7\x01\xe8\ +\x26\x90\x52\x02\x98\x30\xac\xf8\x7e\x95\x88\x13\x5a\x0e\x4e\xe0\ +\xb9\xe9\x6f\xf5\xbb\x87\x5a\x17\x37\x01\xe7\x1c\x00\x38\x37\x9e\ +\x87\x9c\x91\xb3\xce\x21\x2f\xc8\x4b\xac\xec\xf5\xf6\x76\xd7\xdf\ +\xa9\x6c\x70\xad\x03\x00\x30\xc6\x6b\x35\x19\x86\x5c\x48\x42\x59\ +\x71\xd1\x3d\x88\x26\x82\x68\x8a\xf4\xa0\x68\x7f\x69\xed\xc0\x9d\ +\xb9\xd7\x41\xf5\xf6\x15\x50\x2a\x07\x60\xe5\xb2\x04\x00\x6b\x1d\ +\x56\x67\x71\x68\xbc\x67\x43\xe3\xa2\x49\x8c\xcb\x10\xe7\xad\xa5\ +\x53\x80\x5b\xb3\xaf\xa4\x52\x79\x9e\x0f\x8c\x4d\x01\xdc\x25\xb6\ +\x08\x27\x38\xaa\xb9\x3b\x4a\xb4\x13\x30\x02\x69\xc0\x1c\xc7\x9e\ +\xea\x2c\x1f\x1b\x23\x9b\xad\x46\xaa\xce\x53\x60\x7e\x09\xa7\x2e\ +\x81\xc3\xf6\x05\x58\xc7\x12\x2c\x45\x1e\x17\x45\xce\x19\x32\x42\ +\x61\xbb\x67\xad\x75\x79\xd0\x69\x9f\x23\x0e\xc0\x1f\x2e\xb3\x67\ +\x00\x00\x80\x04\x85\x25\x72\x56\x7a\xa1\xc7\x32\x61\x33\xb8\x1a\ +\x97\xca\xc1\xa8\x74\xa2\xd2\xd3\x8a\x0b\xc8\x0c\x68\xa5\x8c\xb1\ +\x8e\x0d\x21\x22\x3a\xc7\x3c\xe9\x51\x21\x51\x01\x21\x00\x38\xe4\ +\x95\xb1\xfb\x7c\xb8\x12\x0a\x00\xb2\x46\x19\x6c\xfd\x39\xdc\xda\ +\xda\x56\xca\x5c\x6e\x6f\xb4\x4e\xe2\x93\xbf\x49\xac\x8d\x23\x00\ +\xc7\x82\x70\x64\x5a\xd6\xc2\x00\x6d\x47\x08\x40\x12\x8d\x9d\x5f\ +\x5f\x77\xe2\xdb\x33\x73\x51\x89\x98\x60\x71\xaf\xf9\xf3\x70\xa5\ +\x99\x1c\x3c\x19\xe3\xf5\x9a\x57\x1d\x1e\xf5\x82\x31\x59\xe8\x84\ +\x9b\x6c\x38\x08\x98\xc7\xb2\x76\x7a\xd2\xcf\x38\xc0\xf3\x49\xe6\ +\x97\x82\xc1\xc9\xd2\x86\x5b\xdf\x3f\x75\x8d\x01\x3d\xb9\x55\x79\ +\x51\xf2\x26\x84\x2f\x3f\xaf\x7d\x0c\xfd\xe0\xe9\xdd\xa7\xbe\x70\ +\xdb\x1d\x1f\x31\x16\x9c\xcd\x4f\x8d\x29\xad\x3b\x71\x13\x88\x72\ +\x8d\x22\xa2\x8d\x63\xdd\xef\x37\xa2\xf9\x16\xdf\x6d\x6f\x4a\x91\ +\xf9\x43\xae\x1a\xf9\x82\x0b\x21\xf8\x45\x9a\x69\x5d\x74\xba\xa7\ +\x44\x90\xb7\x1c\x9d\x1b\x8c\x2d\xa5\xf4\xeb\xa8\xb9\x77\xb4\x2f\ +\x1f\xd5\x17\xbf\x6f\xad\x2d\xaf\xad\x3e\x9c\x78\x50\xaf\x08\xa5\ +\xcc\xee\xee\xfe\x4e\x63\x73\xe5\xc7\xea\x41\xe3\xf8\x0e\x8a\x97\ +\xf7\x66\x92\x3c\xa9\x4f\x4f\x64\xa5\xb9\x87\x0b\x8b\xff\x00\x63\ +\xce\x84\xe6\xf7\x5b\x7e\xce\x00\x00\x00\x00\x49\x45\x4e\x44\xae\ +\x42\x60\x82' + +def GetDepartmentIconData(): + return \ +'\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\ +\x00\x00\x00\x10\x00\x00\x00\x11\x08\x06\x00\x00\x00\xd4\xaf\x2c\ +\xc4\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\ +\x88\x00\x00\x01\x52\x49\x44\x41\x54\x38\x8d\xd5\x92\x3d\x4b\x42\ +\x61\x18\x86\xaf\xf3\xfa\xfa\x81\xa9\x58\x48\x60\x08\x49\xd2\x26\ +\xb4\x37\x4a\x14\x6d\x6d\x42\x42\x7f\x20\x68\xae\x31\x28\xff\x85\ +\x83\xd0\x90\x05\x0d\x6d\x0d\xd2\x2a\x89\x24\x48\xb8\x85\x49\x1a\ +\x48\x87\xd4\xca\x93\xbe\xd4\x69\x38\x39\x1c\xa8\x34\x1a\xa2\x7b\ +\xbb\x79\xb8\xaf\x87\xe7\x43\x0b\x2f\x6c\xad\x05\x23\x4b\x39\x4d\ +\x38\x5d\xe6\xdb\x80\x9b\xab\xd3\x7a\xaf\x96\x99\x65\x4c\xc9\xfb\ +\x97\xd9\xdc\x43\xb3\xef\x82\x3e\xaf\xc6\x2d\x4a\x9b\x33\xc7\x0d\ +\x03\x48\x25\xa3\x4e\x25\x86\x0d\x0d\xbc\x8e\x8e\xff\x28\x95\x3a\ +\x70\x08\x21\x01\x0e\xcb\xe5\x5a\xb6\x52\xd9\xfe\x12\x60\x73\xa6\ +\x62\x7f\xae\x3a\x15\xf5\xf8\x52\x00\x8d\x6e\x97\xc5\x40\xe0\x32\ +\x0b\xdb\x00\x3e\x9f\xf0\xa4\xd3\x33\x9b\x5e\xaf\x70\x01\xe4\xf3\ +\x9d\xb6\x1d\xf0\xd6\x67\x3d\xe4\x60\xfa\xc3\xb6\x0d\x03\xb7\x10\ +\xc3\xaa\xd8\xd9\x99\x3c\x49\x24\x3c\xab\x00\xdd\xae\xc2\x30\x1e\ +\xaf\xed\x80\xef\xe5\x4e\x26\xf5\x95\x58\x4c\x07\xa0\x50\x80\x60\ +\x10\xc4\x88\xd0\x48\xfd\x1a\x30\x72\x84\x62\x24\x12\x9b\xdf\xdd\ +\x3d\x33\x95\x12\x26\x7b\xda\x8f\x00\xe7\x42\x70\x1c\x8f\x07\x34\ +\x29\x97\x91\x12\xd0\x00\xfb\x9b\x7c\x0b\xd0\xc3\x61\x5a\xa1\x90\ +\x65\x06\x03\xcc\x4f\x5e\xec\xef\x97\xf8\xcf\x01\x4f\x4f\xd4\x25\ +\xbd\xea\x05\x4a\xb7\xee\xdb\xab\x3e\x17\x5a\xad\x89\xa0\xdb\x0d\ +\x40\x43\x08\x0d\xbf\xdf\xda\xbd\x52\x14\x8b\x26\x77\x4d\x2b\x5c\ +\x2a\xa1\x67\x32\x6c\xbc\x03\x17\xdb\x6e\x97\x68\x69\xf7\x4f\x00\ +\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82' + +def GetConflictIconData(): + return \ +'\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\ +\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\x00\x00\x00\x90\x91\x68\ +\x36\x00\x00\x00\x03\x73\x42\x49\x54\x08\x08\x08\xdb\xe1\x4f\xe0\ +\x00\x00\x02\x45\x49\x44\x41\x54\x28\x91\x6d\x92\x4f\x48\x9a\x71\ +\x18\xc7\x7f\xbe\xef\xab\xcd\xed\x95\xcd\x8c\x25\x83\xc0\x24\xa9\ +\xc3\x4a\x17\xce\xea\x96\x3b\xe4\x0e\x5d\xba\xce\xa8\x88\xe8\x20\ +\x1a\x15\x1d\x3a\x78\x09\xf2\xed\xcf\xe8\x32\x68\x45\x56\x93\x66\ +\x94\x78\x99\x53\x68\x4e\x1b\xe1\x61\x30\xc2\x19\x5b\x16\xac\x9c\ +\x76\x19\x92\x2e\x35\xa6\x7b\xf7\xda\xfb\x3e\x3b\xd8\x9c\x9b\x7e\ +\x8e\xdf\xdf\xf3\x81\xdf\xf3\x87\x07\x00\xe8\x0f\x99\xb3\xb3\xd0\ +\xca\xca\x17\x97\x2b\x75\x7a\x8a\xf1\xf9\x77\xea\xeb\xe5\x3a\xdd\ +\x83\xe1\xe1\x6a\x85\xa2\x58\xc3\x2b\x08\x5c\x3e\x1f\x98\x9a\xfa\ +\xb0\xb0\x80\xf3\xf9\x72\x9d\xae\x56\xa5\xe2\x58\x36\x13\x8b\x9d\ +\xb8\xdd\x3f\x2f\x2e\x1e\x8e\x8c\x3c\x9a\x9d\xc5\xab\xaa\x10\x42\ +\x08\x00\x38\x96\x75\xf6\xf4\x58\x78\xbc\x37\x46\x23\x9d\x4e\x43\ +\x09\x57\x34\xfd\x7e\x6e\x6e\x4e\x28\xb4\x6b\xb5\x2c\xc3\x00\x00\ +\x02\x80\x77\x93\x93\xd3\x08\x51\x04\x71\xec\x74\x42\x25\xbe\xfa\ +\x7c\xf3\x24\xb9\x63\x30\x00\x00\x4a\x45\x22\x33\x02\x81\xd7\x64\ +\x5a\x69\x6e\x9e\xe1\xf3\x8f\x1c\x8e\x8a\xce\xc7\xe5\x65\x0b\x86\ +\x7d\xdb\xdf\x47\xfe\x89\x89\xa7\x22\xd1\xaf\xcb\xcb\x6c\x22\x61\ +\x55\x2a\x29\x82\x08\x6f\x6d\x95\x0b\x1c\xcb\x3e\x57\x28\x3c\x43\ +\x43\x68\x5d\xa3\x71\x74\x77\x17\xd2\x5c\x32\x69\x55\xa9\x28\x82\ +\x38\xdc\xdc\x2c\x77\xbc\x26\xd3\xb3\xba\x3a\xec\xfb\xf1\xb1\xb8\ +\xa1\xa1\x30\x32\xa1\x44\xa2\xdf\xdd\xbd\xdb\xd2\xf2\xba\xbf\xff\ +\xd0\x6e\x47\xff\x22\x69\x6a\xfa\x11\x8f\x63\x1c\xcb\xb2\x0c\x53\ +\x4c\x85\xd5\xd5\x7a\xbf\xbf\x56\xa9\x74\x0f\x0c\x7c\xde\xd8\x28\ +\x15\x80\xe3\x80\xe3\xb0\xdb\x32\x59\x26\x1a\x2d\x7d\xb8\x21\x16\ +\x3f\xf1\xf9\xa4\xad\xad\x9e\xc1\xc1\x4f\x36\x5b\x31\x4f\x47\xa3\ +\xa4\x54\x8a\x7c\xe3\xe3\xf3\x24\x99\x4b\x26\xff\xfb\x31\x9d\x4a\ +\xad\x6b\x34\x14\x8e\x1f\xac\xad\x15\x9a\x5e\x6a\x6c\x74\xf5\xf5\ +\xa1\x44\x38\x4c\xe1\xf8\xdb\xd1\xd1\xf2\x2e\xe9\x74\xfa\x45\x7b\ +\xbb\x05\xc3\x42\x56\x6b\x70\x69\xc9\xc2\xe3\x9d\x05\x02\x08\x00\ +\x76\x0c\x06\x8a\x20\xc2\xdb\xdb\x15\x9c\x4c\xc6\xd6\xd1\x61\xc1\ +\xb0\x79\x92\x7c\xa5\xd7\x5f\x6f\x9a\x65\x98\x97\x9d\x9d\x14\x8e\ +\xef\x99\xcd\x57\x34\x5d\x2a\xb0\x0c\xb3\x67\x36\x4f\x23\xb4\xae\ +\x56\xe7\x73\x39\x00\xb8\x3e\xbe\x7c\x2e\xe7\x1b\x1b\x3b\x58\x5d\ +\xbd\x59\x53\x23\xef\xea\x2a\x0c\x3a\x13\x8b\x45\xbc\xde\x6c\x3c\ +\x7e\xbf\xb7\xf7\xf1\xe2\xa2\x40\x24\xfa\x7b\xad\x05\xe2\xc1\x60\ +\xc8\x6a\x3d\xf1\x78\xb2\xe7\xe7\x88\xe3\x6e\x49\xa5\x32\xad\x56\ +\x6d\x34\xde\x6b\x6b\x2b\xd6\xfc\x06\xb3\xcb\xb3\xdb\x2f\x3f\x31\ +\xa9\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82' + +#=============== help texts + +NewRealmButtonHelp = \ + "Use this button to add a new top-level REALM type. \n\n\ +You can refine an existing realm by right-clicking it \ +and selecting \"Add workload\" from the pop-up menu.\n\n-h for help" + +RealmWorkloadPanelHelp = \ + "\ +Use this panel to define names for types of workloads that \ +shall be confined against each other.\n\n-h for help" + +RunTimeExclusionPanelHelp = \ + "\ +The run-time exclusion rules restrict which workload types \ +can run simultaneously on the same platform. At most one \ +type in an exclusion rule can run. If a domain starts, its \ +workload type is looked up and if it is in any exclusion rule \ +of which another type is already running, then it is denied \ +to start.\n\n-h for help" + +CreateRunTimeButtonHelp = \ + "\ +This button creates a new run-time exclusion rule using the \ +selection from the left side workload definition panel.\n\n-h for help" + +AddToExclusionButtonHelp = \ + "\ +This button adds the current selection in the left side \ +workload definition panel to the associated exclusion rule.\n\n-h for help" + +DelFromExclusionButtonHelp = \ + "\ +This button deletes the current selection of the associated \ +exclusion rule from the associated exclusion rule.\n\n-h for help" + +ManageExclusionButtonHelp = \ + "\ +This button allows to rename or delete the associated exclusion \ +rule. Left-click the button for the menu.\n\n-h for help" + +ExclusionSetHelp = \ + "\ +Of the workload types specified in an exclusion rule, \ +only one can run at a time on the same platform.\n\n-h for help" + +GetHelp = \ + "\ +Use -h to open the help window. Use the context help on buttons." + +#================ html help page ================= +# for ez use included in a single file, one could also +# optionally try to fetch the page from a public location +import wx.html as html + +class HelpHtmlWindow(html.HtmlWindow): + def __init__(self, parent, id): + html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE) + if "gtk2" in wx.PlatformInfo: + self.SetStandardFonts() + self.SetPage(helptext) + +helptext = """ + + + + + +Overview + + +

Creating A Xen Workload-Protection Security Policy

+The purpose of this tool is to create a Xen security policy that understands +the workload types that you want to confine against each other. For this +purpose you enter the names of workload types that you want to assign to +domains and resources. You can also define groups of workload types that +should not run on the same system simultaneously for any reason; such groups +are called Runtime Exclusion Sets. Please refer to the Xen User Guide for +more information.
+
+This tool will create a unique security label for each workload type. Every +domain and resource must be labeled so that the hypervisor system can correctly +identify the associated workload type and control the sharing among domains +in a way that keeps different workload types confined from each other. +This tool ensures two things:
+
+1. The created security policy includes a distinctive label for each workload +type defined in step 1 below. These labels must later be assigned to Domains +and Resources to enable Xen to enforce the confinement.
+
+2. The created security policy includes access control rules that are enforced +by the Xen Hypervisor (independently of the guest Domains) and guarantee +that:
+
(i) Domains that are assigned the same workload type label can +share (communicate, +use common resources) without restriction through the hypervisor. Their +interoperation can still be constraint by the domains (domain-internal +means).
+
(ii) Domains that are assigned different workload type labels cannot share, +i.e., cannot communicate or use common resources. Independently enforced +by the hypervisor, the domains cannot overrule this decision.
+
(iii) Once a Domain labeled with a workload type of a Runtime Exclusion +Rule is running, no other domain labeled with another workload type of +the same Runtime Exclusion Rule can start. This holds for all Runtime Exclusion +Rules.
+While all workloads share common hardware resources, the core hypervisor +isolation and virtualization in combination with the Xen access control +policy ensure that, e.g., viruses in one workload type cannot infect other +workload types and that secrets used within one workload type cannot leak +into another workload type. Currently the Xen access control enforcement +covers domains, local storage resources, and the local virtual network +interfaces. Protecting sharing through the open network is subject of ongoing +work; such protection must currently be setup manually using IP filtering +rules in Domain0. +
+
+

Step 1

+The first step of creating a workload protection policy is to determine +names for the different workload types. The left panel offers the means +to define and and manage workload type definitions.
+
+A workload can be an organization name (coarse-grained type), e.g. a corporate +realm such as IBM or PepsiCo. An organization can be refined to describe +independent functional groupings within the organization, such as IBM.Financing +or Pepsi.Payroll. Use the <New Org> button on the left panel +to create a new organization workload. To refine such a workload, right-click the +organization and chose <Add Department>. You can add multiple +departments to an organization but you do not have to add any.
+
+This tool will create a separate label name for each organization and for +each department workload. The policy will be computed so that there is +no sharing between organizations or departments by default. IBM, IBM.Financing, +Pepsi, and Pepsi.Payroll will by default not be able to share in this simple +policy example. You can introduce controlled sharing by refining the policy, +which is beyond the scope of this help.
+
+As an example, define the four organizations PepsiCo, CocaCola, Avis, Hertz. +Define department workloads Payroll, HumanResources and Financing for Avis +and CocaCola, and PepsiCo.
+
+

Step 2

+In this second step, we enter those workload types that should not run +simultaneously on the same hardware platform. There might be multiple reasons +for this, e.g., imperfect resource control.
+
+As an example, we will create a policy that guarantees that PepsiCo workloads +and CocaCola workloads never run simultaneously on the same platform:
+
+1. Select the PepsiCo organization on the left panel by left-clicking it..
+
+2. Press the <Ctrl>-Key and then select CocaCola organization by +left-clicking it while keeping the <Ctrl>-Key pressed..
+
+3. Click the <Create run-time exclusion rule from selection> +button and enter a name for this Run-time Exclusion rule (e.g., RER1). The name is +for your reference only. It has no impact on the policy. On the right panel, a run-time +exclusion rule with the chosen name appears.
+
+The interpretation of the rule is as follows: If a domain labeled PepsiCo +is running, then another domain labeled CocaCola cannot start on the same +system and the other way round. This also holds for departments of PepsiCo +and CocaCola (organizations dominate their departments). If PepsiCo or +PepsiCo.Payroll etc. are running, then a domain with label CocaCola or +CocaCola.Payroll etc. cannot start. If you want to restrict concurrency +between specific subtypes, then you must create a Run-time Exclusion rule +that specifies the department workload types. To exclude only CocaCola.Payroll +and PepsiCo.Payroll from running simultaneously the Run-time Exclusion +rule must be formed using Coca.Cola.Payroll and PepsiCo.Payroll, not their +organizations. Consequently it does not make sense to add both an organization +and any of its departments to the same Run-time Exclusion rule because +any department is already covered by its organization (this tool will not +allow it).
+
+You can create multiple Run-time Exclusion rules, all of which will be +enforced simultaneously by the hypervisor. You do not need to define any +Run-time Exclusion rule if you do not find it necessary. You can add or +delete workload types from Run-time Exclusion rules using the <Add> +and <Del> buttons associated with the rule. The <Add> +button adds the workload types selected in the left panel to the Run-time +Exclusion rule. The <Del> button deletes the workload types selected +in the associated Run-time Exclusion rule from the rule.
+
+

Step 3

+Now that we have defined the workloads and Run-time Exclusion rules, we +can save the workload definition for later reference or refinement. Select +the File->Save Workload +Definition as.. menu entry and choose a file name.
+
+Please use the File->Save as Xen ACM Security Policy.. menu entry and choose a policy +name to create a Xen Workload Protection +security policy from the current workload definition. To simplify the succeeding +steps, please use a name of the form "example.chwall_ste.NAME" +where you merely replace "NAME" with a policy name of your choice. +Save the policy under the name proposed by the tool in the proposed directory +if you are using this tool in your Xen environment. Otherwise, you need +to copy the resulting file into your Xen environment to the directory +"/etc/xen/acm-security/policies/example/chwall_ste/".
+
+This tool creates policies for the Xen Chinese Wall and Simple Type Enforcement +policy. The Xen access control policy in general is more expressive and +this tool only uses a small subset of the possible configurations.
+
+Where to go from here.

+
+Before the new policy can be activated, we need to translate the policy into a representation that +Xen and the Xen-tools can work with. To this end, in your Xen environment, please issue the command +xm makepolicy example.chwall_ste.NAME where NAME must be replaced by the name you chose +for your policy in step 3 above. Then, we need to make the policy available to the Xen hypervisor. In +your Xen environment, please issue the command xm cfgbootpolicy example.chwall_ste.NAME +to install the policy for the next reboot. If the command cannot find the correct boot title, then you +can manually install it as described in the xm man page.
+
+Finally, reboot your security-enabled Xen environment. Please refer to the xm man page for how to enable +Xen security. After reboot, you can use xm labels type=any to list all the created workload l +abels. Use the xm addlabel command to assign workload type labels to the associated domains +and resources.
+
+From here, please check the Xen user guide.
+
+ +""" + +#=============== main ===== + +def main(): + global app + app = ezApp(0) + if len(sys.argv) in [2]: + app.Load(sys.argv[1]) + app.MainLoop() + print "Goodbye" + +if __name__ == '__main__': + main() + +#==== end of file From 0434f44fcd71e71ab93df1a90109357d5d6c6e65 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 11:54:45 +0100 Subject: [PATCH 031/111] [NET] Enable TCPv4 segmentation offload in front/back drivers. Signed-off-by: Keir Fraser --- .../drivers/xen/netback/netback.c | 17 ++++++++++++----- .../drivers/xen/netback/xenbus.c | 4 ---- .../drivers/xen/netfront/netfront.c | 4 ---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 82832368b9..4de5a9cb0b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -221,13 +221,20 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb) return NULL; } +static inline int netbk_max_required_rx_slots(netif_t *netif) +{ + if (netif->features & (NETIF_F_SG|NETIF_F_TSO)) + return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */ + return 1; /* all in one */ +} + static inline int netbk_queue_full(netif_t *netif) { - RING_IDX peek = netif->rx_req_cons_peek; + RING_IDX peek = netif->rx_req_cons_peek; + RING_IDX needed = netbk_max_required_rx_slots(netif); - return ((netif->rx.sring->req_prod - peek) <= (MAX_SKB_FRAGS + 1)) || - ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) <= - (MAX_SKB_FRAGS + 1)); + return ((netif->rx.sring->req_prod - peek) < needed) || + ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed); } int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -271,7 +278,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) if (netbk_can_queue(dev) && netbk_queue_full(netif)) { netif->rx.sring->req_event = netif->rx_req_cons_peek + - MAX_SKB_FRAGS + 2; + netbk_max_required_rx_slots(netif); mb(); /* request notification /then/ check & stop the queue */ if (netbk_queue_full(netif)) netif_stop_queue(dev); diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c index eb51533942..0d34bc8511 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @@ -101,14 +101,12 @@ static int netback_probe(struct xenbus_device *dev, goto abort_transaction; } -#if 0 /* KAF: After the protocol is finalised. */ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); if (err) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } -#endif err = xenbus_transaction_end(xbt, 0); } while (err == -EAGAIN); @@ -384,7 +382,6 @@ static int connect_rings(struct backend_info *be) be->netif->dev->features |= NETIF_F_SG; } -#if 0 /* KAF: After the protocol is finalised. */ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d", &val) < 0) val = 0; @@ -392,7 +389,6 @@ static int connect_rings(struct backend_info *be) be->netif->features |= NETIF_F_TSO; be->netif->dev->features |= NETIF_F_TSO; } -#endif /* Map the shared frame, irq etc. */ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn); diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 9ab89571de..3be2e87a7c 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -338,13 +338,11 @@ again: goto abort_transaction; } -#if 0 /* KAF: After the protocol is finalised. */ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); if (err) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } -#endif err = xenbus_transaction_end(xbt, 0); if (err) { @@ -1327,9 +1325,7 @@ static int xennet_set_tso(struct net_device *dev, u32 data) if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-gso-tcpv4", "%d", &val) < 0) val = 0; -#if 0 /* KAF: After the protocol is finalised. */ if (!val) -#endif return -ENOSYS; } From 9212caa7a4c750a9aad9a58e4b4fe4fef7e13b8b Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Tue, 1 Aug 2006 14:34:18 +0100 Subject: [PATCH 032/111] Rename all the CVS directories to .CVS. We want to keep the references to upstream QEMU, but they can be confusing when they are called CVS. Signed-off-by: Ewan Mellor --- tools/ioemu/{CVS => .CVS}/Entries | 0 tools/ioemu/{CVS => .CVS}/Repository | 0 tools/ioemu/{CVS => .CVS}/Root | 0 tools/ioemu/{CVS => .CVS}/Tag | 0 tools/ioemu/audio/{CVS => .CVS}/Entries | 0 tools/ioemu/audio/{CVS => .CVS}/Repository | 0 tools/ioemu/audio/{CVS => .CVS}/Root | 0 tools/ioemu/audio/{CVS => .CVS}/Tag | 0 tools/ioemu/fpu/{CVS => .CVS}/Entries | 0 tools/ioemu/fpu/{CVS => .CVS}/Repository | 0 tools/ioemu/fpu/{CVS => .CVS}/Root | 0 tools/ioemu/fpu/{CVS => .CVS}/Tag | 0 tools/ioemu/hw/{CVS => .CVS}/Entries | 0 tools/ioemu/hw/{CVS => .CVS}/Repository | 0 tools/ioemu/hw/{CVS => .CVS}/Root | 0 tools/ioemu/hw/{CVS => .CVS}/Tag | 0 tools/ioemu/keymaps/{CVS => .CVS}/Entries | 0 tools/ioemu/keymaps/{CVS => .CVS}/Repository | 0 tools/ioemu/keymaps/{CVS => .CVS}/Root | 0 tools/ioemu/keymaps/{CVS => .CVS}/Tag | 0 tools/ioemu/pc-bios/{CVS => .CVS}/Entries | 0 tools/ioemu/pc-bios/{CVS => .CVS}/Repository | 0 tools/ioemu/pc-bios/{CVS => .CVS}/Root | 0 tools/ioemu/pc-bios/{CVS => .CVS}/Tag | 0 tools/ioemu/target-i386/{CVS => .CVS}/Entries | 0 tools/ioemu/target-i386/{CVS => .CVS}/Repository | 0 tools/ioemu/target-i386/{CVS => .CVS}/Root | 0 tools/ioemu/target-i386/{CVS => .CVS}/Tag | 0 tools/ioemu/tests/{CVS => .CVS}/Entries | 0 tools/ioemu/tests/{CVS => .CVS}/Repository | 0 tools/ioemu/tests/{CVS => .CVS}/Root | 0 tools/ioemu/tests/{CVS => .CVS}/Tag | 0 32 files changed, 0 insertions(+), 0 deletions(-) rename tools/ioemu/{CVS => .CVS}/Entries (100%) rename tools/ioemu/{CVS => .CVS}/Repository (100%) rename tools/ioemu/{CVS => .CVS}/Root (100%) rename tools/ioemu/{CVS => .CVS}/Tag (100%) rename tools/ioemu/audio/{CVS => .CVS}/Entries (100%) rename tools/ioemu/audio/{CVS => .CVS}/Repository (100%) rename tools/ioemu/audio/{CVS => .CVS}/Root (100%) rename tools/ioemu/audio/{CVS => .CVS}/Tag (100%) rename tools/ioemu/fpu/{CVS => .CVS}/Entries (100%) rename tools/ioemu/fpu/{CVS => .CVS}/Repository (100%) rename tools/ioemu/fpu/{CVS => .CVS}/Root (100%) rename tools/ioemu/fpu/{CVS => .CVS}/Tag (100%) rename tools/ioemu/hw/{CVS => .CVS}/Entries (100%) rename tools/ioemu/hw/{CVS => .CVS}/Repository (100%) rename tools/ioemu/hw/{CVS => .CVS}/Root (100%) rename tools/ioemu/hw/{CVS => .CVS}/Tag (100%) rename tools/ioemu/keymaps/{CVS => .CVS}/Entries (100%) rename tools/ioemu/keymaps/{CVS => .CVS}/Repository (100%) rename tools/ioemu/keymaps/{CVS => .CVS}/Root (100%) rename tools/ioemu/keymaps/{CVS => .CVS}/Tag (100%) rename tools/ioemu/pc-bios/{CVS => .CVS}/Entries (100%) rename tools/ioemu/pc-bios/{CVS => .CVS}/Repository (100%) rename tools/ioemu/pc-bios/{CVS => .CVS}/Root (100%) rename tools/ioemu/pc-bios/{CVS => .CVS}/Tag (100%) rename tools/ioemu/target-i386/{CVS => .CVS}/Entries (100%) rename tools/ioemu/target-i386/{CVS => .CVS}/Repository (100%) rename tools/ioemu/target-i386/{CVS => .CVS}/Root (100%) rename tools/ioemu/target-i386/{CVS => .CVS}/Tag (100%) rename tools/ioemu/tests/{CVS => .CVS}/Entries (100%) rename tools/ioemu/tests/{CVS => .CVS}/Repository (100%) rename tools/ioemu/tests/{CVS => .CVS}/Root (100%) rename tools/ioemu/tests/{CVS => .CVS}/Tag (100%) diff --git a/tools/ioemu/CVS/Entries b/tools/ioemu/.CVS/Entries similarity index 100% rename from tools/ioemu/CVS/Entries rename to tools/ioemu/.CVS/Entries diff --git a/tools/ioemu/CVS/Repository b/tools/ioemu/.CVS/Repository similarity index 100% rename from tools/ioemu/CVS/Repository rename to tools/ioemu/.CVS/Repository diff --git a/tools/ioemu/CVS/Root b/tools/ioemu/.CVS/Root similarity index 100% rename from tools/ioemu/CVS/Root rename to tools/ioemu/.CVS/Root diff --git a/tools/ioemu/CVS/Tag b/tools/ioemu/.CVS/Tag similarity index 100% rename from tools/ioemu/CVS/Tag rename to tools/ioemu/.CVS/Tag diff --git a/tools/ioemu/audio/CVS/Entries b/tools/ioemu/audio/.CVS/Entries similarity index 100% rename from tools/ioemu/audio/CVS/Entries rename to tools/ioemu/audio/.CVS/Entries diff --git a/tools/ioemu/audio/CVS/Repository b/tools/ioemu/audio/.CVS/Repository similarity index 100% rename from tools/ioemu/audio/CVS/Repository rename to tools/ioemu/audio/.CVS/Repository diff --git a/tools/ioemu/audio/CVS/Root b/tools/ioemu/audio/.CVS/Root similarity index 100% rename from tools/ioemu/audio/CVS/Root rename to tools/ioemu/audio/.CVS/Root diff --git a/tools/ioemu/audio/CVS/Tag b/tools/ioemu/audio/.CVS/Tag similarity index 100% rename from tools/ioemu/audio/CVS/Tag rename to tools/ioemu/audio/.CVS/Tag diff --git a/tools/ioemu/fpu/CVS/Entries b/tools/ioemu/fpu/.CVS/Entries similarity index 100% rename from tools/ioemu/fpu/CVS/Entries rename to tools/ioemu/fpu/.CVS/Entries diff --git a/tools/ioemu/fpu/CVS/Repository b/tools/ioemu/fpu/.CVS/Repository similarity index 100% rename from tools/ioemu/fpu/CVS/Repository rename to tools/ioemu/fpu/.CVS/Repository diff --git a/tools/ioemu/fpu/CVS/Root b/tools/ioemu/fpu/.CVS/Root similarity index 100% rename from tools/ioemu/fpu/CVS/Root rename to tools/ioemu/fpu/.CVS/Root diff --git a/tools/ioemu/fpu/CVS/Tag b/tools/ioemu/fpu/.CVS/Tag similarity index 100% rename from tools/ioemu/fpu/CVS/Tag rename to tools/ioemu/fpu/.CVS/Tag diff --git a/tools/ioemu/hw/CVS/Entries b/tools/ioemu/hw/.CVS/Entries similarity index 100% rename from tools/ioemu/hw/CVS/Entries rename to tools/ioemu/hw/.CVS/Entries diff --git a/tools/ioemu/hw/CVS/Repository b/tools/ioemu/hw/.CVS/Repository similarity index 100% rename from tools/ioemu/hw/CVS/Repository rename to tools/ioemu/hw/.CVS/Repository diff --git a/tools/ioemu/hw/CVS/Root b/tools/ioemu/hw/.CVS/Root similarity index 100% rename from tools/ioemu/hw/CVS/Root rename to tools/ioemu/hw/.CVS/Root diff --git a/tools/ioemu/hw/CVS/Tag b/tools/ioemu/hw/.CVS/Tag similarity index 100% rename from tools/ioemu/hw/CVS/Tag rename to tools/ioemu/hw/.CVS/Tag diff --git a/tools/ioemu/keymaps/CVS/Entries b/tools/ioemu/keymaps/.CVS/Entries similarity index 100% rename from tools/ioemu/keymaps/CVS/Entries rename to tools/ioemu/keymaps/.CVS/Entries diff --git a/tools/ioemu/keymaps/CVS/Repository b/tools/ioemu/keymaps/.CVS/Repository similarity index 100% rename from tools/ioemu/keymaps/CVS/Repository rename to tools/ioemu/keymaps/.CVS/Repository diff --git a/tools/ioemu/keymaps/CVS/Root b/tools/ioemu/keymaps/.CVS/Root similarity index 100% rename from tools/ioemu/keymaps/CVS/Root rename to tools/ioemu/keymaps/.CVS/Root diff --git a/tools/ioemu/keymaps/CVS/Tag b/tools/ioemu/keymaps/.CVS/Tag similarity index 100% rename from tools/ioemu/keymaps/CVS/Tag rename to tools/ioemu/keymaps/.CVS/Tag diff --git a/tools/ioemu/pc-bios/CVS/Entries b/tools/ioemu/pc-bios/.CVS/Entries similarity index 100% rename from tools/ioemu/pc-bios/CVS/Entries rename to tools/ioemu/pc-bios/.CVS/Entries diff --git a/tools/ioemu/pc-bios/CVS/Repository b/tools/ioemu/pc-bios/.CVS/Repository similarity index 100% rename from tools/ioemu/pc-bios/CVS/Repository rename to tools/ioemu/pc-bios/.CVS/Repository diff --git a/tools/ioemu/pc-bios/CVS/Root b/tools/ioemu/pc-bios/.CVS/Root similarity index 100% rename from tools/ioemu/pc-bios/CVS/Root rename to tools/ioemu/pc-bios/.CVS/Root diff --git a/tools/ioemu/pc-bios/CVS/Tag b/tools/ioemu/pc-bios/.CVS/Tag similarity index 100% rename from tools/ioemu/pc-bios/CVS/Tag rename to tools/ioemu/pc-bios/.CVS/Tag diff --git a/tools/ioemu/target-i386/CVS/Entries b/tools/ioemu/target-i386/.CVS/Entries similarity index 100% rename from tools/ioemu/target-i386/CVS/Entries rename to tools/ioemu/target-i386/.CVS/Entries diff --git a/tools/ioemu/target-i386/CVS/Repository b/tools/ioemu/target-i386/.CVS/Repository similarity index 100% rename from tools/ioemu/target-i386/CVS/Repository rename to tools/ioemu/target-i386/.CVS/Repository diff --git a/tools/ioemu/target-i386/CVS/Root b/tools/ioemu/target-i386/.CVS/Root similarity index 100% rename from tools/ioemu/target-i386/CVS/Root rename to tools/ioemu/target-i386/.CVS/Root diff --git a/tools/ioemu/target-i386/CVS/Tag b/tools/ioemu/target-i386/.CVS/Tag similarity index 100% rename from tools/ioemu/target-i386/CVS/Tag rename to tools/ioemu/target-i386/.CVS/Tag diff --git a/tools/ioemu/tests/CVS/Entries b/tools/ioemu/tests/.CVS/Entries similarity index 100% rename from tools/ioemu/tests/CVS/Entries rename to tools/ioemu/tests/.CVS/Entries diff --git a/tools/ioemu/tests/CVS/Repository b/tools/ioemu/tests/.CVS/Repository similarity index 100% rename from tools/ioemu/tests/CVS/Repository rename to tools/ioemu/tests/.CVS/Repository diff --git a/tools/ioemu/tests/CVS/Root b/tools/ioemu/tests/.CVS/Root similarity index 100% rename from tools/ioemu/tests/CVS/Root rename to tools/ioemu/tests/.CVS/Root diff --git a/tools/ioemu/tests/CVS/Tag b/tools/ioemu/tests/.CVS/Tag similarity index 100% rename from tools/ioemu/tests/CVS/Tag rename to tools/ioemu/tests/.CVS/Tag From 5dd83c7e6d9eb830707ff31702f3f09a4a22a260 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 15:28:09 +0100 Subject: [PATCH 033/111] [XEN] Hide compile-time information values behind a functional interface, so that the values are contained within a single object file. Signed-off-by: Keir Fraser --- xen/Makefile | 10 ++---- xen/Rules.mk | 1 - xen/arch/ia64/xen/dom_fw.c | 14 +++++--- xen/arch/ia64/xen/domain.c | 5 +-- xen/arch/ia64/xen/xensetup.c | 8 +++-- xen/arch/powerpc/boot_of.c | 8 ++--- xen/arch/powerpc/domain_build.c | 4 +-- xen/arch/powerpc/mpic_init.c | 1 - xen/arch/powerpc/ofd_fixup.c | 4 +-- xen/arch/powerpc/powerpc64/traps.c | 4 +-- xen/arch/x86/domain_build.c | 5 +-- xen/arch/x86/setup.c | 22 ++++++------ xen/arch/x86/x86_32/traps.c | 6 ++-- xen/arch/x86/x86_64/traps.c | 6 ++-- xen/common/Makefile | 3 +- xen/common/kernel.c | 16 ++++----- xen/common/version.c | 56 ++++++++++++++++++++++++++++++ xen/drivers/char/Makefile | 3 -- xen/drivers/char/console.c | 12 +++---- xen/include/xen/version.h | 16 +++++++++ 20 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 xen/common/version.c create mode 100644 xen/include/xen/version.h diff --git a/xen/Makefile b/xen/Makefile index 4279b0ef27..d9f5322eb6 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -72,7 +72,7 @@ $(TARGET): delete-unfresh-files .PHONY: delete-unfresh-files delete-unfresh-files: @if [ ! -r include/xen/compile.h -o -O include/xen/compile.h ]; then \ - rm -f include/xen/{banner,compile}.h; \ + rm -f include/xen/compile.h; \ fi # acm_policy.h contains security policy for Xen @@ -91,7 +91,7 @@ include/xen/acm_policy.h: # compile.h contains dynamic build info. Rebuilt on every 'make' invocation. include/xen/compile.h: LANG=C -include/xen/compile.h: include/xen/compile.h.in include/xen/banner.h +include/xen/compile.h: include/xen/compile.h.in @sed -e 's/@@date@@/$(shell date)/g' \ -e 's/@@time@@/$(shell date +%T)/g' \ -e 's/@@whoami@@/$(shell whoami)/g' \ @@ -103,11 +103,7 @@ include/xen/compile.h: include/xen/compile.h.in include/xen/banner.h -e 's/@@extraversion@@/$(XEN_EXTRAVERSION)/g' \ -e 's!@@changeset@@!$(shell ((hg parents || head -n 7 ../ChangeLog || echo date: unavailable) | awk '{FS="changeset:[ ]+"}/^changeset/{CS=$$2};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null)!g' \ < include/xen/compile.h.in > $@.new - @cat include/xen/banner.h >> $@.new - @mv -f $@.new $@ - -include/xen/banner.h: - tools/figlet/figlet -d tools/figlet Xen $(XEN_FULLVERSION) > $@.new + tools/figlet/figlet -d tools/figlet Xen $(XEN_FULLVERSION) >> $@.new @mv -f $@.new $@ include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s diff --git a/xen/Rules.mk b/xen/Rules.mk index 674e4a39bc..17a0eb04aa 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -43,7 +43,6 @@ include $(BASEDIR)/arch/$(TARGET_ARCH)/Rules.mk # Do not depend on auto-generated header files. HDRS := $(subst $(BASEDIR)/include/asm-$(TARGET_ARCH)/asm-offsets.h,,$(HDRS)) -HDRS := $(subst $(BASEDIR)/include/xen/banner.h,,$(HDRS)) HDRS := $(subst $(BASEDIR)/include/xen/compile.h,,$(HDRS)) # Note that link order matters! diff --git a/xen/arch/ia64/xen/dom_fw.c b/xen/arch/ia64/xen/dom_fw.c index a3f699646b..df6cfca77e 100644 --- a/xen/arch/ia64/xen/dom_fw.c +++ b/xen/arch/ia64/xen/dom_fw.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -353,7 +353,8 @@ dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables) strcpy(xsdt->oem_id, "XEN"); strcpy(xsdt->oem_table_id, "Xen/ia64"); strcpy(xsdt->asl_compiler_id, "XEN"); - xsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION); + xsdt->asl_compiler_revision = (xen_major_version() << 16) | + xen_minor_version(); xsdt->table_offset_entry[0] = dom_pa((unsigned long) fadt); tables->madt_ptr = dom_pa((unsigned long) madt); @@ -367,7 +368,8 @@ dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables) strcpy(fadt->oem_id, "XEN"); strcpy(fadt->oem_table_id, "Xen/ia64"); strcpy(fadt->asl_compiler_id, "XEN"); - fadt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION); + fadt->asl_compiler_revision = (xen_major_version() << 16) | + xen_minor_version(); strncpy(facs->signature, FACS_SIG, 4); facs->version = 1; @@ -413,7 +415,8 @@ dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables) strcpy(dsdt->oem_id, "XEN"); strcpy(dsdt->oem_table_id, "Xen/ia64"); strcpy(dsdt->asl_compiler_id, "XEN"); - dsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION); + dsdt->asl_compiler_revision = (xen_major_version() << 16) | + xen_minor_version(); /* Trivial namespace, avoids ACPI CA complaints */ tables->aml[0] = 0x10; /* Scope */ @@ -454,7 +457,8 @@ dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables) strcpy(madt->header.oem_id, "XEN"); strcpy(madt->header.oem_table_id, "Xen/ia64"); strcpy(madt->header.asl_compiler_id, "XEN"); - madt->header.asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION); + madt->header.asl_compiler_revision = (xen_major_version() << 16) | + xen_minor_version(); /* An LSAPIC entry describes a CPU. */ for (i = 0; i < MAX_VIRT_CPUS; i++) { diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index b4c7401e5c..25c3c854b8 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include /* for IA64_THREAD_INFO_SIZE */ @@ -1069,7 +1069,8 @@ int construct_dom0(struct domain *d, panic("can't allocate start info page"); si = page_to_virt(start_info_page); memset(si, 0, PAGE_SIZE); - sprintf(si->magic, "xen-%i.%i-ia64", XEN_VERSION, XEN_SUBVERSION); + sprintf(si->magic, "xen-%i.%i-ia64", + xen_major_version(), xen_minor_version()); si->nr_pages = max_pages; si->flags = SIF_INITDOMAIN|SIF_PRIVILEGED; diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index 2fcab3ea14..eccc8bb349 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -547,11 +547,13 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); void arch_get_xen_caps(xen_capabilities_info_t info) { char *p=info; + int major = xen_major_version(); + int minor = xen_minor_version(); - p += sprintf(p,"xen-%d.%d-ia64 ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p,"xen-%d.%d-ia64 ", major, minor); if (vmx_enabled) - p += sprintf(p,"hvm-%d.%d-ia64 ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p,"hvm-%d.%d-ia64 ", major, minor); *(p-1) = 0; diff --git a/xen/arch/powerpc/boot_of.c b/xen/arch/powerpc/boot_of.c index 1b22c2a7fb..4fd5b0b571 100644 --- a/xen/arch/powerpc/boot_of.c +++ b/xen/arch/powerpc/boot_of.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -976,9 +976,9 @@ multiboot_info_t __init *boot_of_init( of_printf("%s\n", "---------------------------------------------------"); of_printf("OF: Xen/PPC version %d.%d%s (%s@%s) (%s) %s\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, - XEN_COMPILE_BY, XEN_COMPILE_DOMAIN, - XEN_COMPILER, XEN_COMPILE_DATE); + xen_major_version(), xen_minor_version(), xen_extra_version(), + xen_compile_by(), xen_compile_domain(), + xen_compiler(), xen_compile_date()); of_printf("%s args: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n" "boot msr: 0x%lx\n", diff --git a/xen/arch/powerpc/domain_build.c b/xen/arch/powerpc/domain_build.c index dfe51f62cd..89f68dae1b 100644 --- a/xen/arch/powerpc/domain_build.c +++ b/xen/arch/powerpc/domain_build.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include "oftree.h" @@ -153,7 +153,7 @@ int construct_dom0(struct domain *d, printk("xen_start_info: %p\n", si); sprintf(si->magic, "xen-%i.%i-powerpc%d%s", - XEN_VERSION, XEN_SUBVERSION, BITS_PER_LONG, "HV"); + xen_major_version(), xen_minor_version(), BITS_PER_LONG, "HV"); si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN; si->shared_info = ((ulong)d->shared_info) - rma; diff --git a/xen/arch/powerpc/mpic_init.c b/xen/arch/powerpc/mpic_init.c index 59cb8d80d2..5977868451 100644 --- a/xen/arch/powerpc/mpic_init.c +++ b/xen/arch/powerpc/mpic_init.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include "mpic_init.h" #include "oftree.h" diff --git a/xen/arch/powerpc/ofd_fixup.c b/xen/arch/powerpc/ofd_fixup.c index 6178a1fabe..5905423590 100644 --- a/xen/arch/powerpc/ofd_fixup.c +++ b/xen/arch/powerpc/ofd_fixup.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "of-devtree.h" @@ -420,7 +420,7 @@ static ofdn_t ofd_xen_props(void *m, struct domain *d, start_info_t *si) ofd_prop_add(m, n, "name", &path[1], sizeof (path) - 1); xl = snprintf(xen, sizeof (xen), "Xen-%d.%d%s", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION); + xen_major_version(), xen_minor_version(), xen_extra_version()); ASSERT(xl < sizeof (xen)); ofd_prop_add(m, n, "version", xen, xl + 1); diff --git a/xen/arch/powerpc/powerpc64/traps.c b/xen/arch/powerpc/powerpc64/traps.c index 8948c27313..e1945faa27 100644 --- a/xen/arch/powerpc/powerpc64/traps.c +++ b/xen/arch/powerpc/powerpc64/traps.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include void show_registers(struct cpu_user_regs *regs) @@ -32,7 +32,7 @@ void show_registers(struct cpu_user_regs *regs) console_start_sync(); printk("----[ Xen-%d.%d%s ]----\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION); + xen_major_version(), xen_minor_version(), xen_extra_version()); printk("CPU: %08x DOMID: %08x\n", smp_processor_id(), current->domain->domain_id); printk("pc %016lx msr %016lx\n" diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 8c89877b08..78180898b7 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -726,7 +726,8 @@ int construct_dom0(struct domain *d, si->nr_pt_frames = nr_pt_pages; si->mfn_list = vphysmap_start; sprintf(si->magic, "xen-%i.%i-x86_%d%s", - XEN_VERSION, XEN_SUBVERSION, BITS_PER_LONG, xen_pae ? "p" : ""); + xen_major_version(), xen_minor_version(), + BITS_PER_LONG, xen_pae ? "p" : ""); /* Write the phys->machine and machine->phys table entries. */ for ( pfn = 0; pfn < d->tot_pages; pfn++ ) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index d49073ce3e..dbf4909495 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -612,30 +612,32 @@ void __init __start_xen(multiboot_info_t *mbi) void arch_get_xen_caps(xen_capabilities_info_t info) { char *p = info; + int major = xen_major_version(); + int minor = xen_minor_version(); #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE) - p += sprintf(p, "xen-%d.%d-x86_32 ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p, "xen-%d.%d-x86_32 ", major, minor); if ( hvm_enabled ) - p += sprintf(p, "hvm-%d.%d-x86_32 ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p, "hvm-%d.%d-x86_32 ", major, minor); #elif defined(CONFIG_X86_32) && defined(CONFIG_X86_PAE) - p += sprintf(p, "xen-%d.%d-x86_32p ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p, "xen-%d.%d-x86_32p ", major, minor); if ( hvm_enabled ) { - p += sprintf(p, "hvm-%d.%d-x86_32 ", XEN_VERSION, XEN_SUBVERSION); - p += sprintf(p, "hvm-%d.%d-x86_32p ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p, "hvm-%d.%d-x86_32 ", major, minor); + p += sprintf(p, "hvm-%d.%d-x86_32p ", major, minor); } #elif defined(CONFIG_X86_64) - p += sprintf(p, "xen-%d.%d-x86_64 ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p, "xen-%d.%d-x86_64 ", major, minor); if ( hvm_enabled ) { - p += sprintf(p, "hvm-%d.%d-x86_32 ", XEN_VERSION, XEN_SUBVERSION); - p += sprintf(p, "hvm-%d.%d-x86_32p ", XEN_VERSION, XEN_SUBVERSION); - p += sprintf(p, "hvm-%d.%d-x86_64 ", XEN_VERSION, XEN_SUBVERSION); + p += sprintf(p, "hvm-%d.%d-x86_32 ", major, minor); + p += sprintf(p, "hvm-%d.%d-x86_32p ", major, minor); + p += sprintf(p, "hvm-%d.%d-x86_64 ", major, minor); } #else diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index 3774aa83c8..ae18f654ad 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -52,7 +52,7 @@ void show_registers(struct cpu_user_regs *regs) } printk("----[ Xen-%d.%d%s %s ]----\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, + xen_major_version(), xen_minor_version(), xen_extra_version(), print_tainted(taint_str)); printk("CPU: %d\nEIP: %04x:[<%08x>]", smp_processor_id(), fault_regs.cs, fault_regs.eip); @@ -131,7 +131,7 @@ asmlinkage void do_double_fault(void) /* Find information saved during fault and dump it to the console. */ tss = &init_tss[cpu]; printk("*** DOUBLE FAULT: Xen-%d.%d%s %s\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, + xen_major_version(), xen_minor_version(), xen_extra_version(), print_tainted(taint_str)); printk("CPU: %d\nEIP: %04x:[<%08x>]", cpu, tss->cs, tss->eip); diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index a5b7aef858..3cae3e3fc3 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -45,7 +45,7 @@ void show_registers(struct cpu_user_regs *regs) } printk("----[ Xen-%d.%d%s %s ]----\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, + xen_major_version(), xen_minor_version(), xen_extra_version(), print_tainted(taint_str)); printk("CPU: %d\nRIP: %04x:[<%016lx>]", smp_processor_id(), fault_regs.cs, fault_regs.rip); @@ -128,7 +128,7 @@ asmlinkage void do_double_fault(struct cpu_user_regs *regs) /* Find information saved during fault and dump it to the console. */ printk("*** DOUBLE FAULT: Xen-%d.%d%s %s\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, + xen_major_version(), xen_minor_version(), xen_extra_version(), print_tainted(taint_str)); printk("CPU: %d\nRIP: %04x:[<%016lx>]", cpu, regs->cs, regs->rip); diff --git a/xen/common/Makefile b/xen/common/Makefile index f6bad03a1a..be3179afdc 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -21,6 +21,7 @@ obj-y += string.o obj-y += symbols.o obj-y += trace.o obj-y += timer.o +obj-y += version.o obj-y += vsprintf.o obj-y += xmalloc.o @@ -28,4 +29,4 @@ obj-$(perfc) += perfc.o obj-$(crash_debug) += gdbstub.o # Object file contains changeset and compiler information. -kernel.o: $(BASEDIR)/include/xen/compile.h +version.o: $(BASEDIR)/include/xen/compile.h diff --git a/xen/common/kernel.c b/xen/common/kernel.c index dc76a893a3..5c3069bb62 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -125,13 +125,13 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE(void) arg) { case XENVER_version: { - return (XEN_VERSION<<16) | (XEN_SUBVERSION); + return (xen_major_version() << 16) | xen_minor_version(); } case XENVER_extraversion: { xen_extraversion_t extraversion; - safe_strcpy(extraversion, XEN_EXTRAVERSION); + safe_strcpy(extraversion, xen_extra_version()); if ( copy_to_guest(arg, (char *)extraversion, sizeof(extraversion)) ) return -EFAULT; return 0; @@ -140,10 +140,10 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE(void) arg) case XENVER_compile_info: { struct xen_compile_info info; - safe_strcpy(info.compiler, XEN_COMPILER); - safe_strcpy(info.compile_by, XEN_COMPILE_BY); - safe_strcpy(info.compile_domain, XEN_COMPILE_DOMAIN); - safe_strcpy(info.compile_date, XEN_COMPILE_DATE); + safe_strcpy(info.compiler, xen_compiler()); + safe_strcpy(info.compile_by, xen_compile_by()); + safe_strcpy(info.compile_domain, xen_compile_domain()); + safe_strcpy(info.compile_date, xen_compile_date()); if ( copy_to_guest(arg, &info, 1) ) return -EFAULT; return 0; @@ -176,7 +176,7 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE(void) arg) case XENVER_changeset: { xen_changeset_info_t chgset; - safe_strcpy(chgset, XEN_CHANGESET); + safe_strcpy(chgset, xen_changeset()); if ( copy_to_guest(arg, (char *)chgset, sizeof(chgset)) ) return -EFAULT; return 0; diff --git a/xen/common/version.c b/xen/common/version.c new file mode 100644 index 0000000000..6afa128cd0 --- /dev/null +++ b/xen/common/version.c @@ -0,0 +1,56 @@ +#include + +const char *xen_compile_date(void) +{ + return XEN_COMPILE_DATE; +} + +const char *xen_compile_time(void) +{ + return XEN_COMPILE_TIME; +} + +const char *xen_compile_by(void) +{ + return XEN_COMPILE_BY; +} + +const char *xen_compile_domain(void) +{ + return XEN_COMPILE_DOMAIN; +} + +const char *xen_compile_host(void) +{ + return XEN_COMPILE_HOST; +} + +const char *xen_compiler(void) +{ + return XEN_COMPILER; +} + +unsigned int xen_major_version(void) +{ + return XEN_VERSION; +} + +unsigned int xen_minor_version(void) +{ + return XEN_SUBVERSION; +} + +const char *xen_extra_version(void) +{ + return XEN_EXTRAVERSION; +} + +const char *xen_changeset(void) +{ + return XEN_CHANGESET; +} + +const char *xen_banner(void) +{ + return XEN_BANNER; +} diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile index e63753d429..ded9a94cc1 100644 --- a/xen/drivers/char/Makefile +++ b/xen/drivers/char/Makefile @@ -1,6 +1,3 @@ obj-y += console.o obj-y += ns16550.o obj-y += serial.o - -# Object file contains changeset and compiler information. -console.o: $(BASEDIR)/include/xen/compile.h diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index c9a56771c5..f5ca219f9c 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include @@ -488,14 +488,14 @@ void init_console(void) serial_set_rx_handler(sercon_handle, serial_rx); /* HELLO WORLD --- start-of-day banner text. */ - printk(XEN_BANNER); + printk(xen_banner()); printk(" http://www.cl.cam.ac.uk/netos/xen\n"); printk(" University of Cambridge Computer Laboratory\n\n"); printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n", - XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, - XEN_COMPILE_BY, XEN_COMPILE_DOMAIN, - XEN_COMPILER, XEN_COMPILE_DATE); - printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET); + xen_major_version(), xen_minor_version(), xen_extra_version(), + xen_compile_by(), xen_compile_domain(), + xen_compiler(), xen_compile_date()); + printk(" Latest ChangeSet: %s\n\n", xen_changeset()); set_printk_prefix("(XEN) "); if ( opt_sync_console ) diff --git a/xen/include/xen/version.h b/xen/include/xen/version.h new file mode 100644 index 0000000000..81a3c7d111 --- /dev/null +++ b/xen/include/xen/version.h @@ -0,0 +1,16 @@ +#ifndef __XEN_VERSION_H__ +#define __XEN_VERSION_H__ + +const char *xen_compile_date(void); +const char *xen_compile_time(void); +const char *xen_compile_by(void); +const char *xen_compile_domain(void); +const char *xen_compile_host(void); +const char *xen_compiler(void); +unsigned int xen_major_version(void); +unsigned int xen_minor_version(void); +const char *xen_extra_version(void); +const char *xen_changeset(void); +const char *xen_banner(void); + +#endif /* __XEN_VERSION_H__ */ From 177155de98343fa322fd0e3f6d1c05315aaa3f74 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 15:48:48 +0100 Subject: [PATCH 034/111] [LINUX] Do not early-unpin pagetables that contain foreign mappings. This fixes a bug whereby foreign pages were freed by the unpin, which then become owned by the local domain before it destroys its ptes. It therefore (erroneously) detects the mappings as local and so updates reference counts, leading to crashes. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/arch/i386/kernel/ldt-xen.c | 1 + linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c | 2 ++ linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c | 3 ++- linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c | 3 ++- linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/mmu.h | 3 +++ linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/mmu.h | 1 + 6 files changed, 11 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/ldt-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/ldt-xen.c index 06970d9517..d2cceffbb1 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/ldt-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/ldt-xen.c @@ -109,6 +109,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) init_MUTEX(&mm->context.sem); mm->context.size = 0; + mm->context.has_foreign_mappings = 0; old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); diff --git a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c index 1de992b228..3438269705 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c @@ -126,6 +126,8 @@ int direct_remap_pfn_range(struct vm_area_struct *vma, if (domid == DOMID_SELF) return -EINVAL; + vma->vm_mm->context.has_foreign_mappings = 1; + return __direct_remap_pfn_range( vma->vm_mm, address, mfn, size, prot, domid); } diff --git a/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c index a551252c71..843c9d0fd3 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c @@ -694,6 +694,7 @@ void _arch_exit_mmap(struct mm_struct *mm) task_unlock(tsk); if (test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags) && - (atomic_read(&mm->mm_count) == 1)) + (atomic_read(&mm->mm_count) == 1) && + !mm->context.has_foreign_mappings) mm_unpin(mm); } diff --git a/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c b/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c index 721c47b1fd..3641bfb805 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c @@ -159,7 +159,8 @@ void _arch_exit_mmap(struct mm_struct *mm) task_unlock(tsk); - if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) ) + if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) && + !mm->context.has_foreign_mappings ) mm_unpin(mm); } diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/mmu.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/mmu.h index cba1785e39..139e54a9be 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/mmu.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/mmu.h @@ -12,6 +12,9 @@ typedef struct { int size; struct semaphore sem; void *ldt; +#ifdef CONFIG_XEN + int has_foreign_mappings; +#endif } mm_context_t; /* mm/memory.c:exit_mmap hook */ diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/mmu.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/mmu.h index f95e8d5d79..2ac8252954 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/mmu.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/mmu.h @@ -17,6 +17,7 @@ typedef struct { struct semaphore sem; #ifdef CONFIG_XEN unsigned pinned:1; + unsigned has_foreign_mappings:1; struct list_head unpinned; #endif } mm_context_t; From 0ead411665eed0883b475f8309e366d4f7e914e7 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 17:18:05 +0100 Subject: [PATCH 035/111] [XEN] Add hypercall support for HVM guests. This is fairly useless at the moment, since all of the hypercalls fail, since copy_from_user doesn't work correctly in HVM domains. Signed-off-by: Steven Smith Add a CPUID hypervisor platform interface at leaf 0x40000000. Allow hypercall transfer page to be filled in via MSR 0x40000000. Signed-off-by: Keir Fraser --- xen/arch/x86/dom0_ops.c | 2 +- xen/arch/x86/domain.c | 2 +- xen/arch/x86/domain_build.c | 2 +- xen/arch/x86/hvm/hvm.c | 60 +++++++++++++++++++ xen/arch/x86/hvm/svm/svm.c | 39 ++++++++++++- xen/arch/x86/hvm/vmx/vmx.c | 45 ++++++++++++-- xen/arch/x86/traps.c | 97 +++++++++++++++++++++++++++++-- xen/arch/x86/x86_32/traps.c | 6 +- xen/arch/x86/x86_64/traps.c | 10 +++- xen/include/asm-x86/domain.h | 2 +- xen/include/asm-x86/hvm/hvm.h | 5 ++ xen/include/asm-x86/hvm/support.h | 2 + xen/include/asm-x86/processor.h | 4 ++ 13 files changed, 256 insertions(+), 20 deletions(-) diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index 500c7f7ae6..e9c015fd0b 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -429,7 +429,7 @@ long arch_do_dom0_op(struct dom0_op *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op) ret = 0; hypercall_page = map_domain_page(mfn); - hypercall_page_initialise(hypercall_page); + hypercall_page_initialise(d, hypercall_page); unmap_domain_page(hypercall_page); put_page_and_type(mfn_to_page(mfn)); diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 9eb1f53771..cdab497e43 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -819,7 +819,7 @@ unsigned long hypercall_create_continuation( #if defined(__i386__) regs->eax = op; - if ( supervisor_mode_kernel ) + if ( supervisor_mode_kernel || hvm_guest(current) ) regs->eip &= ~31; /* re-execute entire hypercall entry stub */ else regs->eip -= 2; /* re-execute 'int 0x82' */ diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 78180898b7..8526d15365 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -704,7 +704,7 @@ int construct_dom0(struct domain *d, return -1; } - hypercall_page_initialise((void *)hypercall_page); + hypercall_page_initialise(d, (void *)hypercall_page); } /* Copy the initial ramdisk. */ diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 6e0808e641..f4dee16ecc 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -329,6 +330,65 @@ void hvm_print_line(struct vcpu *v, const char c) pbuf[(*index)++] = c; } +#if defined(__i386__) + +typedef unsigned long hvm_hypercall_t( + unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); +#define HYPERCALL(x) [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x +static hvm_hypercall_handler *hvm_hypercall_table[] = { + HYPERCALL(mmu_update), + HYPERCALL(memory_op), + HYPERCALL(multicall), + HYPERCALL(update_va_mapping), + HYPERCALL(event_channel_op_compat), + HYPERCALL(xen_version), + HYPERCALL(grant_table_op), + HYPERCALL(event_channel_op), + HYPERCALL(hvm_op) +}; +#undef HYPERCALL + +void hvm_do_hypercall(struct cpu_user_regs *pregs) +{ + if ( ring_3(pregs) ) + { + pregs->eax = -EPERM; + return; + } + + if ( pregs->eax > ARRAY_SIZE(hvm_hypercall_table) || + !hvm_hypercall_table[pregs->eax] ) + { + DPRINTK("HVM vcpu %d:%d did a bad hypercall %d.\n", + current->domain->domain_id, current->vcpu_id, + pregs->eax); + pregs->eax = -ENOSYS; + } + else + { + pregs->eax = hvm_hypercall_table[pregs->eax]( + pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi); + } +} + +#else /* __x86_64__ */ + +void hvm_do_hypercall(struct cpu_user_regs *pregs) +{ + printk("not supported yet!\n"); +} + +#endif + +/* Initialise a hypercall transfer page for a VMX domain using + paravirtualised drivers. */ +void hvm_hypercall_page_initialise(struct domain *d, + void *hypercall_page) +{ + hvm_funcs.init_hypercall_page(d, hypercall_page); +} + + /* * only called in HVM domain BSP context * when booting, vcpuid is always equal to apic_id diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 998611220e..9ee9ee5bf8 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -456,6 +456,28 @@ void svm_init_ap_context(struct vcpu_guest_context *ctxt, ctxt->flags = VGCF_HVM_GUEST; } +static void svm_init_hypercall_page(struct domain *d, void *hypercall_page) +{ + char *p; + int i; + + memset(hypercall_page, 0, PAGE_SIZE); + + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */ + *(u32 *)(p + 1) = i; + *(u8 *)(p + 5) = 0x0f; /* vmmcall */ + *(u8 *)(p + 6) = 0x01; + *(u8 *)(p + 7) = 0xd9; + *(u8 *)(p + 8) = 0xc3; /* ret */ + } + + /* Don't support HYPERVISOR_iret at the moment */ + *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */ +} + int start_svm(void) { u32 eax, ecx, edx; @@ -504,6 +526,8 @@ int start_svm(void) hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg; hvm_funcs.init_ap_context = svm_init_ap_context; + hvm_funcs.init_hypercall_page = svm_init_hypercall_page; + hvm_enabled = 1; return 1; @@ -1980,11 +2004,13 @@ static int svm_cr_access(struct vcpu *v, unsigned int cr, unsigned int type, return result; } -static inline void svm_do_msr_access(struct vcpu *v, struct cpu_user_regs *regs) +static inline void svm_do_msr_access( + struct vcpu *v, struct cpu_user_regs *regs) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; int inst_len; u64 msr_content=0; + u32 eax, edx; ASSERT(vmcb); @@ -2018,6 +2044,14 @@ static inline void svm_do_msr_access(struct vcpu *v, struct cpu_user_regs *regs) default: if (long_mode_do_msr_read(regs)) goto done; + + if ( rdmsr_hypervisor_regs(regs->ecx, &eax, &edx) ) + { + regs->eax = eax; + regs->edx = edx; + goto done; + } + rdmsr_safe(regs->ecx, regs->eax, regs->edx); break; } @@ -2047,7 +2081,8 @@ static inline void svm_do_msr_access(struct vcpu *v, struct cpu_user_regs *regs) vlapic_msr_set(VLAPIC(v), msr_content); break; default: - long_mode_do_msr_write(regs); + if ( !long_mode_do_msr_write(regs) ) + wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx); break; } } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index fe00954a0a..f8df7bbcf8 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -669,6 +669,28 @@ static int check_vmx_controls(u32 ctrls, u32 msr) return 1; } +static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page) +{ + char *p; + int i; + + memset(hypercall_page, 0, PAGE_SIZE); + + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */ + *(u32 *)(p + 1) = i; + *(u8 *)(p + 5) = 0x0f; /* vmcall */ + *(u8 *)(p + 6) = 0x01; + *(u8 *)(p + 7) = 0xc1; + *(u8 *)(p + 8) = 0xc3; /* ret */ + } + + /* Don't support HYPERVISOR_iret at the moment */ + *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */ +} + int start_vmx(void) { u32 eax, edx; @@ -749,6 +771,8 @@ int start_vmx(void) hvm_funcs.init_ap_context = vmx_init_ap_context; + hvm_funcs.init_hypercall_page = vmx_init_hypercall_page; + hvm_enabled = 1; return 1; @@ -1877,6 +1901,7 @@ static int vmx_cr_access(unsigned long exit_qualification, struct cpu_user_regs static inline void vmx_do_msr_read(struct cpu_user_regs *regs) { u64 msr_content = 0; + u32 eax, edx; struct vcpu *v = current; HVM_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read: ecx=%lx, eax=%lx, edx=%lx", @@ -1899,8 +1924,16 @@ static inline void vmx_do_msr_read(struct cpu_user_regs *regs) msr_content = VLAPIC(v) ? VLAPIC(v)->apic_base_msr : 0; break; default: - if(long_mode_do_msr_read(regs)) + if (long_mode_do_msr_read(regs)) return; + + if ( rdmsr_hypervisor_regs(regs->ecx, &eax, &edx) ) + { + regs->eax = eax; + regs->edx = edx; + return; + } + rdmsr_safe(regs->ecx, regs->eax, regs->edx); break; } @@ -1942,7 +1975,8 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs) vlapic_msr_set(VLAPIC(v), msr_content); break; default: - long_mode_do_msr_write(regs); + if ( !long_mode_do_msr_write(regs) ) + wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx); break; } @@ -2273,16 +2307,16 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) __update_guest_eip(inst_len); break; } -#if 0 /* keep this for debugging */ case EXIT_REASON_VMCALL: + { __get_instruction_length(inst_len); __vmread(GUEST_RIP, &eip); __vmread(EXIT_QUALIFICATION, &exit_qualification); - hvm_print_line(v, regs.eax); /* provides the current domain */ + hvm_do_hypercall(®s); __update_guest_eip(inst_len); break; -#endif + } case EXIT_REASON_CR_ACCESS: { __vmread(GUEST_RIP, &eip); @@ -2323,7 +2357,6 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) case EXIT_REASON_MWAIT_INSTRUCTION: __hvm_bug(®s); break; - case EXIT_REASON_VMCALL: case EXIT_REASON_VMCLEAR: case EXIT_REASON_VMLAUNCH: case EXIT_REASON_VMPTRLD: diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 44913b2f42..45d73bc511 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -429,18 +430,95 @@ DO_ERROR_NOCODE(16, "fpu error", coprocessor_error) DO_ERROR(17, "alignment check", alignment_check) DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error) +int rdmsr_hypervisor_regs( + uint32_t idx, uint32_t *eax, uint32_t *edx) +{ + idx -= 0x40000000; + if ( idx > 0 ) + return 0; + + *eax = *edx = 0; + return 1; +} + +int wrmsr_hypervisor_regs( + uint32_t idx, uint32_t eax, uint32_t edx) +{ + struct domain *d = current->domain; + + idx -= 0x40000000; + if ( idx > 0 ) + return 0; + + switch ( idx ) + { + case 0: + { + void *hypercall_page; + unsigned long mfn; + unsigned long gmfn = ((unsigned long)edx << 20) | (eax >> 12); + unsigned int idx = eax & 0xfff; + + if ( idx > 0 ) + { + DPRINTK("Dom%d: Out of range index %u to MSR %08x\n", + d->domain_id, idx, 0x40000000); + return 0; + } + + mfn = gmfn_to_mfn(d, gmfn); + + if ( !mfn_valid(mfn) || + !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) ) + { + DPRINTK("Dom%d: Bad GMFN %lx (MFN %lx) to MSR %08x\n", + d->domain_id, gmfn, mfn, 0x40000000); + return 0; + } + + hypercall_page = map_domain_page(mfn); + hypercall_page_initialise(d, hypercall_page); + unmap_domain_page(hypercall_page); + + put_page_and_type(mfn_to_page(mfn)); + break; + } + + default: + BUG(); + } + + return 1; +} + int cpuid_hypervisor_leaves( uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { - if ( (idx < 0x40000000) || (idx > 0x40000000) ) + idx -= 0x40000000; + if ( idx > 2 ) return 0; - switch ( idx - 0x40000000 ) + switch ( idx ) { case 0: - *eax = 0x40000000; - *ebx = 0x006e6558; /* "Xen\0" */ - *ecx = *edx = 0; + *eax = 0x40000002; /* Largest leaf */ + *ebx = 0x566e6558; /* Signature 1: "XenV" */ + *ecx = 0x65584d4d; /* Signature 2: "MMXe" */ + *edx = 0x4d4d566e; /* Signature 3: "nVMM" */ + break; + + case 1: + *eax = (xen_major_version() << 16) | xen_minor_version(); + *ebx = 0; /* Reserved */ + *ecx = 0; /* Reserved */ + *edx = 0; /* Reserved */ + break; + + case 2: + *eax = 1; /* Number of hypercall-transfer pages */ + *ebx = 0x40000000; /* MSR base address */ + *ecx = 0; /* Features 1 */ + *edx = 0; /* Features 2 */ break; default: @@ -1297,6 +1375,9 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) break; #endif default: + if ( wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx) ) + break; + if ( (rdmsr_safe(regs->ecx, l, h) != 0) || (regs->eax != l) || (regs->edx != h) ) DPRINTK("Domain attempted WRMSR %p from " @@ -1328,6 +1409,12 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) goto fail; break; default: + if ( rdmsr_hypervisor_regs(regs->ecx, &l, &h) ) + { + regs->eax = l; + regs->edx = h; + break; + } /* Everyone can read the MSR space. */ /*DPRINTK("Domain attempted RDMSR %p.\n", _p(regs->ecx));*/ if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) ) diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index ae18f654ad..3c6d81f21d 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -490,9 +490,11 @@ static void hypercall_page_initialise_ring1_kernel(void *hypercall_page) *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */ } -void hypercall_page_initialise(void *hypercall_page) +void hypercall_page_initialise(struct domain *d, void *hypercall_page) { - if ( supervisor_mode_kernel ) + if ( hvm_guest(d->vcpu[0]) ) + hvm_hypercall_page_initialise(d, hypercall_page); + else if ( supervisor_mode_kernel ) hypercall_page_initialise_ring0_kernel(hypercall_page); else hypercall_page_initialise_ring1_kernel(hypercall_page); diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 3cae3e3fc3..6b674a5b53 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -432,7 +432,7 @@ long do_set_callbacks(unsigned long event_address, return 0; } -void hypercall_page_initialise(void *hypercall_page) +static void hypercall_page_initialise_ring3_kernel(void *hypercall_page) { char *p; int i; @@ -465,6 +465,14 @@ void hypercall_page_initialise(void *hypercall_page) *(u16 *)(p+ 9) = 0x050f; /* syscall */ } +void hypercall_page_initialise(struct domain *d, void *hypercall_page) +{ + if ( hvm_guest(d->vcpu[0]) ) + hvm_hypercall_page_initialise(d, hypercall_page); + else + hypercall_page_initialise_ring3_kernel(hypercall_page); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 962fa7954b..bdba98ba03 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -55,7 +55,7 @@ extern void toggle_guest_mode(struct vcpu *); * Initialise a hypercall-transfer page. The given pointer must be mapped * in Xen virtual address space (accesses are not validated or checked). */ -extern void hypercall_page_initialise(void *); +extern void hypercall_page_initialise(struct domain *d, void *); struct arch_domain { diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 8e830977cc..04faa8971c 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -61,6 +61,8 @@ struct hvm_function_table { void (*init_ap_context)(struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector); + + void (*init_hypercall_page)(struct domain *d, void *hypercall_page); }; extern struct hvm_function_table hvm_funcs; @@ -121,6 +123,9 @@ hvm_instruction_length(struct vcpu *v) return hvm_funcs.instruction_length(v); } +void hvm_hypercall_page_initialise(struct domain *d, + void *hypercall_page); + static inline unsigned long hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num) { diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h index 61ad981399..4534e66680 100644 --- a/xen/include/asm-x86/hvm/support.h +++ b/xen/include/asm-x86/hvm/support.h @@ -148,4 +148,6 @@ extern void hvm_hooks_assist(struct vcpu *v); extern void hvm_print_line(struct vcpu *v, const char c); extern void hlt_timer_fn(void *data); +void hvm_do_hypercall(struct cpu_user_regs *pregs); + #endif /* __ASM_X86_HVM_SUPPORT_H__ */ diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 38c8330446..bc8d95b2c1 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -547,6 +547,10 @@ extern void mcheck_init(struct cpuinfo_x86 *c); int cpuid_hypervisor_leaves( uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); +int rdmsr_hypervisor_regs( + uint32_t idx, uint32_t *eax, uint32_t *edx); +int wrmsr_hypervisor_regs( + uint32_t idx, uint32_t eax, uint32_t edx); #endif /* !__ASSEMBLY__ */ From 8e3af29104242a0b411be048a4455884cfca06dd Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 17:28:19 +0100 Subject: [PATCH 036/111] [HVM][SVM] Change the calling convention for SVM VMMCALLs so that they don't conflict with the hypercall calling convention. Signed-off-by: Steven Smith --- tools/firmware/hvmloader/hvmloader.c | 10 +++--- xen/arch/x86/hvm/svm/svm.c | 52 +++++++++++++++------------ xen/include/asm-x86/hvm/svm/vmmcall.h | 8 ++--- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index 702a988fab..4c4637dc58 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -31,7 +31,7 @@ #define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000 /* invoke SVM's paged realmode support */ -#define SVM_VMMCALL_RESET_TO_REALMODE 0x00000001 +#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001 /* * C runtime start off @@ -133,15 +133,15 @@ cirrus_check(void) return inb(0x3C5) == 0x12; } -int -vmmcall(int edi, int esi, int edx, int ecx, int ebx) +int +vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx) { int eax; __asm__ __volatile__( ".byte 0x0F,0x01,0xD9" : "=a" (eax) - : "a"(0x58454E00), /* XEN\0 key */ + : "a"(function), "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) ); return eax; @@ -200,7 +200,7 @@ main(void) if (check_amd()) { /* AMD implies this is SVM */ puts("SVM go ...\n"); - vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0); + vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0); } else { puts("Loading VMXAssist ...\n"); memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS, diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 9ee9ee5bf8..4490bd7f5f 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -2349,33 +2349,41 @@ static int svm_do_vmmcall(struct vcpu *v, struct cpu_user_regs *regs) inst_len = __get_instruction_length(vmcb, INSTR_VMCALL, NULL); ASSERT(inst_len > 0); - /* VMMCALL sanity check */ - if (vmcb->cpl > get_vmmcall_cpl(regs->edi)) + if ( regs->eax & 0x80000000 ) { - printf("VMMCALL CPL check failed\n"); - return -1; - } - - /* handle the request */ - switch (regs->edi) - { - case VMMCALL_RESET_TO_REALMODE: - if (svm_do_vmmcall_reset_to_realmode(v, regs)) + /* VMMCALL sanity check */ + if ( vmcb->cpl > get_vmmcall_cpl(regs->edi) ) { - printf("svm_do_vmmcall_reset_to_realmode() failed\n"); + printf("VMMCALL CPL check failed\n"); return -1; } - - /* since we just reset the VMCB, return without adjusting the eip */ - return 0; - case VMMCALL_DEBUG: - printf("DEBUG features not implemented yet\n"); - break; - default: - break; - } - hvm_print_line(v, regs->eax); /* provides the current domain */ + /* handle the request */ + switch ( regs->eax ) + { + case VMMCALL_RESET_TO_REALMODE: + if ( svm_do_vmmcall_reset_to_realmode(v, regs) ) + { + printf("svm_do_vmmcall_reset_to_realmode() failed\n"); + return -1; + } + /* since we just reset the VMCB, return without adjusting + * the eip */ + return 0; + + case VMMCALL_DEBUG: + printf("DEBUG features not implemented yet\n"); + break; + default: + break; + } + + hvm_print_line(v, regs->eax); /* provides the current domain */ + } + else + { + hvm_do_hypercall(regs); + } __update_guest_eip(vmcb, inst_len); return 0; diff --git a/xen/include/asm-x86/hvm/svm/vmmcall.h b/xen/include/asm-x86/hvm/svm/vmmcall.h index 41c40473f9..7587bab7c6 100644 --- a/xen/include/asm-x86/hvm/svm/vmmcall.h +++ b/xen/include/asm-x86/hvm/svm/vmmcall.h @@ -23,11 +23,11 @@ #define __ASM_X86_HVM_SVM_VMMCALL_H__ /* VMMCALL command fields */ -#define VMMCALL_CODE_CPL_MASK 0xC0000000 -#define VMMCALL_CODE_MBZ_MASK 0x3FFF0000 +#define VMMCALL_CODE_CPL_MASK 0x60000000 +#define VMMCALL_CODE_MBZ_MASK 0x1FFF0000 #define VMMCALL_CODE_COMMAND_MASK 0x0000FFFF -#define MAKE_VMMCALL_CODE(cpl,func) ((cpl << 30) | (func)) +#define MAKE_VMMCALL_CODE(cpl,func) ((cpl << 29) | (func) | 0x80000000) /* CPL=0 VMMCALL Requests */ #define VMMCALL_RESET_TO_REALMODE MAKE_VMMCALL_CODE(0,1) @@ -38,7 +38,7 @@ /* return the cpl required for the vmmcall cmd */ static inline int get_vmmcall_cpl(int cmd) { - return (cmd & VMMCALL_CODE_CPL_MASK) >> 30; + return (cmd & VMMCALL_CODE_CPL_MASK) >> 29; } #endif /* __ASM_X86_HVM_SVM_VMMCALL_H__ */ From 0d3e2626204a6e2e2f7c7754e47f191041bd22b3 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 17:47:01 +0100 Subject: [PATCH 037/111] [XEN] Fix 32-bit build. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/hvm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index f4dee16ecc..4120505a8b 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -335,7 +335,7 @@ void hvm_print_line(struct vcpu *v, const char c) typedef unsigned long hvm_hypercall_t( unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); #define HYPERCALL(x) [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x -static hvm_hypercall_handler *hvm_hypercall_table[] = { +static hvm_hypercall_t *hvm_hypercall_table[] = { HYPERCALL(mmu_update), HYPERCALL(memory_op), HYPERCALL(multicall), @@ -343,8 +343,8 @@ static hvm_hypercall_handler *hvm_hypercall_table[] = { HYPERCALL(event_channel_op_compat), HYPERCALL(xen_version), HYPERCALL(grant_table_op), - HYPERCALL(event_channel_op), - HYPERCALL(hvm_op) + HYPERCALL(event_channel_op) + /*HYPERCALL(hvm_op)*/ }; #undef HYPERCALL From ad3b5ffb6a258e9536900c788eac5de023242d1b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 17:47:21 +0100 Subject: [PATCH 038/111] [TOOLS] Clean up libxenstore.a on 'make clean'. Signed-off-by: Keir Fraser --- tools/xenstore/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index a504ac2645..53f3467465 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -102,7 +102,7 @@ libxenstore.a: xs.o xs_lib.o .PHONY: clean clean: testsuite-clean - rm -f *.o *.opic *.so* + rm -f *.a *.o *.opic *.so* rm -f xenstored xs_random xs_stress xs_crashme rm -f xs_test xenstored_test xs_tdb_dump xenstore-control xenstore-ls rm -f $(CLIENTS) From 7005c6cd935be8bdd18b899cc7342f3e40a265d0 Mon Sep 17 00:00:00 2001 From: "jchesterfield@dhcp92.uk.xensource.com" Date: Tue, 1 Aug 2006 17:59:27 +0100 Subject: [PATCH 039/111] Switch blktapctrl.c over to using standard system daemon(3) call. Current patch was not closing all FDs and redirecting output to /dev/null, preventing tapdisk from launching correctly. --- tools/blktap/drivers/blktapctrl.c | 54 ++++++++++--------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/tools/blktap/drivers/blktapctrl.c b/tools/blktap/drivers/blktapctrl.c index 14a86d9088..3e535b9fec 100644 --- a/tools/blktap/drivers/blktapctrl.c +++ b/tools/blktap/drivers/blktapctrl.c @@ -61,6 +61,7 @@ #define MSG_SIZE 4096 #define MAX_TIMEOUT 10 #define MAX_RAND_VAL 0xFFFF +#define MAX_ATTEMPTS 10 int run = 1; int max_timeout = MAX_TIMEOUT; @@ -622,50 +623,18 @@ static void print_drivers(void) DPRINTF("Found driver: [%s]\n",dtypes[i]->name); } -/* Stevens. */ -static void daemonize(void) -{ - pid_t pid; - - /* Separate from our parent via fork, so init inherits us. */ - if ((pid = fork()) < 0) - DPRINTF("Failed to fork daemon\n"); - if (pid != 0) - exit(0); - - /* Session leader so ^C doesn't whack us. */ - setsid(); - - /* Let session leader exit so child cannot regain CTTY */ - if ((pid = fork()) < 0) - DPRINTF("Failed to fork daemon\n"); - if (pid != 0) - exit(0); - - /* Move off any mount points we might be in. */ - if (chdir("/") == -1) - DPRINTF("Failed to chdir\n"); - - /* Discard our parent's old-fashioned umask prejudices. */ - umask(0); - - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); -} - int main(int argc, char *argv[]) { char *devname; tapdev_info_t *ctlinfo; - int tap_pfd, store_pfd, xs_fd, ret, timeout, pfd_count; + int tap_pfd, store_pfd, xs_fd, ret, timeout, pfd_count, count=0; struct xs_handle *h; struct pollfd pfd[NUM_POLL_FDS]; pid_t process; __init_blkif(); openlog("BLKTAPCTRL", LOG_CONS|LOG_ODELAY, LOG_DAEMON); - daemonize(); + daemon(0,0); print_drivers(); init_driver_list(); @@ -684,18 +653,28 @@ int main(int argc, char *argv[]) goto open_failed; } + retry: /* Set up store connection and watch. */ h = xs_daemon_open(); if (h == NULL) { DPRINTF("xs_daemon_open failed -- " "is xenstore running?\n"); - goto open_failed; + if (count < MAX_ATTEMPTS) { + count++; + sleep(2); + goto retry; + } else goto open_failed; } ret = add_blockdevice_probe_watch(h, "Domain-0"); if (ret != 0) { - DPRINTF("adding device probewatch\n"); - goto open_failed; + DPRINTF("Failed adding device probewatch\n"); + if (count < MAX_ATTEMPTS) { + count++; + sleep(2); + xs_daemon_close(h); + goto retry; + } else goto open_failed; } ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE ); @@ -724,6 +703,7 @@ int main(int argc, char *argv[]) } } + xs_daemon_close(h); ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH ); close(ctlfd); closelog(); From 6c8184a0a36971143661f2aba3ffb35876ade706 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 1 Aug 2006 18:06:44 +0100 Subject: [PATCH 040/111] [LINUX] Fix save/restore (broken by my own GSO tweaks). Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 3be2e87a7c..7644b09b86 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -1388,7 +1388,7 @@ static void network_connect(struct net_device *dev) gnttab_grant_foreign_transfer_ref( ref, np->xbdev->otherend_id, - page_to_pfn(skb_shinfo(np->rx_skbs[i])->frags->page)); + page_to_pfn(skb_shinfo(skb)->frags->page)); RING_GET_REQUEST(&np->rx, requeue_idx)->gref = ref; RING_GET_REQUEST(&np->rx, requeue_idx)->id = requeue_idx; From bef5a7699a6b0c665bddadf91691a46e7d39b8d5 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 09:15:26 +0100 Subject: [PATCH 041/111] [PCI] back: Fix potential infinite loop in pcistub_match_one(). The for loop in pcistub_match_one will loop forever if the dev->bus->self links to itself at the uppermost bridge. Adding a check to prevent linking back in on itself prevents this. Signed-off-by: Jon Mason --- linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c index aab9238c2d..b33855932d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c @@ -232,6 +232,10 @@ static int __devinit pcistub_match_one(struct pci_dev *dev, && dev->bus->number == pdev_id->bus && dev->devfn == pdev_id->devfn) return 1; + + /* Sometimes topmost bridge links to itself. */ + if (dev == dev->bus->self) + break; } return 0; From 63c35d035176c976fb33ed15877ce5e341b774ea Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 09:16:26 +0100 Subject: [PATCH 042/111] [TOOLS] ppc64 is not a LIB_64_ARCH Signed-off-by: Jimi Xenidis --- tools/python/xen/util/auxbin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/util/auxbin.py b/tools/python/xen/util/auxbin.py index ba8aba182a..50450773dd 100644 --- a/tools/python/xen/util/auxbin.py +++ b/tools/python/xen/util/auxbin.py @@ -21,8 +21,8 @@ LIB_64 = "/usr/lib64" LIB_BIN_SUFFIX = "xen/bin" ## The architectures on which the LIB_64 directory is used. This -# deliberately excludes ia64. -LIB_64_ARCHS = [ 'x86_64', 'ppc64', 's390x', 'sparc64'] +# deliberately excludes ia64 and ppc64. +LIB_64_ARCHS = [ 'x86_64', 's390x', 'sparc64'] import os From 9552068222f0c4a8fd59d53f36331882ad31dafd Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 09:20:09 +0100 Subject: [PATCH 043/111] There is an allocation-failure path in sched_credit.c that BUGs. The attached patch handles this potential failure case more gracefully. Signed-off-by: Charles Coffing --- xen/common/sched_credit.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/xen/common/sched_credit.c b/xen/common/sched_credit.c index 98e1e3e6c1..19cd2426ef 100644 --- a/xen/common/sched_credit.c +++ b/xen/common/sched_credit.c @@ -296,12 +296,17 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new) cpumask_raise_softirq(mask, SCHEDULE_SOFTIRQ); } -static void +static int csched_pcpu_init(int cpu) { struct csched_pcpu *spc; unsigned long flags; + /* Allocate per-PCPU info */ + spc = xmalloc(struct csched_pcpu); + if ( spc == NULL ) + return -1; + spin_lock_irqsave(&csched_priv.lock, flags); /* Initialize/update system-wide config */ @@ -311,9 +316,6 @@ csched_pcpu_init(int cpu) if ( csched_priv.master >= csched_priv.ncpus ) csched_priv.master = cpu; - /* Allocate per-PCPU info */ - spc = xmalloc(struct csched_pcpu); - BUG_ON( spc == NULL ); INIT_LIST_HEAD(&spc->runq); spc->runq_sort_last = csched_priv.runq_sort; schedule_data[cpu].sched_priv = spc; @@ -323,6 +325,8 @@ csched_pcpu_init(int cpu) cpu_set(cpu, csched_priv.idlers); spin_unlock_irqrestore(&csched_priv.lock, flags); + + return 0; } #ifndef NDEBUG @@ -490,7 +494,10 @@ csched_vcpu_init(struct vcpu *vc) /* Allocate per-PCPU info */ if ( unlikely(!CSCHED_PCPU(vc->processor)) ) - csched_pcpu_init(vc->processor); + { + if ( csched_pcpu_init(vc->processor) != 0 ) + return -1; + } CSCHED_VCPU_CHECK(vc); From 8b7270326c6ef21d50193597baf01890765997db Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 09:38:08 +0100 Subject: [PATCH 044/111] [HVM][VMX] Clean up vmx hvm interface functions: 1) define vmx hvm interface functions static. 2) setup hvm interface functions only once. Signed-off-by: Xin Li --- xen/arch/x86/hvm/vmx/vmx.c | 50 +++++++++++++++++------------- xen/include/asm-x86/hvm/vmx/vmcs.h | 1 - 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index f8df7bbcf8..66991e0a0e 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -477,7 +477,7 @@ static void vmx_ctxt_switch_to(struct vcpu *v) vmx_restore_dr(v); } -void stop_vmx(void) +static void stop_vmx(void) { if (read_cr4() & X86_CR4_VMXE) __vmxoff(); @@ -562,7 +562,7 @@ static void fixup_vm86_seg_bases(struct cpu_user_regs *regs) BUG_ON(err); } -void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) +static void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) { vmx_vmcs_enter(v); @@ -588,7 +588,7 @@ void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs) vmx_vmcs_exit(v); } -int vmx_realmode(struct vcpu *v) +static int vmx_realmode(struct vcpu *v) { unsigned long rflags; @@ -596,7 +596,7 @@ int vmx_realmode(struct vcpu *v) return rflags & X86_EFLAGS_VM; } -int vmx_instruction_length(struct vcpu *v) +static int vmx_instruction_length(struct vcpu *v) { unsigned long inst_len; @@ -605,7 +605,7 @@ int vmx_instruction_length(struct vcpu *v) return inst_len; } -unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) +static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) { switch ( num ) { @@ -622,7 +622,7 @@ unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) } /* SMP VMX guest support */ -void vmx_init_ap_context(struct vcpu_guest_context *ctxt, +static void vmx_init_ap_context(struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector) { int i; @@ -669,6 +669,28 @@ static int check_vmx_controls(u32 ctrls, u32 msr) return 1; } +/* Setup HVM interfaces */ +static void vmx_setup_hvm_funcs(void) +{ + if ( hvm_enabled ) + return; + + hvm_funcs.disable = stop_vmx; + + hvm_funcs.initialize_guest_resources = vmx_initialize_guest_resources; + hvm_funcs.relinquish_guest_resources = vmx_relinquish_guest_resources; + + hvm_funcs.store_cpu_guest_regs = vmx_store_cpu_guest_regs; + hvm_funcs.load_cpu_guest_regs = vmx_load_cpu_guest_regs; + + hvm_funcs.realmode = vmx_realmode; + hvm_funcs.paging_enabled = vmx_paging_enabled; + hvm_funcs.instruction_length = vmx_instruction_length; + hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; + + hvm_funcs.init_ap_context = vmx_init_ap_context; +} + static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page) { char *p; @@ -755,21 +777,7 @@ int start_vmx(void) vmx_save_init_msrs(); - /* Setup HVM interfaces */ - hvm_funcs.disable = stop_vmx; - - hvm_funcs.initialize_guest_resources = vmx_initialize_guest_resources; - hvm_funcs.relinquish_guest_resources = vmx_relinquish_guest_resources; - - hvm_funcs.store_cpu_guest_regs = vmx_store_cpu_guest_regs; - hvm_funcs.load_cpu_guest_regs = vmx_load_cpu_guest_regs; - - hvm_funcs.realmode = vmx_realmode; - hvm_funcs.paging_enabled = vmx_paging_enabled; - hvm_funcs.instruction_length = vmx_instruction_length; - hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; - - hvm_funcs.init_ap_context = vmx_init_ap_context; + vmx_setup_hvm_funcs(); hvm_funcs.init_hypercall_page = vmx_init_hypercall_page; diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index 2b14b7c420..2886f51b6d 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -25,7 +25,6 @@ #include extern int start_vmx(void); -extern void stop_vmx(void); extern void vmcs_dump_vcpu(void); extern void vmx_init_vmcs_config(void); From ed3a5e71bdb56894bd9d92181b0a3e8ceb3c4c77 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 09:52:03 +0100 Subject: [PATCH 045/111] [HVM] Initialise full regs structure for PIO requests. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/io.c | 5 ++--- xen/arch/x86/hvm/platform.c | 1 - xen/arch/x86/hvm/svm/svm.c | 1 + xen/arch/x86/hvm/vmx/vmx.c | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 4be6afdc01..6549f8946d 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -695,12 +695,11 @@ void hvm_io_assist(struct vcpu *v) if ( p->type == IOREQ_TYPE_PIO ) hvm_pio_assist(regs, p, io_opp); - else { + else hvm_mmio_assist(regs, p, io_opp); - hvm_load_cpu_guest_regs(v, regs); - } /* Copy register changes back into current guest state. */ + hvm_load_cpu_guest_regs(v, regs); memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); } /* else an interrupt send event raced us */ diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index d2044fca43..1b5c5966af 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -827,7 +827,6 @@ void handle_mmio(unsigned long va, unsigned long gpa) /* Copy current guest state into io instruction state structure. */ memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES); - hvm_store_cpu_guest_regs(v, regs, NULL); if ((inst_len = hvm_instruction_length(v)) <= 0) { diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 4490bd7f5f..01d48b2524 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1416,6 +1416,7 @@ static void svm_io_instruction(struct vcpu *v) /* Copy current guest state into io instruction state structure. */ memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES); + hvm_store_cpu_guest_regs(v, regs, NULL); info.bytes = vmcb->exitinfo1; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 66991e0a0e..6dfea007aa 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1107,6 +1107,7 @@ static void vmx_io_instruction(unsigned long exit_qualification, /* Copy current guest state into io instruction state structure. */ memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES); + hvm_store_cpu_guest_regs(current, regs, NULL); __vmread(GUEST_RIP, &eip); __vmread(GUEST_CS_SELECTOR, &cs); From 0baacdb68b0b2910d5309a207598d91b354d2af5 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Wed, 2 Aug 2006 09:54:32 +0100 Subject: [PATCH 046/111] Update patch to reflect changes from 10867:edf7a25fdc43. Signed-off-by: Christian Limpach --- tools/ioemu/patches/ioemu-ia64 | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/ioemu/patches/ioemu-ia64 b/tools/ioemu/patches/ioemu-ia64 index 4bf197f66a..0fc91b92ee 100644 --- a/tools/ioemu/patches/ioemu-ia64 +++ b/tools/ioemu/patches/ioemu-ia64 @@ -1,7 +1,7 @@ Index: ioemu/hw/iommu.c =================================================================== ---- ioemu.orig/hw/iommu.c 2006-07-28 09:56:58.571272016 +0100 -+++ ioemu/hw/iommu.c 2006-07-28 10:02:10.171049510 +0100 +--- ioemu.orig/hw/iommu.c 2006-08-02 09:46:38.774790244 +0100 ++++ ioemu/hw/iommu.c 2006-08-02 09:46:39.030761544 +0100 @@ -82,7 +82,11 @@ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -16,8 +16,8 @@ Index: ioemu/hw/iommu.c Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-07-28 09:58:38.815935452 +0100 -+++ ioemu/cpu-all.h 2006-07-28 10:02:10.171049510 +0100 +--- ioemu.orig/cpu-all.h 2006-08-02 09:46:38.969768383 +0100 ++++ ioemu/cpu-all.h 2006-08-02 09:46:39.030761544 +0100 @@ -835,6 +835,31 @@ :"=m" (*(volatile long *)addr) :"dIr" (nr)); @@ -52,8 +52,8 @@ Index: ioemu/cpu-all.h /* memory API */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-28 09:58:59.672577418 +0100 -+++ ioemu/vl.c 2006-07-28 10:02:10.174049171 +0100 +--- ioemu.orig/vl.c 2006-08-02 09:46:39.020762665 +0100 ++++ ioemu/vl.c 2006-08-02 09:47:02.896085814 +0100 @@ -5578,6 +5578,7 @@ exit(-1); } @@ -82,7 +82,7 @@ Index: ioemu/vl.c + } + + if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, -+ nr_pages + (GFW_SIZE >> PAGE_SHIFT), 1)!= 1){ ++ IO_PAGE_START >> PAGE_SHIFT, 1) != 1){ + fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); + exit(-1); + } @@ -91,7 +91,7 @@ Index: ioemu/vl.c + PROT_READ|PROT_WRITE, + page_array[0]); + -+ fprintf(logfile, "shared page at pfn:%lx, mfn: %l016x\n", ++ fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n", + IO_PAGE_START >> PAGE_SHIFT, page_array[0]); +#endif #else /* !CONFIG_DM */ @@ -99,8 +99,8 @@ Index: ioemu/vl.c #ifdef CONFIG_SOFTMMU Index: ioemu/target-i386-dm/exec-dm.c =================================================================== ---- ioemu.orig/target-i386-dm/exec-dm.c 2006-07-28 09:58:22.882736989 +0100 -+++ ioemu/target-i386-dm/exec-dm.c 2006-07-28 10:03:19.972165675 +0100 +--- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-02 09:46:38.903775782 +0100 ++++ ioemu/target-i386-dm/exec-dm.c 2006-08-02 09:46:39.034761096 +0100 @@ -341,6 +341,23 @@ return io_mem_read[io_index >> IO_MEM_SHIFT]; } @@ -137,8 +137,8 @@ Index: ioemu/target-i386-dm/exec-dm.c memset(buf, 0xff, len); Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-07-28 09:56:58.572271903 +0100 -+++ ioemu/exec-all.h 2006-07-28 10:02:10.175049059 +0100 +--- ioemu.orig/exec-all.h 2006-08-02 09:46:38.881778248 +0100 ++++ ioemu/exec-all.h 2006-08-02 09:46:39.034761096 +0100 @@ -462,12 +462,13 @@ } #endif @@ -158,8 +158,8 @@ Index: ioemu/exec-all.h Index: ioemu/target-i386-dm/cpu.h =================================================================== ---- ioemu.orig/target-i386-dm/cpu.h 2006-07-28 09:56:58.572271903 +0100 -+++ ioemu/target-i386-dm/cpu.h 2006-07-28 10:02:10.175049059 +0100 +--- ioemu.orig/target-i386-dm/cpu.h 2006-08-02 09:46:38.902775894 +0100 ++++ ioemu/target-i386-dm/cpu.h 2006-08-02 09:46:39.034761096 +0100 @@ -80,7 +80,11 @@ /* helper2.c */ int main_loop(void); @@ -175,7 +175,7 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/ia64_intrinsic.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/ia64_intrinsic.h 2006-07-28 10:02:10.176048946 +0100 ++++ ioemu/ia64_intrinsic.h 2006-08-02 09:46:39.035760983 +0100 @@ -0,0 +1,276 @@ +#ifndef IA64_INTRINSIC_H +#define IA64_INTRINSIC_H From 7dcaf7de5f023533592bff28a77f28930f66636d Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 09:58:06 +0100 Subject: [PATCH 047/111] [SHADOW] Build p2m mapping according to m2p mapping. Signed-off-by: Xin Li Signed-off-by: Yunhong Jiang --- xen/arch/x86/shadow32.c | 6 ++++-- xen/arch/x86/shadow_public.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/shadow32.c b/xen/arch/x86/shadow32.c index 8dece9d52a..a2c82138c3 100644 --- a/xen/arch/x86/shadow32.c +++ b/xen/arch/x86/shadow32.c @@ -990,18 +990,20 @@ alloc_p2m_table(struct domain *d) list_ent = d->page_list.next; - for ( gpfn = 0; list_ent != &d->page_list; gpfn++ ) + while ( list_ent != &d->page_list ) { page = list_entry(list_ent, struct page_info, list); mfn = page_to_mfn(page); + gpfn = get_gpfn_from_mfn(mfn); + if ( !(error = map_p2m_entry(l1tab, gpfn, mfn)) ) { domain_crash(d); break; } - list_ent = frame_table[mfn].list.next; + list_ent = page->list.next; } unmap_domain_page(l1tab); diff --git a/xen/arch/x86/shadow_public.c b/xen/arch/x86/shadow_public.c index 44833b68bc..9350aa6d72 100644 --- a/xen/arch/x86/shadow_public.c +++ b/xen/arch/x86/shadow_public.c @@ -1617,20 +1617,22 @@ alloc_p2m_table(struct domain *d) list_ent = d->page_list.next; - for ( gpfn = 0; list_ent != &d->page_list; gpfn++ ) + while ( list_ent != &d->page_list ) { struct page_info *page; page = list_entry(list_ent, struct page_info, list); mfn = page_to_mfn(page); + gpfn = get_gpfn_from_mfn(mfn); + if ( !(error = map_p2m_entry(top_tab, gpfn, mfn)) ) { domain_crash(d); break; } - list_ent = frame_table[mfn].list.next; + list_ent = page->list.next; } unmap_domain_page(top_tab); From f0667416beecf35efc429978ffc98ba4d418c01f Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 10:03:04 +0100 Subject: [PATCH 048/111] [VMXASSIST] Fix GDTR accesses when paging mode enabled. The gdtr information in oldctx is an address for guest, not for vmxassist. When access descriptor on guest gdt, we need to go through guest page table if guest enable paging. This error may happen if guest enable PE/PG in one instruction. Signed-off-by: Yunhong Jiang =20 Signed-off-by: Xin Li --- tools/firmware/vmxassist/vm86.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c index edb7dd685b..67bd2d0f7b 100644 --- a/tools/firmware/vmxassist/vm86.c +++ b/tools/firmware/vmxassist/vm86.c @@ -52,6 +52,31 @@ char *states[] = { static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; #endif /* DEBUG */ +#define PT_ENTRY_PRESENT 0x1 + +static unsigned +guest_linear_to_real(unsigned long base, unsigned off) +{ + unsigned int gcr3 = oldctx.cr3; + unsigned int l1_mfn; + unsigned int l0_mfn; + + if (!(oldctx.cr0 & CR0_PG)) + return base + off; + + l1_mfn = ((unsigned int *)gcr3)[(base >> 22) & 0x3ff ]; + if (!(l1_mfn & PT_ENTRY_PRESENT)) + panic("l2 entry not present\n"); + l1_mfn = l1_mfn & 0xfffff000 ; + + l0_mfn = ((unsigned int *)l1_mfn)[(base >> 12) & 0x3ff]; + if (!(l0_mfn & PT_ENTRY_PRESENT)) + panic("l1 entry not present\n"); + l0_mfn = l0_mfn & 0xfffff000; + + return l0_mfn + off + (base & 0xfff); +} + static unsigned address(struct regs *regs, unsigned seg, unsigned off) { @@ -70,7 +95,7 @@ address(struct regs *regs, unsigned seg, unsigned off) (mode == VM86_REAL_TO_PROTECTED && regs->cs == seg)) return ((seg & 0xFFFF) << 4) + off; - entry = ((unsigned long long *) oldctx.gdtr_base)[seg >> 3]; + entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base, 0))[seg >> 3]; entry_high = entry >> 32; entry_low = entry & 0xFFFFFFFF; @@ -94,7 +119,7 @@ void trace(struct regs *regs, int adjust, char *fmt, ...) { unsigned off = regs->eip - adjust; - va_list ap; + va_list ap; if ((traceset & (1 << mode)) && (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) { @@ -755,7 +780,7 @@ load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes return 1; } - entry = ((unsigned long long *) oldctx.gdtr_base)[sel >> 3]; + entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base, 0))[sel >> 3]; /* Check the P bit first */ if (!((entry >> (15+32)) & 0x1) && sel != 0) From 0496f983a21720b7f59ee7243316b1e2e4cdf5b8 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 10:04:27 +0100 Subject: [PATCH 049/111] [HVM] Fix an issue with APIC priority checks. Signed-off-by; Yunhong Jiang --- xen/arch/x86/hvm/vlapic.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 900a98e485..1257d592be 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -210,7 +210,7 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode, if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) ) break; - if ( test_and_set_bit(vector, &vlapic->irr[0]) ) + if ( test_and_set_bit(vector, &vlapic->irr[0]) && level) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "level trig mode repeatedly for vector %d\n", vector); @@ -922,7 +922,8 @@ int cpu_get_apic_interrupt(struct vcpu *v, int *mode) { int highest_irr = vlapic_find_highest_irr(vlapic); - if ( highest_irr != -1 && highest_irr >= vlapic->processor_priority ) + if ( highest_irr != -1 && + ( (highest_irr & 0xF0) > vlapic->processor_priority ) ) { if ( highest_irr < 0x10 ) { @@ -952,7 +953,8 @@ int cpu_has_apic_interrupt(struct vcpu* v) if (vlapic && vlapic_enabled(vlapic)) { int highest_irr = vlapic_find_highest_irr(vlapic); - if (highest_irr != -1 && highest_irr >= vlapic->processor_priority) { + if ( highest_irr != -1 && + ( (highest_irr & 0xF0) > vlapic->processor_priority ) ) { return 1; } } From 50b3cef2eecb02429356b1d8e7a766d5e98f3c2a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 10:07:03 +0100 Subject: [PATCH 050/111] [HVM] Place all APIC registers into one page in native format. With this change we can re-use code at include/asm-x86/apicdef.h, making the code much cleaner. Also it help for future enhancement. This patch does not change any logic except the change to CONTROL_REG_ACCESS_NUM, which should be 0xf for CR8 access. Signed-off-by: Yunhong Jiang domain->arch.hvm_domain.vpic.pics[0].irq_base; else pit_vec = diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c index a4e752db59..fbcf60632f 100644 --- a/xen/arch/x86/hvm/svm/intr.c +++ b/xen/arch/x86/hvm/svm/intr.c @@ -76,7 +76,7 @@ interrupt_post_injection(struct vcpu * v, int vector, int type) switch(type) { - case VLAPIC_DELIV_MODE_EXT: + case APIC_DM_EXTINT: break; default: @@ -112,7 +112,7 @@ asmlinkage void svm_intr_assist(void) struct hvm_domain *plat=&v->domain->arch.hvm_domain; struct periodic_time *pt = &plat->pl_time.periodic_tm; struct hvm_virpic *pic= &plat->vpic; - int intr_type = VLAPIC_DELIV_MODE_EXT; + int intr_type = APIC_DM_EXTINT; int intr_vector = -1; int re_injecting = 0; unsigned long rflags; @@ -172,9 +172,9 @@ asmlinkage void svm_intr_assist(void) /* have we got an interrupt to inject? */ if (intr_vector >= 0) { switch (intr_type) { - case VLAPIC_DELIV_MODE_EXT: - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: + case APIC_DM_EXTINT: + case APIC_DM_FIXED: + case APIC_DM_LOWEST: /* Re-injecting a PIT interruptt? */ if (re_injecting && is_pit_irq(v, intr_vector, intr_type)) { @@ -185,10 +185,10 @@ asmlinkage void svm_intr_assist(void) svm_inject_extint(v, intr_vector, VMX_DELIVER_NO_ERROR_CODE); interrupt_post_injection(v, intr_vector, intr_type); break; - case VLAPIC_DELIV_MODE_SMI: - case VLAPIC_DELIV_MODE_NMI: - case VLAPIC_DELIV_MODE_INIT: - case VLAPIC_DELIV_MODE_STARTUP: + case APIC_DM_SMI: + case APIC_DM_NMI: + case APIC_DM_INIT: + case APIC_DM_STARTUP: default: printk("Unsupported interrupt type: %d\n", intr_type); BUG(); diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index cf50014380..f69ae45bd6 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -197,7 +197,7 @@ static void hvm_vioapic_write_indirect(struct hvm_vioapic *s, redir_content = ((redir_content >> 32) << 32) | (val & 0xffffffff); s->redirtbl[redir_index].value = redir_content; - hvm_vioapic_update_imr(s, redir_index); + hvm_vioapic_update_imr(s, redir_index); } else { printk("hvm_vioapic_write_indirect " "error register %x\n", s->ioregsel); @@ -295,8 +295,8 @@ static int ioapic_inj_irq(hvm_vioapic_t *s, vector, trig_mode, delivery_mode); switch (delivery_mode) { - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: + case dest_Fixed: + case dest_LowestPrio: if (vlapic_set_irq(target, vector, trig_mode) && (trig_mode == 1)) printk(" level interrupt happen before cleared\n"); result = 1; @@ -314,6 +314,7 @@ static int ioapic_inj_irq(hvm_vioapic_t *s, static int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint8_t dest) { int result = 0; + uint32_t logical_dest = vlapic_get_reg(s->lapic_info[number], APIC_LDR); ASSERT(s && s->lapic_info[number]); @@ -321,17 +322,17 @@ static int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint8_t dest) "number %i dest %x\n", number, dest); - switch (((s->lapic_info[number]->dest_format >> 28) & 0xf)) { - case 0xf: + switch (vlapic_get_reg(s->lapic_info[number], APIC_DFR)) + { + case APIC_DFR_FLAT: result = - (dest & ((s->lapic_info[number]->logical_dest >> 24) & 0xff)) != 0; + (dest & GET_APIC_LOGICAL_ID(logical_dest)) != 0; break; - case 0x0: + case APIC_DFR_CLUSTER: /* Should we support flat cluster mode ?*/ - if ( ((s->lapic_info[number]->logical_dest >> 28) + if ( (GET_APIC_LOGICAL_ID(logical_dest) >> 4 == ((dest >> 0x4) & 0xf)) && - (((s->lapic_info[number]->logical_dest >> 24) & 0xf) - & (dest & 0xf)) ) + (logical_dest & (dest & 0xf)) ) result = 1; break; default: @@ -410,7 +411,7 @@ static void ioapic_deliver(hvm_vioapic_t *s, int irqno) } switch (delivery_mode) { - case VLAPIC_DELIV_MODE_LPRI: + case dest_LowestPrio: { struct vlapic* target; @@ -430,8 +431,8 @@ static void ioapic_deliver(hvm_vioapic_t *s, int irqno) break; } - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_EXT: + case dest_Fixed: + case dest_ExtINT: { uint8_t bit; for (bit = 0; bit < s->lapic_count; bit++) { @@ -452,10 +453,10 @@ static void ioapic_deliver(hvm_vioapic_t *s, int irqno) break; } - case VLAPIC_DELIV_MODE_SMI: - case VLAPIC_DELIV_MODE_NMI: - case VLAPIC_DELIV_MODE_INIT: - case VLAPIC_DELIV_MODE_STARTUP: + case dest_SMI: + case dest_NMI: + case dest_INIT: + case dest__reserved_2: default: printk("Not support delivey mode %d\n", delivery_mode); break; diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 1257d592be..d87be427bb 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -43,35 +43,43 @@ extern u32 get_apic_bus_cycle(void); static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] = { - 0x310ff, 0x117ff, 0x117ff, 0x1f7ff, 0x1f7ff, 0x117ff + /* LVTT */ + LVT_MASK | APIC_LVT_TIMER_PERIODIC, + /* LVTTHMR */ + LVT_MASK | APIC_MODE_MASK, + /* LVTPC */ + LVT_MASK | APIC_MODE_MASK, + /* LVT0-1 */ + LINT_MASK, LINT_MASK, + /* LVTERR */ + LVT_MASK }; -int vlapic_find_highest_irr(struct vlapic *vlapic) -{ - int result; - - result = find_highest_bit(vlapic->irr, MAX_VECTOR); - - if ( result != -1 && result < 16 ) - { - printk("VLAPIC: irr on reserved bits %d\n ", result); - domain_crash_synchronous(); - } - - return result; -} - int hvm_apic_support(struct domain *d) { return d->arch.hvm_domain.apic_enabled; } +int vlapic_find_highest_irr(struct vlapic *vlapic) +{ + int result; + + result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_IRR), + MAX_VECTOR); + + ASSERT( result == -1 || result > 16); + + return result; +} + s_time_t get_apictime_scheduled(struct vcpu *v) { struct vlapic *vlapic = VLAPIC(v); - if ( !hvm_apic_support(v->domain) || !vlapic_lvt_timer_enabled(vlapic) ) + if ( !hvm_apic_support(v->domain) || + !vlapic_lvt_enabled(vlapic, APIC_LVTT) ) return -1; + return vlapic->vlapic_timer.expires; } @@ -79,16 +87,10 @@ int vlapic_find_highest_isr(struct vlapic *vlapic) { int result; - result = find_highest_bit(vlapic->isr, MAX_VECTOR); + result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_ISR), + MAX_VECTOR); - if ( result != -1 && result < 16 ) - { - int i = 0; - printk("VLAPIC: isr on reserved bits %d, isr is\n ", result); - for ( i = 0; i < ARRAY_SIZE(vlapic->isr); i++ ) - printk("%d: %p\n", i, (void *)vlapic->isr[i]); - return -1; - } + ASSERT( result == -1 || result > 16); return result; } @@ -98,20 +100,21 @@ uint32_t vlapic_update_ppr(struct vlapic *vlapic) uint32_t tpr, isrv, ppr; int isr; - tpr = (vlapic->task_priority >> 4) & 0xf; /* we want 7:4 */ + tpr = vlapic_get_reg(vlapic, APIC_TASKPRI); isr = vlapic_find_highest_isr(vlapic); + if ( isr != -1 ) isrv = (isr >> 4) & 0xf; /* ditto */ else isrv = 0; - if ( tpr >= isrv ) - ppr = vlapic->task_priority & 0xff; + if ( (tpr >> 4) >= isrv ) + ppr = tpr & 0xff; else ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */ - vlapic->processor_priority = ppr; + vlapic_set_reg(vlapic, APIC_PROCPRI, ppr); HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT, "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x.", @@ -133,9 +136,9 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source, target, source, dest, dest_mode, short_hand, delivery_mode); if ( unlikely(target == NULL) && - ((delivery_mode != VLAPIC_DELIV_MODE_INIT) && - (delivery_mode != VLAPIC_DELIV_MODE_STARTUP) && - (delivery_mode != VLAPIC_DELIV_MODE_NMI)) ) + ((delivery_mode != APIC_DM_INIT) && + (delivery_mode != APIC_DM_STARTUP) && + (delivery_mode != APIC_DM_NMI)) ) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, " "delivery_mode 0x%x, dest 0x%x.\n", v, delivery_mode, dest); @@ -143,22 +146,27 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source, } switch ( short_hand ) { - case VLAPIC_NO_SHORTHAND: + case APIC_DEST_NOSHORT: /* no shorthand */ if ( !dest_mode ) /* Physical */ { - result = (target != NULL ? target->id : v->vcpu_id) == dest; + result = ( ((target != NULL) ? + GET_APIC_ID(vlapic_get_reg(target, APIC_ID)): + v->vcpu_id)) == dest; } else /* Logical */ { + uint32_t ldr = vlapic_get_reg(target, APIC_LDR); + if ( target == NULL ) break; - if ( ((target->dest_format >> 28) & 0xf) == 0xf ) /* Flat mode */ + /* Flat mode */ + if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT) { - result = (target->logical_dest >> 24) & dest; + result = GET_APIC_LOGICAL_ID(ldr) & dest; } else { - if ( (delivery_mode == VLAPIC_DELIV_MODE_LPRI) && + if ( (delivery_mode == APIC_DM_LOWEST) && (dest == 0xff) ) { /* What shall we do now? */ @@ -166,22 +174,22 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source, "delivery mode\n"); domain_crash_synchronous(); } - result = (target->logical_dest == (dest & 0xf)) ? - ((target->logical_dest >> 4) & (dest >> 4)) : 0; + result = (GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ? + (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0; } } break; - case VLAPIC_SHORTHAND_SELF: + case APIC_DEST_SELF: if ( target == source ) result = 1; break; - case VLAPIC_SHORTHAND_INCLUDE_SELF: + case APIC_DEST_ALLINC: result = 1; break; - case VLAPIC_SHORTHAND_EXCLUDE_SELF: + case APIC_DEST_ALLBUT: if ( target != source ) result = 1; break; @@ -204,13 +212,13 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode, struct vlapic *vlapic = VLAPIC(v); switch ( delivery_mode ) { - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: + case APIC_DM_FIXED: + case APIC_DM_LOWEST: /* FIXME add logic for vcpu on reset */ if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) ) break; - if ( test_and_set_bit(vector, &vlapic->irr[0]) && level) + if ( test_and_set_bit(vector, vlapic->regs + APIC_IRR) ) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "level trig mode repeatedly for vector %d\n", vector); @@ -221,25 +229,25 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode, { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "level trig mode for vector %d\n", vector); - set_bit(vector, &vlapic->tmr[0]); + set_bit(vector, vlapic->regs + APIC_TMR); } evtchn_set_pending(v, iopacket_port(v)); result = 1; break; - case VLAPIC_DELIV_MODE_RESERVED: + case APIC_DM_REMRD: printk("Ignore deliver mode 3 in vlapic_accept_irq\n"); break; - case VLAPIC_DELIV_MODE_SMI: - case VLAPIC_DELIV_MODE_NMI: + case APIC_DM_SMI: + case APIC_DM_NMI: /* Fixme */ printk("TODO: for guest SMI/NMI\n"); break; - case VLAPIC_DELIV_MODE_INIT: - if ( !level && trig_mode == 1 ) //Deassert + case APIC_DM_INIT: + if ( level && !(trig_mode & APIC_INT_ASSERT) ) //Deassert printk("This hvm_vlapic is for P4, no work for De-assert init\n"); else { @@ -255,7 +263,7 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode, } break; - case VLAPIC_DELIV_MODE_STARTUP: + case APIC_DM_STARTUP: if ( v->arch.hvm_vcpu.init_sipi_sipi_state == HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM ) break; @@ -346,22 +354,23 @@ void vlapic_EOI_set(struct vlapic *vlapic) if ( vector == -1 ) return ; - clear_bit(vector, &vlapic->isr[0]); + clear_bit(vector, vlapic->regs + APIC_ISR); vlapic_update_ppr(vlapic); - if ( test_and_clear_bit(vector, &vlapic->tmr[0]) ) + if ( test_and_clear_bit(vector, vlapic->regs + APIC_TMR) ) ioapic_update_EOI(vlapic->domain, vector); } -int vlapic_check_vector(struct vlapic *vlapic, - unsigned char dm, int vector) +static int vlapic_check_vector(struct vlapic *vlapic, + uint32_t dm, uint32_t vector) { - if ( (dm == VLAPIC_DELIV_MODE_FIXED) && (vector < 16) ) + if ( (dm == APIC_DM_FIXED) && (vector < 16) ) { vlapic->err_status |= 0x40; - vlapic_accept_irq(vlapic->vcpu, VLAPIC_DELIV_MODE_FIXED, - vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), 0, 0); - printk(": check failed.\n"); + vlapic_accept_irq(vlapic->vcpu, APIC_DM_FIXED, + vlapic_lvt_vector(vlapic, APIC_LVTERR), 0, 0); + printk(": check failed " + " dm %x vector %x\n", dm, vector); return 0; } return 1; @@ -369,13 +378,16 @@ int vlapic_check_vector(struct vlapic *vlapic, void vlapic_ipi(struct vlapic *vlapic) { - unsigned int dest = (vlapic->icr_high >> 24) & 0xff; - unsigned int short_hand = (vlapic->icr_low >> 18) & 3; - unsigned int trig_mode = (vlapic->icr_low >> 15) & 1; - unsigned int level = (vlapic->icr_low >> 14) & 1; - unsigned int dest_mode = (vlapic->icr_low >> 11) & 1; - unsigned int delivery_mode = (vlapic->icr_low >> 8) & 7; - unsigned int vector = (vlapic->icr_low & 0xff); + uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR); + uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2); + + unsigned int dest = GET_APIC_DEST_FIELD(icr_high); + unsigned int short_hand = icr_low & APIC_SHORT_MASK; + unsigned int trig_mode = icr_low & APIC_INT_ASSERT; + unsigned int level = icr_low & APIC_INT_LEVELTRIG; + unsigned int dest_mode = icr_low & APIC_DEST_MASK; + unsigned int delivery_mode = icr_low & APIC_MODE_MASK; + unsigned int vector = icr_low & APIC_VECTOR_MASK; struct vlapic *target; struct vcpu *v = NULL; @@ -384,7 +396,7 @@ void vlapic_ipi(struct vlapic *vlapic) HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, " "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x.", - vlapic->icr_high, vlapic->icr_low, short_hand, dest, + icr_high, icr_low, short_hand, dest, trig_mode, level, dest_mode, delivery_mode, vector); for_each_vcpu ( vlapic->domain, v ) @@ -392,7 +404,7 @@ void vlapic_ipi(struct vlapic *vlapic) if ( vlapic_match_dest(v, vlapic, short_hand, dest, dest_mode, delivery_mode) ) { - if ( delivery_mode == VLAPIC_DELIV_MODE_LPRI ) + if ( delivery_mode == APIC_DM_LOWEST) set_bit(v->vcpu_id, &lpr_map); else vlapic_accept_irq(v, delivery_mode, @@ -400,7 +412,7 @@ void vlapic_ipi(struct vlapic *vlapic) } } - if ( delivery_mode == VLAPIC_DELIV_MODE_LPRI ) + if ( delivery_mode == APIC_DM_LOWEST) { v = vlapic->vcpu; target = apic_round_robin(v->domain, dest_mode, vector, lpr_map); @@ -411,158 +423,73 @@ void vlapic_ipi(struct vlapic *vlapic) } } +static uint32_t vlapic_get_tmcct(struct vlapic *vlapic) +{ + uint32_t counter_passed; + s_time_t passed, now = NOW(); + uint32_t tmcct = vlapic_get_reg(vlapic, APIC_TMCCT); + + ASSERT(vlapic != NULL); + + if ( unlikely(now <= vlapic->timer_last_update) ) + { + passed = ~0x0LL - vlapic->timer_last_update + now; + HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed."); + } + else + passed = now - vlapic->timer_last_update; + + counter_passed = passed / + (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count); + + tmcct -= counter_passed; + + if ( tmcct <= 0 ) + { + if ( unlikely(!vlapic_lvtt_period(vlapic)) ) + { + tmcct = 0; + // FIXME: should we add interrupt here? + } + else + { + do { + tmcct += vlapic_get_reg(vlapic, APIC_TMICT); + } while ( tmcct < 0 ); + } + } + + vlapic->timer_last_update = now; + vlapic_set_reg(vlapic, APIC_TMCCT, tmcct); + + HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, + "timer initial count 0x%x, timer current count 0x%x, " + "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.", + vlapic_get_reg(vlapic, APIC_TMICT), + vlapic_get_reg(vlapic, APIC_TMCCT), + vlapic->timer_last_update, now, counter_passed); + + return tmcct; +} + static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset, unsigned int len, unsigned int *result) { - if ( len != 4 ) - printk(" read with len=%d (should be 4).\n", len); + ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR); *result = 0; switch ( offset ) { - case APIC_ID: - *result = vlapic->id << 24; - break; - - case APIC_LVR: - *result = vlapic->version; - break; - - case APIC_TASKPRI: - *result = vlapic->task_priority; - break; - case APIC_ARBPRI: printk("access local APIC ARBPRI register which is for P6\n"); break; - case APIC_PROCPRI: - *result = vlapic->processor_priority; - break; - - case APIC_EOI: /* EOI is write only */ - break; - - case APIC_LDR: - *result = vlapic->logical_dest; - break; - - case APIC_DFR: - *result = vlapic->dest_format; - break; - - case APIC_SPIV: - *result = vlapic->spurious_vec; - break; - - case APIC_ISR: - case 0x110: - case 0x120: - case 0x130: - case 0x140: - case 0x150: - case 0x160: - case 0x170: - *result = vlapic->isr[(offset - APIC_ISR) >> 4]; - break; - - case APIC_TMR: - case 0x190: - case 0x1a0: - case 0x1b0: - case 0x1c0: - case 0x1d0: - case 0x1e0: - case 0x1f0: - *result = vlapic->tmr[(offset - APIC_TMR) >> 4]; - break; - - case APIC_IRR: - case 0x210: - case 0x220: - case 0x230: - case 0x240: - case 0x250: - case 0x260: - case 0x270: - *result = vlapic->irr[(offset - APIC_IRR) >> 4]; - break; - - case APIC_ESR: - if ( vlapic->err_write_count ) - *result = vlapic->err_status; - break; - - case APIC_ICR: - *result = vlapic->icr_low; - break; - - case APIC_ICR2: - *result = vlapic->icr_high; - break; - - case APIC_LVTT: /* LVT Timer Reg */ - case APIC_LVTTHMR: /* LVT Thermal Monitor */ - case APIC_LVTPC: /* LVT Performance Counter */ - case APIC_LVT0: /* LVT LINT0 Reg */ - case APIC_LVT1: /* LVT Lint1 Reg */ - case APIC_LVTERR: /* LVT Error Reg */ - *result = vlapic->lvt[(offset - APIC_LVTT) >> 4]; - break; - - case APIC_TMICT: - *result = vlapic->timer_initial_count; - break; - case APIC_TMCCT: //Timer CCR - { - uint32_t counter_passed; - s_time_t passed, now = NOW(); - - if ( unlikely(now <= vlapic->timer_current_update) ) - { - passed = ~0x0LL - vlapic->timer_current_update + now; - HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed."); - } - else - passed = now - vlapic->timer_current_update; - - counter_passed = passed / - (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count); - vlapic->timer_current_count -= counter_passed; - if ( vlapic->timer_current_count <= 0 ) - { - if ( unlikely(!vlapic_lvt_timer_period(vlapic)) ) - { - vlapic->timer_current_count = 0; - // FIXME: should we add interrupt here? - } - else - { - do { - vlapic->timer_current_count += vlapic->timer_initial_count; - } while ( vlapic->timer_current_count < 0 ); - } - } - - *result = vlapic->timer_current_count; - vlapic->timer_current_update = now; - - HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, - "timer initial count 0x%x, timer current count 0x%x, " - "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.", - vlapic->timer_initial_count, vlapic->timer_current_count, - vlapic->timer_current_update, now, counter_passed); - } - break; - - case APIC_TDCR: - *result = vlapic->timer_divconf; + *result = vlapic_get_tmcct(vlapic); break; default: - printk("Read local APIC address 0x%x not implemented\n", offset); - *result = 0; + *result = vlapic_get_reg(vlapic, offset); break; } } @@ -576,6 +503,9 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address, struct vlapic *vlapic = VLAPIC(v); unsigned int offset = address - vlapic->base_address; + if ( offset > APIC_TDCR) + return 0; + /* some bugs on kernel cause read this with byte*/ if ( len != 4 ) HVM_DBG_LOG(DBG_LEVEL_VLAPIC, @@ -671,11 +601,11 @@ static void vlapic_write(struct vcpu *v, unsigned long address, switch ( offset ) { case APIC_ID: /* Local APIC ID */ - vlapic->id = ((val) >> 24) & VAPIC_ID_MASK; + vlapic_set_reg(vlapic, APIC_ID, val); break; case APIC_TASKPRI: - vlapic->task_priority = val & 0xff; + vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff); vlapic_update_ppr(vlapic); break; @@ -684,24 +614,41 @@ static void vlapic_write(struct vcpu *v, unsigned long address, break; case APIC_LDR: - vlapic->logical_dest = val & VAPIC_LDR_MASK; + vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK); break; case APIC_DFR: - vlapic->dest_format = val ; + vlapic_set_reg(vlapic, APIC_DFR, val); break; case APIC_SPIV: - vlapic->spurious_vec = val & 0x1ff; - if ( !(vlapic->spurious_vec & 0x100) ) + vlapic_set_reg(vlapic, APIC_SPIV, val & 0x1ff); + + if ( !( val & APIC_SPIV_APIC_ENABLED) ) { int i; - for ( i = 0; i < VLAPIC_LVT_NUM; i++ ) - vlapic->lvt[i] |= 0x10000; + uint32_t lvt_val; + vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK; + + for ( i = 0; i < VLAPIC_LVT_NUM; i++ ) + { + lvt_val = vlapic_get_reg(vlapic, APIC_LVT1 + 0x10 * i); + vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, + lvt_val | APIC_LVT_MASKED); + } + + if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK) + == APIC_DM_EXTINT ) + clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); } else + { vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK; + if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK) + == APIC_DM_EXTINT ) + set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); + } break; case APIC_ESR: @@ -712,12 +659,12 @@ static void vlapic_write(struct vcpu *v, unsigned long address, case APIC_ICR: /* No delay here, so we always clear the pending bit*/ - vlapic->icr_low = val & ~(1 << 12); + vlapic_set_reg(vlapic, APIC_ICR, val & ~(1 << 12)); vlapic_ipi(vlapic); break; case APIC_ICR2: - vlapic->icr_high = val & 0xff000000; + vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000); break; case APIC_LVTT: // LVT Timer Reg @@ -727,26 +674,25 @@ static void vlapic_write(struct vcpu *v, unsigned long address, case APIC_LVT1: // LVT Lint1 Reg case APIC_LVTERR: // LVT Error Reg { - int vt = (offset - APIC_LVTT) >> 4; - - vlapic->lvt[vt] = val & vlapic_lvt_mask[vt]; if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK ) - vlapic->lvt[vt] |= VLAPIC_LVT_BIT_MASK; + val |= APIC_LVT_MASKED; + + val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4]; + + vlapic_set_reg(vlapic, offset, val); /* On hardware, when write vector less than 0x20 will error */ - vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic->lvt[vt]), - vlapic_lvt_vector(vlapic, vt)); + if ( !(val & APIC_LVT_MASKED) ) + vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic, offset), + vlapic_lvt_vector(vlapic, offset)); if ( !vlapic->vcpu_id && (offset == APIC_LVT0) ) { - if ( (vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_DELIMOD) - == 0x700 ) - { - if ( vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_MASK ) + if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT ) + if ( val & APIC_LVT_MASKED) clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); else set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); - } else clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); } @@ -758,16 +704,14 @@ static void vlapic_write(struct vcpu *v, unsigned long address, { s_time_t now = NOW(), offset; - if ( vlapic_timer_active(vlapic) ) - stop_timer(&vlapic->vlapic_timer); + stop_timer(&vlapic->vlapic_timer); - vlapic->timer_initial_count = val; - vlapic->timer_current_count = val; - vlapic->timer_current_update = now; + vlapic_set_reg(vlapic, APIC_TMICT, val); + vlapic_set_reg(vlapic, APIC_TMCCT, val); + vlapic->timer_last_update = now; offset = APIC_BUS_CYCLE_NS * - vlapic->timer_divide_count * - vlapic->timer_initial_count; + vlapic->timer_divide_count * val; set_timer(&vlapic->vlapic_timer, now + offset); @@ -775,7 +719,8 @@ static void vlapic_write(struct vcpu *v, unsigned long address, "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", " "timer initial count 0x%x, offset 0x%016"PRIx64", " "expire @ 0x%016"PRIx64".", - APIC_BUS_CYCLE_NS, now, vlapic->timer_initial_count, + APIC_BUS_CYCLE_NS, now, + vlapic_get_reg(vlapic, APIC_TMICT), offset, now + offset); } break; @@ -788,6 +733,8 @@ static void vlapic_write(struct vcpu *v, unsigned long address, tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7); + vlapic_set_reg(vlapic, APIC_TDCR, val); + HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x", vlapic->timer_divide_count); } @@ -827,21 +774,20 @@ void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) value &= ~MSR_IA32_APICBASE_BSP; vlapic->apic_base_msr = value; - vlapic->base_address = vlapic_get_base_address(vlapic); + vlapic->base_address = vlapic->apic_base_msr & + MSR_IA32_APICBASE_BASE; - if ( !(value & 0x800) ) + /* with FSB delivery interrupt, we can restart APIC functionality */ + if ( !(value & MSR_IA32_APICBASE_ENABLE) ) set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status ); + else + clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status); HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.", vlapic->apic_base_msr, vlapic->base_address); } -static inline int vlapic_get_init_id(struct vcpu *v) -{ - return v->vcpu_id; -} - void vlapic_timer_fn(void *data) { struct vlapic *vlapic = data; @@ -850,31 +796,32 @@ void vlapic_timer_fn(void *data) s_time_t now; if ( unlikely(!vlapic_enabled(vlapic) || - !vlapic_lvt_timer_enabled(vlapic)) ) + !vlapic_lvt_enabled(vlapic, APIC_LVTT)) ) return; v = vlapic->vcpu; - timer_vector = vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER); + timer_vector = vlapic_lvt_vector(vlapic, APIC_LVTT); now = NOW(); - vlapic->timer_current_update = now; + vlapic->timer_last_update = now; - if ( test_and_set_bit(timer_vector, &vlapic->irr[0]) ) + if ( test_and_set_bit(timer_vector, vlapic->regs + APIC_IRR )) vlapic->intr_pending_count[timer_vector]++; - if ( vlapic_lvt_timer_period(vlapic) ) + if ( vlapic_lvtt_period(vlapic) ) { s_time_t offset; + uint32_t tmict = vlapic_get_reg(vlapic, APIC_TMICT); - vlapic->timer_current_count = vlapic->timer_initial_count; + vlapic_set_reg(vlapic, APIC_TMCCT, tmict); offset = APIC_BUS_CYCLE_NS * - vlapic->timer_divide_count * - vlapic->timer_initial_count; + vlapic->timer_divide_count * tmict; + set_timer(&vlapic->vlapic_timer, now + offset); } else - vlapic->timer_current_count = 0; + vlapic_set_reg(vlapic, APIC_TMCCT, 0); #if 0 if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) @@ -887,8 +834,8 @@ void vlapic_timer_fn(void *data) "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", " "timer initial count 0x%x, timer current count 0x%x.", now, vlapic->vlapic_timer.expires, - vlapic->timer_initial_count, - vlapic->timer_current_count); + vlapic_get_reg(vlapic, APIC_TMICT), + vlapic_get_reg(vlapic, APIC_TMCCT)); } #if 0 @@ -923,23 +870,23 @@ int cpu_get_apic_interrupt(struct vcpu *v, int *mode) int highest_irr = vlapic_find_highest_irr(vlapic); if ( highest_irr != -1 && - ( (highest_irr & 0xF0) > vlapic->processor_priority ) ) + ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) ) { if ( highest_irr < 0x10 ) { uint32_t err_vector; vlapic->err_status |= 0x20; - err_vector = vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR); + err_vector = vlapic_lvt_vector(vlapic, APIC_LVTERR); HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "Sending an illegal vector 0x%x.", highest_irr); - set_bit(err_vector, &vlapic->irr[0]); + set_bit(err_vector, vlapic->regs + APIC_IRR); highest_irr = err_vector; } - *mode = VLAPIC_DELIV_MODE_FIXED; + *mode = APIC_DM_FIXED; return highest_irr; } } @@ -954,7 +901,7 @@ int cpu_has_apic_interrupt(struct vcpu* v) int highest_irr = vlapic_find_highest_irr(vlapic); if ( highest_irr != -1 && - ( (highest_irr & 0xF0) > vlapic->processor_priority ) ) { + ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) ) { return 1; } } @@ -969,30 +916,30 @@ void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) return; switch ( deliver_mode ) { - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: - set_bit(vector, &vlapic->isr[0]); - clear_bit(vector, &vlapic->irr[0]); + case APIC_DM_FIXED: + case APIC_DM_LOWEST: + set_bit(vector, vlapic->regs + APIC_ISR); + clear_bit(vector, vlapic->regs + APIC_IRR); vlapic_update_ppr(vlapic); - if ( vector == vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER) ) + if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) ) { vlapic->intr_pending_count[vector]--; if ( vlapic->intr_pending_count[vector] > 0 ) - test_and_set_bit(vector, &vlapic->irr[0]); + test_and_set_bit(vector, vlapic->regs + APIC_IRR); } break; /*XXX deal with these later */ - case VLAPIC_DELIV_MODE_RESERVED: + case APIC_DM_REMRD: printk("Ignore deliver mode 3 in vlapic_post_injection\n"); break; - case VLAPIC_DELIV_MODE_SMI: - case VLAPIC_DELIV_MODE_NMI: - case VLAPIC_DELIV_MODE_INIT: - case VLAPIC_DELIV_MODE_STARTUP: - vlapic->direct_intr.deliver_mode &= ~(1 << deliver_mode); + case APIC_DM_SMI: + case APIC_DM_NMI: + case APIC_DM_INIT: + case APIC_DM_STARTUP: + vlapic->direct_intr.deliver_mode &= deliver_mode; break; default: @@ -1004,7 +951,7 @@ void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) static int vlapic_reset(struct vlapic *vlapic) { struct vcpu *v; - int apic_id, i; + int i; ASSERT( vlapic != NULL ); @@ -1012,29 +959,28 @@ static int vlapic_reset(struct vlapic *vlapic) ASSERT( v != NULL ); - apic_id = v->vcpu_id; - vlapic->domain = v->domain; - vlapic->id = apic_id; - vlapic->vcpu_id = v->vcpu_id; - vlapic->version = VLAPIC_VERSION; + vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24); - vlapic->apic_base_msr = VLAPIC_BASE_MSR_INIT_VALUE; - - if ( apic_id == 0 ) - vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP; - - vlapic->base_address = vlapic_get_base_address(vlapic); + vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION); for ( i = 0; i < VLAPIC_LVT_NUM; i++ ) - vlapic->lvt[i] = VLAPIC_LVT_BIT_MASK; + vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); - vlapic->dest_format = 0xffffffffU; + vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU); - vlapic->spurious_vec = 0xff; + vlapic_set_reg(vlapic, APIC_SPIV, 0xff); + + vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; + + if ( v->vcpu_id == 0 ) + vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP; + + vlapic->base_address = vlapic->apic_base_msr & + MSR_IA32_APICBASE_BASE; hvm_vioapic_add_lapic(vlapic, v); @@ -1048,8 +994,8 @@ static int vlapic_reset(struct vlapic *vlapic) */ if ( !v->vcpu_id ) { - vlapic->lvt[VLAPIC_LVT_LINT0] = 0x700; - vlapic->lvt[VLAPIC_LVT_LINT1] = 0x500; + vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8); + vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8); set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); } #endif @@ -1057,7 +1003,8 @@ static int vlapic_reset(struct vlapic *vlapic) HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", " "base_address=0x%0lx.", - v, vlapic->id, vlapic->apic_base_msr, vlapic->base_address); + v, GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)), + vlapic->apic_base_msr, vlapic->base_address); return 1; } @@ -1079,6 +1026,18 @@ int vlapic_init(struct vcpu *v) memset(vlapic, 0, sizeof(struct vlapic)); + vlapic->regs_page = alloc_domheap_page(NULL); + if ( vlapic->regs_page == NULL ) + { + printk("malloc vlapic regs error for vcpu %x\n", v->vcpu_id); + xfree(vlapic); + return -ENOMEM; + } + + vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page)); + + memset(vlapic->regs, 0, PAGE_SIZE); + VLAPIC(v) = vlapic; vlapic->vcpu = v; diff --git a/xen/arch/x86/hvm/vmx/io.c b/xen/arch/x86/hvm/vmx/io.c index 726782eb45..def255b04e 100644 --- a/xen/arch/x86/hvm/vmx/io.c +++ b/xen/arch/x86/hvm/vmx/io.c @@ -81,7 +81,7 @@ interrupt_post_injection(struct vcpu * v, int vector, int type) switch(type) { - case VLAPIC_DELIV_MODE_EXT: + case APIC_DM_EXTINT: break; default: @@ -198,16 +198,17 @@ asmlinkage void vmx_intr_assist(void) highest_vector = cpu_get_interrupt(v, &intr_type); switch (intr_type) { - case VLAPIC_DELIV_MODE_EXT: - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: + case APIC_DM_EXTINT: + case APIC_DM_FIXED: + case APIC_DM_LOWEST: vmx_inject_extint(v, highest_vector, VMX_DELIVER_NO_ERROR_CODE); TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0); break; - case VLAPIC_DELIV_MODE_SMI: - case VLAPIC_DELIV_MODE_NMI: - case VLAPIC_DELIV_MODE_INIT: - case VLAPIC_DELIV_MODE_STARTUP: + + case APIC_DM_SMI: + case APIC_DM_NMI: + case APIC_DM_INIT: + case APIC_DM_STARTUP: default: printk("Unsupported interrupt type\n"); BUG(); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 6dfea007aa..0eabadb5b7 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -137,6 +137,8 @@ static void vmx_relinquish_guest_resources(struct domain *d) if ( hvm_apic_support(v->domain) && (VLAPIC(v) != NULL) ) { kill_timer(&VLAPIC(v)->vlapic_timer); + unmap_domain_page_global(VLAPIC(v)->regs); + free_domheap_page(VLAPIC(v)->regs_page); xfree(VLAPIC(v)); } } diff --git a/xen/include/asm-ia64/vmx_platform.h b/xen/include/asm-ia64/vmx_platform.h index d6f1f3b9bb..e5888e5e22 100644 --- a/xen/include/asm-ia64/vmx_platform.h +++ b/xen/include/asm-ia64/vmx_platform.h @@ -59,6 +59,17 @@ static inline int vlapic_set_irq(struct vlapic *t, uint8_t vec, uint8_t trig) return vmx_vcpu_pend_interrupt(t->vcpu, vec); } +enum ioapic_irq_destination_types { + dest_Fixed = 0, + dest_LowestPrio = 1, + dest_SMI = 2, + dest__reserved_1 = 3, + dest_NMI = 4, + dest_INIT = 5, + dest__reserved_2 = 6, + dest_ExtINT = 7 +}; + /* As long as we register vlsapic to ioapic controller, it's said enabled */ #define vlapic_enabled(l) 1 #define hvm_apic_support(d) 1 diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h index 4534e66680..9092254727 100644 --- a/xen/include/asm-x86/hvm/support.h +++ b/xen/include/asm-x86/hvm/support.h @@ -29,7 +29,7 @@ #ifndef NDEBUG #define HVM_DEBUG 1 #else -#define HVM_DEBUG 0 +#define HVM_DEBUG 1 #endif #define hvm_guest(v) ((v)->arch.guest_context.flags & VGCF_HVM_GUEST) diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index d2b11f3d8e..7550bf3b05 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -33,58 +33,31 @@ static __inline__ int find_highest_bit(unsigned long *data, int nr_bits) #define VLAPIC(v) (v->arch.hvm_vcpu.vlapic) -#define VAPIC_ID_MASK 0xff -#define VAPIC_LDR_MASK (VAPIC_ID_MASK << 24) #define VLAPIC_VERSION 0x00050014 -#define VLAPIC_BASE_MSR_MASK 0x00000000fffff900ULL -#define VLAPIC_BASE_MSR_INIT_BASE_ADDR 0xfee00000U -#define VLAPIC_BASE_MSR_BASE_ADDR_MASK 0xfffff000U -#define VLAPIC_BASE_MSR_INIT_VALUE (VLAPIC_BASE_MSR_INIT_BASE_ADDR | \ - MSR_IA32_APICBASE_ENABLE) #define VLOCAL_APIC_MEM_LENGTH (1 << 12) -#define VLAPIC_LVT_TIMER 0 -#define VLAPIC_LVT_THERMAL 1 -#define VLAPIC_LVT_PERFORM 2 -#define VLAPIC_LVT_LINT0 3 -#define VLAPIC_LVT_LINT1 4 -#define VLAPIC_LVT_ERROR 5 #define VLAPIC_LVT_NUM 6 -#define VLAPIC_LVT_BIT_MASK (1 << 16) -#define VLAPIC_LVT_BIT_VECTOR 0xff -#define VLAPIC_LVT_BIT_DELIMOD (0x7 << 8) -#define VLAPIC_LVT_BIT_DELISTATUS (1 << 12) -#define VLAPIC_LVT_BIT_POLARITY (1 << 13) -#define VLAPIC_LVT_BIT_IRR (1 << 14) -#define VLAPIC_LVT_BIT_TRIG (1 << 15) -#define VLAPIC_LVT_TIMERMODE (1 << 17) +#define VLAPIC_ID(vlapic) \ + (GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID))) -#define VLAPIC_DELIV_MODE_FIXED 0x0 -#define VLAPIC_DELIV_MODE_LPRI 0x1 -#define VLAPIC_DELIV_MODE_SMI 0x2 -#define VLAPIC_DELIV_MODE_RESERVED 0x3 -#define VLAPIC_DELIV_MODE_NMI 0x4 -#define VLAPIC_DELIV_MODE_INIT 0x5 -#define VLAPIC_DELIV_MODE_STARTUP 0x6 -#define VLAPIC_DELIV_MODE_EXT 0x7 +/* followed define is not in apicdef.h */ +#define APIC_SHORT_MASK 0xc0000 +#define APIC_DEST_NOSHORT 0x0 +#define APIC_DEST_MASK 0x800 +#define vlapic_lvt_enabled(vlapic, lvt_type) \ + (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED)) -#define VLAPIC_NO_SHORTHAND 0x0 -#define VLAPIC_SHORTHAND_SELF 0x1 -#define VLAPIC_SHORTHAND_INCLUDE_SELF 0x2 -#define VLAPIC_SHORTHAND_EXCLUDE_SELF 0x3 +#define vlapic_lvt_vector(vlapic, lvt_type) \ + (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK) -#define vlapic_lvt_timer_enabled(vlapic) \ - (!((vlapic)->lvt[VLAPIC_LVT_TIMER] & VLAPIC_LVT_BIT_MASK)) +#define vlapic_lvt_dm(vlapic, lvt_type) \ + (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK) -#define vlapic_lvt_vector(vlapic, type) \ - ((vlapic)->lvt[(type)] & VLAPIC_LVT_BIT_VECTOR) - -#define vlapic_lvt_dm(value) (((value) >> 8) && 7) -#define vlapic_lvt_timer_period(vlapic) \ - ((vlapic)->lvt[VLAPIC_LVT_TIMER] & VLAPIC_LVT_TIMERMODE) +#define vlapic_lvtt_period(vlapic) \ + (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC) #define _VLAPIC_GLOB_DISABLE 0x0 #define VLAPIC_GLOB_DISABLE_MASK 0x1 @@ -98,8 +71,12 @@ static __inline__ int find_highest_bit(unsigned long *data, int nr_bits) #define vlapic_global_enabled(vlapic) \ (!(test_bit(_VLAPIC_GLOB_DISABLE, &(vlapic)->status))) -#define VLAPIC_IRR(t) ((t)->irr[0]) -#define VLAPIC_ID(t) ((t)->id) +#define LVT_MASK \ + APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK + +#define LINT_MASK \ + LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\ + APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER typedef struct direct_intr_info { int deliver_mode; @@ -109,73 +86,53 @@ typedef struct direct_intr_info { #define MAX_VECTOR 256 struct vlapic { - uint32_t version; uint32_t status; - uint32_t id; uint32_t vcpu_id; + uint64_t apic_base_msr; unsigned long base_address; - unsigned long isr[BITS_TO_LONGS(MAX_VECTOR)]; - unsigned long irr[BITS_TO_LONGS(MAX_VECTOR)]; - unsigned long tmr[BITS_TO_LONGS(MAX_VECTOR)]; - uint32_t task_priority; - uint32_t processor_priority; - uint32_t logical_dest; - uint32_t dest_format; - uint32_t spurious_vec; - uint32_t lvt[6]; - uint32_t timer_initial_count; - uint32_t timer_current_count; - uint32_t timer_divconf; uint32_t timer_divide_count; struct timer vlapic_timer; int intr_pending_count[MAX_VECTOR]; - s_time_t timer_current_update; - uint32_t icr_high; - uint32_t icr_low; + s_time_t timer_last_update; direct_intr_info_t direct_intr; uint32_t err_status; - unsigned long init_ticks; uint32_t err_write_count; - uint64_t apic_base_msr; struct vcpu *vcpu; struct domain *domain; + struct page_info *regs_page; + void *regs; }; -static inline int vlapic_set_irq(struct vlapic *t, uint8_t vec, uint8_t trig) +static inline int vlapic_set_irq(struct vlapic *vlapic, + uint8_t vec, uint8_t trig) { int ret; - ret = test_and_set_bit(vec, &t->irr[0]); + ret = test_and_set_bit(vec, vlapic->regs + APIC_IRR); if ( trig ) - set_bit(vec, &t->tmr[0]); + set_bit(vec, vlapic->regs + APIC_TMR); /* We may need to wake up target vcpu, besides set pending bit here */ return ret; } -static inline int vlapic_timer_active(struct vlapic *vlapic) +static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg) { - return active_timer(&vlapic->vlapic_timer); + return *( (uint32_t *)(vlapic->regs + reg)); } -int vlapic_find_highest_irr(struct vlapic *vlapic); - -int vlapic_find_highest_isr(struct vlapic *vlapic); - -static uint32_t inline vlapic_get_base_address(struct vlapic *vlapic) +static inline void vlapic_set_reg(struct vlapic *vlapic, + uint32_t reg, uint32_t val) { - return (vlapic->apic_base_msr & VLAPIC_BASE_MSR_BASE_ADDR_MASK); + *((uint32_t *)(vlapic->regs + reg)) = val; } + void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode); int cpu_has_apic_interrupt(struct vcpu* v); int cpu_get_apic_interrupt(struct vcpu* v, int *mode); -extern uint32_t vlapic_update_ppr(struct vlapic *vlapic); - -int vlapic_update(struct vcpu *v); - extern int vlapic_init(struct vcpu *vc); extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index f8fe619ede..a59473e514 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -153,7 +153,7 @@ extern unsigned int cpu_rev; /* * Exit Qualifications for MOV for Control Register Access */ -#define CONTROL_REG_ACCESS_NUM 0x7 /* 2:0, number of control register */ +#define CONTROL_REG_ACCESS_NUM 0xf /* 3:0, number of control register */ #define CONTROL_REG_ACCESS_TYPE 0x30 /* 5:4, access type */ #define CONTROL_REG_ACCESS_REG 0xf00 /* 10:8, general purpose register */ #define LMSW_SOURCE_DATA (0xFFFF << 16) /* 16:31 lmsw source */ From bb41ceb3e914a9beaa980dc8aacf4e1479ce5ffd Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 10:08:33 +0100 Subject: [PATCH 051/111] [IA64] Updates the ia64 buildconfigs. Enables pcifront for all kernels and pciback for -xen and -xen0. Signed-off-by: Alex Williamson --- buildconfigs/linux-defconfig_xen0_ia64 | 16 +++++++++++----- buildconfigs/linux-defconfig_xenU_ia64 | 16 ++++++++++++++-- buildconfigs/linux-defconfig_xen_ia64 | 16 +++++++++++----- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/buildconfigs/linux-defconfig_xen0_ia64 b/buildconfigs/linux-defconfig_xen0_ia64 index 08a32721aa..cd2008f9da 100644 --- a/buildconfigs/linux-defconfig_xen0_ia64 +++ b/buildconfigs/linux-defconfig_xen0_ia64 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.16.13-xen0 -# Fri Jun 30 12:59:19 2006 +# Fri Jul 28 16:33:47 2006 # # @@ -92,6 +92,7 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_XEN=y CONFIG_XEN_IA64_DOM0_VP=y +CONFIG_XEN_IA64_VDSO_PARAVIRT=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_IS_DMA32=y # CONFIG_IA64_GENERIC is not set @@ -180,6 +181,8 @@ CONFIG_ACPI_CONTAINER=y # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_XEN_PCIDEV_FRONTEND=y +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set CONFIG_PCI_LEGACY_PROC=y # CONFIG_PCI_DEBUG is not set @@ -1513,7 +1516,7 @@ CONFIG_XEN_SKBUFF=y CONFIG_XEN_NETDEV_BACKEND=y CONFIG_XEN_NETDEV_FRONTEND=y # CONFIG_XEN_DEVMEM is not set -# CONFIG_XEN_REBOOT is not set +CONFIG_XEN_REBOOT=y # CONFIG_XEN_SMPBOOT is not set CONFIG_XEN_INTERFACE_VERSION=0x00030202 @@ -1523,13 +1526,16 @@ CONFIG_XEN_INTERFACE_VERSION=0x00030202 CONFIG_XEN_PRIVILEGED_GUEST=y # CONFIG_XEN_UNPRIVILEGED_GUEST is not set CONFIG_XEN_PRIVCMD=y -CONFIG_XEN_BACKEND=y -# CONFIG_XEN_PCIDEV_BACKEND is not set -CONFIG_XEN_BLKDEV_BACKEND=y CONFIG_XEN_XENBUS_DEV=y +CONFIG_XEN_BACKEND=y +CONFIG_XEN_BLKDEV_BACKEND=y # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set CONFIG_XEN_NETDEV_LOOPBACK=y +CONFIG_XEN_PCIDEV_BACKEND=y +CONFIG_XEN_PCIDEV_BACKEND_VPCI=y +# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set +# CONFIG_XEN_PCIDEV_BE_DEBUG is not set # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y # CONFIG_XEN_SCRUB_PAGES is not set diff --git a/buildconfigs/linux-defconfig_xenU_ia64 b/buildconfigs/linux-defconfig_xenU_ia64 index ed35b560c8..650a026632 100644 --- a/buildconfigs/linux-defconfig_xenU_ia64 +++ b/buildconfigs/linux-defconfig_xenU_ia64 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.16.13-xenU -# Mon May 22 15:05:32 2006 +# Fri Jul 28 16:32:18 2006 # # @@ -89,6 +89,7 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_XEN=y CONFIG_XEN_IA64_DOM0_VP=y +CONFIG_XEN_IA64_VDSO_PARAVIRT=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_IS_DMA32=y # CONFIG_IA64_GENERIC is not set @@ -177,6 +178,8 @@ CONFIG_ACPI_SYSTEM=y # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_XEN_PCIDEV_FRONTEND=y +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set CONFIG_PCI_LEGACY_PROC=y # CONFIG_PCI_DEBUG is not set @@ -1380,8 +1383,15 @@ CONFIG_CRYPTO_DES=y # # Hardware crypto devices # +# CONFIG_XEN_UTIL is not set CONFIG_HAVE_ARCH_ALLOC_SKB=y CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y +CONFIG_XEN_BALLOON=y +CONFIG_XEN_SKBUFF=y +CONFIG_XEN_NETDEV_FRONTEND=y +# CONFIG_XEN_DEVMEM is not set +CONFIG_XEN_REBOOT=y +# CONFIG_XEN_SMPBOOT is not set CONFIG_XEN_INTERFACE_VERSION=0x00030202 # @@ -1389,13 +1399,15 @@ CONFIG_XEN_INTERFACE_VERSION=0x00030202 # # CONFIG_XEN_PRIVILEGED_GUEST is not set CONFIG_XEN_UNPRIVILEGED_GUEST=y +CONFIG_XEN_PRIVCMD=y +CONFIG_XEN_XENBUS_DEV=y # CONFIG_XEN_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y -CONFIG_XEN_NETDEV_FRONTEND=y # CONFIG_XEN_SCRUB_PAGES is not set # CONFIG_XEN_DISABLE_SERIAL is not set CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y diff --git a/buildconfigs/linux-defconfig_xen_ia64 b/buildconfigs/linux-defconfig_xen_ia64 index 566a70522e..8ce5402772 100644 --- a/buildconfigs/linux-defconfig_xen_ia64 +++ b/buildconfigs/linux-defconfig_xen_ia64 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.16.13-xen -# Thu Jun 29 16:23:48 2006 +# Fri Jul 28 16:33:08 2006 # # @@ -92,6 +92,7 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_XEN=y CONFIG_XEN_IA64_DOM0_VP=y +CONFIG_XEN_IA64_VDSO_PARAVIRT=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_IS_DMA32=y # CONFIG_IA64_GENERIC is not set @@ -180,6 +181,8 @@ CONFIG_ACPI_CONTAINER=y # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_XEN_PCIDEV_FRONTEND=y +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set CONFIG_PCI_LEGACY_PROC=y # CONFIG_PCI_DEBUG is not set @@ -1519,7 +1522,7 @@ CONFIG_XEN_SKBUFF=y CONFIG_XEN_NETDEV_BACKEND=y CONFIG_XEN_NETDEV_FRONTEND=y # CONFIG_XEN_DEVMEM is not set -# CONFIG_XEN_REBOOT is not set +CONFIG_XEN_REBOOT=y # CONFIG_XEN_SMPBOOT is not set CONFIG_XEN_INTERFACE_VERSION=0x00030202 @@ -1529,13 +1532,16 @@ CONFIG_XEN_INTERFACE_VERSION=0x00030202 CONFIG_XEN_PRIVILEGED_GUEST=y # CONFIG_XEN_UNPRIVILEGED_GUEST is not set CONFIG_XEN_PRIVCMD=y -CONFIG_XEN_BACKEND=y -# CONFIG_XEN_PCIDEV_BACKEND is not set -CONFIG_XEN_BLKDEV_BACKEND=y CONFIG_XEN_XENBUS_DEV=y +CONFIG_XEN_BACKEND=y +CONFIG_XEN_BLKDEV_BACKEND=y # CONFIG_XEN_BLKDEV_TAP is not set # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set CONFIG_XEN_NETDEV_LOOPBACK=y +CONFIG_XEN_PCIDEV_BACKEND=y +CONFIG_XEN_PCIDEV_BACKEND_VPCI=y +# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set +# CONFIG_XEN_PCIDEV_BE_DEBUG is not set # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y # CONFIG_XEN_SCRUB_PAGES is not set From c407ff43f456fa6f158dd1628396451f2c1bcf39 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 10:13:30 +0100 Subject: [PATCH 052/111] [TOOLS] lomount: Fix printf formats inside #ifdef DEBUG. Signed-off-by: Tristan Gingold --- tools/misc/lomount/lomount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/misc/lomount/lomount.c b/tools/misc/lomount/lomount.c index d04a95bfc4..7b86683bef 100644 --- a/tools/misc/lomount/lomount.c +++ b/tools/misc/lomount/lomount.c @@ -158,7 +158,7 @@ load_gpt (const char *diskimage, struct pentry *parttbl[]) entry_size = read_le4 (&data[84]); #ifdef DEBUG - fprintf(stderr, "lba entries: %lu, nbr_part: %u, entry_size: %lu\n", + fprintf(stderr, "lba entries: %llu, nbr_part: %u, entry_size: %lu\n", entries_lba, nbr_part, entry_size); #endif part = malloc (nbr_part * sizeof (struct pentry)); @@ -404,7 +404,7 @@ int main(int argc, char ** argv) value is off by (larger than) a value less than one. */ sec = 512; /* TODO: calculate real sector size */ #ifdef DEBUG - printf("sec: %d\n", sec); + printf("sec: %llu\n", sec); #endif if (partition > nbr_part) { @@ -421,7 +421,7 @@ int main(int argc, char ** argv) pnum = sec * num; #ifdef DEBUG - printf("offset = %d\n", pnum); + printf("offset = %llu\n", pnum); #endif snprintf(buf, sizeof(buf), "mount -oloop,offset=%lld %s %s", pnum, diskimage, argv2); From 219c85a53b1c4722bad271aa8ac03af19b53e953 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 14:58:37 +0100 Subject: [PATCH 053/111] [TOOLS] Modify xenstore_client.c to include a new utility, xenstore-chmod. This utility permits developers and administrators to manually change the permissions on arbitrary locations in XenStore from the command line. This is often helpful if you're trying to debug an application that relies on XenStore and is encountering difficulties with permissions. Signed-off-by: Michael LeMay --- .hgignore | 1 + tools/xenstore/Makefile | 2 +- tools/xenstore/xenstore_client.c | 106 ++++++++++++++++++++++++++++++- 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/.hgignore b/.hgignore index 1bb0f83e6d..6c36a72ac7 100644 --- a/.hgignore +++ b/.hgignore @@ -156,6 +156,7 @@ ^tools/xenstat/xentop/xentop$ ^tools/xenstore/testsuite/tmp/.*$ ^tools/xenstore/xen$ +^tools/xenstore/xenstore-chmod$ ^tools/xenstore/xenstore-exists$ ^tools/xenstore/xenstore-list$ ^tools/xenstore/xenstore-read$ diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 53f3467465..b568a24c5a 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -26,7 +26,7 @@ TESTDIR = testsuite/tmp TESTFLAGS= -DTESTING TESTENV = XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) -CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm +CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm xenstore-chmod CLIENTS += xenstore-write CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS)) diff --git a/tools/xenstore/xenstore_client.c b/tools/xenstore/xenstore_client.c index 07809e6c83..811c6acb6a 100644 --- a/tools/xenstore/xenstore_client.c +++ b/tools/xenstore/xenstore_client.c @@ -60,6 +60,8 @@ usage(const char *progname) errx(1, "Usage: %s [-h] [-s] [-t] key [...]", progname); #elif defined(CLIENT_exists) || defined(CLIENT_list) errx(1, "Usage: %s [-h] [-s] key [...]", progname); +#elif defined(CLIENT_chmod) + errx(1, "Usage: %s [-h] [-s] key ", progname); #endif } @@ -78,10 +80,61 @@ do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth) } #endif +#if defined(CLIENT_chmod) +#define PATH_SEP '/' +#define MAX_PATH_LEN 256 + +static void +do_chmod(char *path, struct xs_permissions *perms, int nperms, int upto, + int recurse, struct xs_handle *xsh, xs_transaction_t xth) +{ + int ret; + + if (!path[0]) + return; + + ret = xs_set_permissions(xsh, xth, path, perms, nperms); + if (!ret) + err(1, "Error occurred setting permissions on '%s'", path); + + if (upto) { + /* apply same permissions to all parent entries: */ + char *path_sep_ptr = strrchr(path, PATH_SEP); + if (!path_sep_ptr) + errx(1, "Unable to locate path separator '%c' in '%s'", + PATH_SEP, path); + + *path_sep_ptr = '\0'; /* truncate path */ + + do_chmod(path, perms, nperms, 1, 0, xsh, xth); + + *path_sep_ptr = PATH_SEP; + } + + if (recurse) { + char buf[MAX_PATH_LEN]; + + /* apply same permissions to all child entries: */ + unsigned int xsval_n; + char **xsval = xs_directory(xsh, xth, path, &xsval_n); + + if (xsval) { + int i; + for (i = 0; i < xsval_n; i++) { + snprintf(buf, MAX_PATH_LEN, "%s/%s", path, xsval[i]); + + do_chmod(buf, perms, nperms, 0, 1, xsh, xth); + } + + free(xsval); + } + } +} +#endif static int perform(int optind, int argc, char **argv, struct xs_handle *xsh, - xs_transaction_t xth, int prefix, int tidy) + xs_transaction_t xth, int prefix, int tidy, int upto, int recurse) { while (optind < argc) { #if defined(CLIENT_read) @@ -168,6 +221,41 @@ perform(int optind, int argc, char **argv, struct xs_handle *xsh, } free(list); optind++; +#elif defined(CLIENT_chmod) +#define MAX_PERMS 16 + struct xs_permissions perms[MAX_PERMS]; + int nperms = 0; + /* save path pointer: */ + char *path = argv[optind++]; + for (; argv[optind]; optind++, nperms++) + { + if (MAX_PERMS <= nperms) + errx(1, "Too many permissions specified. " + "Maximum per invocation is %d.", MAX_PERMS); + + perms[nperms].id = atoi(argv[optind]+1); + + switch (argv[optind][0]) + { + case 'n': + perms[nperms].perms = XS_PERM_NONE; + break; + case 'r': + perms[nperms].perms = XS_PERM_READ; + break; + case 'w': + perms[nperms].perms = XS_PERM_WRITE; + break; + case 'b': + perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE; + break; + default: + errx(1, "Invalid permission specification: '%c'", + argv[optind][0]); + } + } + + do_chmod(path, perms, nperms, upto, recurse, xsh, xth); #endif } @@ -183,6 +271,8 @@ main(int argc, char **argv) int ret = 0, socket = 0; int prefix = 0; int tidy = 0; + int upto = 0; + int recurse = 0; while (1) { int c, index = 0; @@ -193,6 +283,9 @@ main(int argc, char **argv) {"prefix", 0, 0, 'p'}, #elif defined(CLIENT_rm) {"tidy", 0, 0, 't'}, +#elif defined(CLIENT_chmod) + {"upto", 0, 0, 'u'}, + {"recurse", 0, 0, 'r'}, #endif {0, 0, 0, 0} }; @@ -202,6 +295,8 @@ main(int argc, char **argv) "p" #elif defined(CLIENT_rm) "t" +#elif defined(CLIENT_chmod) + "ur" #endif , long_options, &index); if (c == -1) @@ -222,6 +317,13 @@ main(int argc, char **argv) case 't': tidy = 1; break; +#elif defined(CLIENT_chmod) + case 'u': + upto = 1; + break; + case 'r': + recurse = 1; + break; #endif } } @@ -246,7 +348,7 @@ main(int argc, char **argv) if (xth == XBT_NULL) errx(1, "couldn't start transaction"); - ret = perform(optind, argc, argv, xsh, xth, prefix, tidy); + ret = perform(optind, argc, argv, xsh, xth, prefix, tidy, upto, recurse); if (!xs_transaction_end(xsh, xth, ret)) { if (ret == 0 && errno == EAGAIN) { From 17d151cf1e09384e5d797d19cd7929636a73c801 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 14:59:22 +0100 Subject: [PATCH 054/111] [LINUX] Clarify a confusing error message in xenbus_probe.c. Signed-off-by: Michael LeMay --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index a4ee6e8a54..ea093bb191 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -141,7 +141,9 @@ static int read_otherend_details(struct xenbus_device *xendev, } if (strlen(xendev->otherend) == 0 || !xenbus_exists(XBT_NIL, xendev->otherend, "")) { - xenbus_dev_fatal(xendev, -ENOENT, "missing other end from %s", + xenbus_dev_fatal(xendev, -ENOENT, + "unable to read other end from %s. " + "missing or inaccessible.", xendev->nodename); free_otherend_details(xendev); return -ENOENT; From ae9516f06f34e61ce00e0fac5d5fc101ef6c1a57 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 15:00:39 +0100 Subject: [PATCH 055/111] [TOOLS] Enhance xenstore-ls to optionally display permissions. Also perform an ioctl to determine the current width of the terminal. Signed-off-by: Michael LeMay --- tools/xenstore/xsls.c | 103 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 11 deletions(-) diff --git a/tools/xenstore/xsls.c b/tools/xenstore/xsls.c index 7f3fa4f7f1..4d3b1aa1af 100644 --- a/tools/xenstore/xsls.c +++ b/tools/xenstore/xsls.c @@ -3,8 +3,19 @@ #include #include #include +#include +#include +#include -void print_dir(struct xs_handle *h, char *path, int cur_depth) +static int max_width = 80; +static int desired_width = 60; + +#define TAG " = \"...\"" +#define TAG_LEN strlen(TAG) + +#define MIN(a, b) (((a) < (b))? (a) : (b)) + +void print_dir(struct xs_handle *h, char *path, int cur_depth, int show_perms) { char **e; char newpath[512], *val; @@ -16,33 +27,103 @@ void print_dir(struct xs_handle *h, char *path, int cur_depth) err(1, "xs_directory (%s)", path); for (i = 0; i (151 - strlen(e[i]))) - printf(" = \"%.*s...\"\n", (int)(148 - strlen(e[i])), val); - else - printf(" = \"%s\"\n", val); + } + else { + if (max_width < (linewid + len + TAG_LEN)) { + printf(" = \"%.*s...\"", + (int)(max_width - TAG_LEN - linewid), val); + } + else { + linewid += printf(" = \"%s\"", val); + if (show_perms) { + putchar(' '); + for (linewid++; + linewid < MIN(desired_width, max_width); + linewid++) + putchar((linewid & 1)? '.' : ' '); + } + } + } free(val); - print_dir(h, newpath, cur_depth+1); + + if (show_perms) { + perms = xs_get_permissions(h, XBT_NULL, newpath, &nperms); + if (perms == NULL) { + warn("\ncould not access permissions for %s", e[i]); + } + else { + int i; + fputs(" (", stdout); + for (i = 0; i < nperms; i++) { + if (i) + putchar(','); + xs_perm_to_string(perms+i, buf); + fputs(buf, stdout); + } + putchar(')'); + } + } + + putchar('\n'); + + print_dir(h, newpath, cur_depth+1, show_perms); } free(e); } +void usage(int argc, char *argv[]) +{ + fprintf(stderr, "Usage: %s [-p] [path]\n", argv[0]); +} + int main(int argc, char *argv[]) { + struct winsize ws; + int ret; + int c; + int show_perm = 0; + struct xs_handle *xsh = xs_daemon_open(); if (xsh == NULL) err(1, "xs_daemon_open"); - print_dir(xsh, argc == 1 ? "/" : argv[1], 0); +#define PAD 2 + + memset(&ws, 0, sizeof(ws)); + ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); + if (!ret) + max_width = ws.ws_col - PAD; + + while (0 < (c = getopt(argc, argv, "p"))) { + switch (c) { + case 'p': + show_perm = 1; + max_width -= 16; + break; + case ':': + case '?': + default: + usage(argc, argv); + return 0; + } + } + + print_dir(xsh, (argc - optind) == 1 ? argv[optind] : "/", 0, show_perm); return 0; } From 8f84603260b78eec6ab65ae4be493083171bc276 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 15:01:59 +0100 Subject: [PATCH 056/111] [LINUX] Allows userspace tools on a domU to set up a watch on the xenstore. It does this by intercepting XS_WATCH requests written to /proc/xen/xenbus and then re-submitting the request to the in-kernel xenstore interface, in linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c. When a callback occurs, an in-kernel function is invoked, which then reconstructs a response in the format expected by userspace, and sends this response through /proc/xen/xenbus. It was necessary to add some supporting infrastructure to linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c, such as an additional mutex to protect the response queue and a list of active watches associated with each connection. Signed-off-by: Michael LeMay --- .../drivers/xen/xenbus/xenbus_dev.c | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c index 9d25b33d81..02d3b46ee7 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c @@ -58,6 +58,9 @@ struct xenbus_dev_data { /* In-progress transaction. */ struct list_head transactions; + /* Active watches. */ + struct list_head watches; + /* Partial request. */ unsigned int len; union { @@ -70,6 +73,8 @@ struct xenbus_dev_data { char read_buffer[PAGE_SIZE]; unsigned int read_cons, read_prod; wait_queue_head_t read_waitq; + + struct mutex reply_mutex; }; static struct proc_dir_entry *xenbus_dev_intf; @@ -100,14 +105,60 @@ static void queue_reply(struct xenbus_dev_data *u, { int i; + mutex_lock(&u->reply_mutex); + for (i = 0; i < len; i++, u->read_prod++) u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer)); + mutex_unlock(&u->reply_mutex); + wake_up(&u->read_waitq); } +struct watch_adapter +{ + struct list_head list; + struct xenbus_watch watch; + struct xenbus_dev_data *dev_data; + char *token; +}; + +static void free_watch_adapter (struct watch_adapter *watch) +{ + kfree(watch->watch.node); + kfree(watch->token); + kfree(watch); +} + +static void watch_fired(struct xenbus_watch *watch, + const char **vec, + unsigned int len) +{ + struct watch_adapter *adap = + container_of(watch, struct watch_adapter, watch); + struct xsd_sockmsg hdr; + const char *path, *token; + int path_len, tok_len, body_len; + + path = vec[XS_WATCH_PATH]; + token = adap->token; + + path_len = strlen(path) + 1; + tok_len = strlen(token) + 1; + body_len = path_len + tok_len; + + hdr.type = XS_WATCH_EVENT; + hdr.len = body_len; + + queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr)); + queue_reply(adap->dev_data, (char *)path, path_len); + queue_reply(adap->dev_data, (char *)token, tok_len); +} + +static LIST_HEAD(watch_list); + static ssize_t xenbus_dev_write(struct file *filp, const char __user *ubuf, size_t len, loff_t *ppos) @@ -116,6 +167,9 @@ static ssize_t xenbus_dev_write(struct file *filp, struct xenbus_dev_transaction *trans = NULL; uint32_t msg_type; void *reply; + char *path, *token; + struct watch_adapter *watch, *tmp_watch; + int err; if ((len + u->len) > sizeof(u->u.buffer)) return -EINVAL; @@ -169,6 +223,56 @@ static ssize_t xenbus_dev_write(struct file *filp, kfree(reply); break; + case XS_WATCH: + case XS_UNWATCH: + path = u->u.buffer + sizeof(u->u.msg); + token = memchr(path, 0, u->u.msg.len); + if (token == NULL) + return -EILSEQ; + token++; + + if (msg_type == XS_WATCH) { + static const char * XS_WATCH_RESP = "OK"; + struct xsd_sockmsg hdr; + + watch = kmalloc(sizeof(*watch), GFP_KERNEL); + watch->watch.node = kmalloc(strlen(path)+1, + GFP_KERNEL); + strcpy((char *)watch->watch.node, path); + watch->watch.callback = watch_fired; + watch->token = kmalloc(strlen(token)+1, GFP_KERNEL); + strcpy(watch->token, token); + watch->dev_data = u; + + err = register_xenbus_watch(&watch->watch); + if (err) { + free_watch_adapter(watch); + return err; + } + + list_add(&watch->list, &u->watches); + + hdr.type = XS_WATCH; + hdr.len = strlen(XS_WATCH_RESP) + 1; + queue_reply(u, (char *)&hdr, sizeof(hdr)); + queue_reply(u, (char *)XS_WATCH_RESP, hdr.len); + } else { + list_for_each_entry_safe(watch, tmp_watch, + &u->watches, list) { + if (!strcmp(watch->token, token) && + !strcmp(watch->watch.node, path)) + break; + { + unregister_xenbus_watch(&watch->watch); + list_del(&watch->list); + free_watch_adapter(watch); + break; + } + } + } + + break; + default: return -EINVAL; } @@ -191,8 +295,11 @@ static int xenbus_dev_open(struct inode *inode, struct file *filp) return -ENOMEM; INIT_LIST_HEAD(&u->transactions); + INIT_LIST_HEAD(&u->watches); init_waitqueue_head(&u->read_waitq); + mutex_init(&u->reply_mutex); + filp->private_data = u; return 0; @@ -202,6 +309,7 @@ static int xenbus_dev_release(struct inode *inode, struct file *filp) { struct xenbus_dev_data *u = filp->private_data; struct xenbus_dev_transaction *trans, *tmp; + struct watch_adapter *watch, *tmp_watch; list_for_each_entry_safe(trans, tmp, &u->transactions, list) { xenbus_transaction_end(trans->handle, 1); @@ -209,6 +317,12 @@ static int xenbus_dev_release(struct inode *inode, struct file *filp) kfree(trans); } + list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { + unregister_xenbus_watch(&watch->watch); + list_del(&watch->list); + free_watch_adapter(watch); + } + kfree(u); return 0; From 518e1001737d4bdd2abbc1bc00d7120c6f92af57 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 15:06:29 +0100 Subject: [PATCH 057/111] [XEN] Allow quick building of individual files. For the purpose of quick compile testing of (namely smaller) changes, provide a means to build individual pieces underneath the xen dir (could equally be applied to tools, and the top level Makefile could also be made aware of this logic to make things even more consistent). At once, add a way to only pre-process files in case some of the more complicated macros need change and hence inspection of the results. Signed-off-by: Jan Beulich --- xen/Makefile | 12 ++++++++++++ xen/Rules.mk | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/xen/Makefile b/xen/Makefile index d9f5322eb6..cad1dc1407 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -146,3 +146,15 @@ _cscope: .PHONY: MAP MAP: $(NM) $(TARGET) | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + +.PHONY: FORCE +FORCE: + +%.o %.i: %.c FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $(*D) $(@F) + +%.o %.s: %.S FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $(*D) $(@F) + +%/: FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $* built_in.o diff --git a/xen/Rules.mk b/xen/Rules.mk index 17a0eb04aa..15c0af3cc1 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -105,3 +105,9 @@ _clean_%/: FORCE %.o: %.S $(HDRS) Makefile $(CC) $(CFLAGS) $(AFLAGS) -c $< -o $@ + +%.i: %.c $(HDRS) Makefile + $(CPP) $(CFLAGS) $< -o $@ + +%.s: %.S $(HDRS) Makefile + $(CPP) $(CFLAGS) $(AFLAGS) $< -o $@ From 5ac47f7c4f69867024a1799fa09e70c0e7ba3779 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 15:07:21 +0100 Subject: [PATCH 058/111] [PCI] Transparent virtualization for pcifront and pciback. Signed-off-by: Tristan Gingold --- linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c | 3 +++ linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c | 7 +++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c index 6927e038f1..86223a35ec 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c @@ -445,6 +445,9 @@ static struct xenbus_driver xenbus_pciback_driver = { int __init pciback_xenbus_register(void) { + if (!is_running_on_xen()) + return -ENODEV; + return xenbus_register_backend(&xenbus_pciback_driver); } diff --git a/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c index f3a642e5b6..4fd9262f9d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c @@ -284,11 +284,10 @@ static struct xenbus_driver xenbus_pcifront_driver = { static int __init pcifront_init(void) { - int err = 0; + if (!is_running_on_xen()) + return -ENODEV; - err = xenbus_register_frontend(&xenbus_pcifront_driver); - - return err; + return xenbus_register_frontend(&xenbus_pcifront_driver); } /* Initialize after the Xen PCI Frontend Stub is initialized */ From 148381f98e5aba1871cb9187c86c7d5143138c3a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 15:42:44 +0100 Subject: [PATCH 059/111] [HVM][VMX] Fix dead loop in PIO handling, introduced in c/s 10894. RIP update is missed for PIO handling. Signed-off-by: Xin Li --- xen/arch/x86/hvm/vmx/vmx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 0eabadb5b7..292fdab4dd 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1111,9 +1111,10 @@ static void vmx_io_instruction(unsigned long exit_qualification, memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES); hvm_store_cpu_guest_regs(current, regs, NULL); - __vmread(GUEST_RIP, &eip); - __vmread(GUEST_CS_SELECTOR, &cs); - __vmread(GUEST_RFLAGS, &eflags); + eip = regs->eip; + cs = regs->cs; + eflags = regs->eflags; + vm86 = eflags & X86_EFLAGS_VM ? 1 : 0; HVM_DBG_LOG(DBG_LEVEL_IO, @@ -1165,7 +1166,7 @@ static void vmx_io_instruction(unsigned long exit_qualification, else count = (addr & ~PAGE_MASK) / size; } else - __update_guest_eip(inst_len); + regs->eip += inst_len; send_pio_req(regs, port, count, size, addr, dir, 1); } @@ -1173,7 +1174,7 @@ static void vmx_io_instruction(unsigned long exit_qualification, if (port == 0xe9 && dir == IOREQ_WRITE && size == 1) hvm_print_line(current, regs->eax); /* guest debug output */ - __update_guest_eip(inst_len); + regs->eip += inst_len; send_pio_req(regs, port, 1, size, regs->eax, dir, 0); } } From d3beb92d96734715589448332335757eead5cfea Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 2 Aug 2006 15:47:04 +0100 Subject: [PATCH 060/111] [HVM][SVM] Fix PIO breakage (fixed for VMX in previous changeset). Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/svm/svm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 01d48b2524..bb16553f55 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1484,7 +1484,7 @@ static void svm_io_instruction(struct vcpu *v) count = (addr & ~PAGE_MASK) / size; } else - vmcb->rip = vmcb->exitinfo2; + regs->eip = vmcb->exitinfo2; send_pio_req(regs, port, count, size, addr, dir, 1); } @@ -1495,7 +1495,7 @@ static void svm_io_instruction(struct vcpu *v) * On SVM, the RIP of the intruction following the IN/OUT is saved in * ExitInfo2 */ - vmcb->rip = vmcb->exitinfo2; + regs->eip = vmcb->exitinfo2; if (port == 0xe9 && dir == IOREQ_WRITE && size == 1) hvm_print_line(v, regs->eax); /* guest debug output */ From 028e72eee5034628bbc044e74883f1b3785faf97 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Wed, 2 Aug 2006 17:42:38 +0100 Subject: [PATCH 061/111] Clarify the use of vcpu-set. Closes bug #686. Signed-off-by Harry Butterworth --- tools/python/xen/xm/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index b6d1dcb63c..83021a49ad 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -78,7 +78,9 @@ help_spacer = """ sysrq_help = "sysrq Send a sysrq to a domain" domid_help = "domid Converts a domain name to a domain id" domname_help = "domname Convert a domain id to a domain name" -vcpu_set_help = """vcpu-set Set the number of VCPUs for a domain""" +vcpu_set_help = """vcpu-set Set the number of active VCPUs for a domain + within the range allowed by the domain + configuration""" vcpu_list_help = "vcpu-list List the VCPUs for a domain (or all domains)" vcpu_pin_help = "vcpu-pin Set which cpus a VCPU can use" dmesg_help = "dmesg [-c|--clear] Read or clear Xen's message buffer" From c255809877604699415e66d76cbef0846970cefe Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 13:53:33 +0100 Subject: [PATCH 062/111] [HVM] Add a concept of HVM parameters to the hypervisor. Each HVM domain has a space of HVM parameters associated with it, and these can be manipulated via a new hvm_op hypercall. This means that the hypervisor no longer needs to parse the hvm_info table, so remove that code. Signed-off-by: Steven Smith Signed-off-by: Keir Fraser --- .../drivers/xen/privcmd/privcmd.c | 1 + tools/libxc/xc_hvm_build.c | 32 +++++ xen/arch/x86/hvm/hvm.c | 120 +++++++++--------- xen/arch/x86/hvm/svm/svm.c | 4 +- xen/arch/x86/hvm/vlapic.c | 3 +- xen/arch/x86/hvm/vmx/vmx.c | 2 +- xen/arch/x86/x86_32/entry.S | 2 + xen/arch/x86/x86_64/entry.S | 2 + xen/include/asm-x86/hvm/domain.h | 8 +- xen/include/public/xen.h | 1 + xen/include/xen/hypercall.h | 5 + 11 files changed, 114 insertions(+), 66 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index d367c69300..3c9bb9f0d2 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -270,6 +270,7 @@ static int __init privcmd_init(void) set_bit(__HYPERVISOR_sched_op_compat, hypercall_permission_map); set_bit(__HYPERVISOR_event_channel_op_compat, hypercall_permission_map); + set_bit(__HYPERVISOR_hvm_op, hypercall_permission_map); privcmd_intf = create_xen_proc_entry("privcmd", 0400); if (privcmd_intf != NULL) diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c index 724b37c4c4..bdfb1cf976 100644 --- a/tools/libxc/xc_hvm_build.c +++ b/tools/libxc/xc_hvm_build.c @@ -6,12 +6,14 @@ #include #include #include "xg_private.h" +#include "xc_private.h" #include "xc_elf.h" #include #include #include #include #include +#include #define HVM_LOADER_ENTR_ADDR 0x00100000 @@ -43,6 +45,30 @@ loadelfimage( char *elfbase, int xch, uint32_t dom, unsigned long *parray, struct domain_setup_info *dsi); +static void xc_set_hvm_param(int handle, + domid_t dom, int param, unsigned long value) +{ + DECLARE_HYPERCALL; + xen_hvm_param_t arg; + int rc; + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_set_param; + hypercall.arg[1] = (unsigned long)&arg; + arg.domid = dom; + arg.index = param; + arg.value = value; + if ( mlock(&arg, sizeof(arg)) != 0 ) + { + PERROR("Could not lock memory for set parameter"); + return; + } + rc = do_xen_hypercall(handle, &hypercall); + safe_munlock(&arg, sizeof(arg)); + if (rc < 0) + PERROR("set HVM parameter failed (%d)", rc); +} + static void build_e820map(void *e820_page, unsigned long long mem_size) { struct e820entry *e820entry = @@ -154,6 +180,9 @@ static int set_hvm_info(int xc_handle, uint32_t dom, munmap(va_map, PAGE_SIZE); + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_APIC_ENABLED, apic); + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae); + return 0; } @@ -287,6 +316,9 @@ static int setup_guest(int xc_handle, munmap(sp, PAGE_SIZE); + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, (v_end >> PAGE_SHIFT) - 2); + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn); + *store_mfn = page_array[(v_end >> PAGE_SHIFT) - 2]; if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) ) goto error_out; diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 4120505a8b..9fcd17be41 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -46,6 +46,7 @@ #include #include #include +#include int hvm_enabled = 0; @@ -128,61 +129,6 @@ static void hvm_map_io_shared_page(struct domain *d) d->arch.hvm_domain.shared_page_va = (unsigned long)p; } -static int validate_hvm_info(struct hvm_info_table *t) -{ - char signature[] = "HVM INFO"; - uint8_t *ptr = (uint8_t *)t; - uint8_t sum = 0; - int i; - - /* strncmp(t->signature, "HVM INFO", 8) */ - for ( i = 0; i < 8; i++ ) { - if ( signature[i] != t->signature[i] ) { - printk("Bad hvm info signature\n"); - return 0; - } - } - - for ( i = 0; i < t->length; i++ ) - sum += ptr[i]; - - return (sum == 0); -} - -static void hvm_get_info(struct domain *d) -{ - unsigned char *p; - unsigned long mfn; - struct hvm_info_table *t; - - mfn = get_mfn_from_gpfn(HVM_INFO_PFN); - if ( mfn == INVALID_MFN ) { - printk("Can not get info page mfn for HVM domain.\n"); - domain_crash_synchronous(); - } - - p = map_domain_page(mfn); - if ( p == NULL ) { - printk("Can not map info page for HVM domain.\n"); - domain_crash_synchronous(); - } - - t = (struct hvm_info_table *)(p + HVM_INFO_OFFSET); - - if ( validate_hvm_info(t) ) { - d->arch.hvm_domain.nr_vcpus = t->nr_vcpus; - d->arch.hvm_domain.apic_enabled = t->apic_enabled; - d->arch.hvm_domain.pae_enabled = t->pae_enabled; - } else { - printk("Bad hvm info table\n"); - d->arch.hvm_domain.nr_vcpus = 1; - d->arch.hvm_domain.apic_enabled = 0; - d->arch.hvm_domain.pae_enabled = 0; - } - - unmap_domain_page(p); -} - void hvm_setup_platform(struct domain* d) { struct hvm_domain *platform; @@ -198,7 +144,6 @@ void hvm_setup_platform(struct domain* d) } hvm_map_io_shared_page(d); - hvm_get_info(d); platform = &d->arch.hvm_domain; pic_init(&platform->vpic, pic_irq_request, &platform->interrupt_request); @@ -343,8 +288,8 @@ static hvm_hypercall_t *hvm_hypercall_table[] = { HYPERCALL(event_channel_op_compat), HYPERCALL(xen_version), HYPERCALL(grant_table_op), - HYPERCALL(event_channel_op) - /*HYPERCALL(hvm_op)*/ + HYPERCALL(event_channel_op), + HYPERCALL(hvm_op) }; #undef HYPERCALL @@ -435,6 +380,65 @@ int hvm_bringup_ap(int vcpuid, int trampoline_vector) return rc; } +long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) + +{ + long rc = 0; + + switch ( op ) + { + case HVMOP_set_param: + case HVMOP_get_param: + { + struct xen_hvm_param a; + struct domain *d; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + if ( a.index >= HVM_NR_PARAMS ) + return -EINVAL; + + if ( a.domid == DOMID_SELF ) + { + get_knownalive_domain(current->domain); + d = current->domain; + } + else if ( IS_PRIV(current->domain) ) + { + d = find_domain_by_id(a.domid); + if ( !d ) + return -ESRCH; + } + else + { + return -EPERM; + } + + if ( op == HVMOP_set_param ) + { + rc = 0; + d->arch.hvm_domain.params[a.index] = a.value; + } + else + { + rc = d->arch.hvm_domain.params[a.index]; + } + + put_domain(d); + return rc; + } + + default: + { + DPRINTK("Bad HVM op %ld.\n", op); + rc = -ENOSYS; + } + } + + return rc; +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index bb16553f55..56805dda26 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -997,7 +997,7 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input, #else if ( v->domain->arch.ops->guest_paging_levels == PAGING_L2 ) { - if ( !v->domain->arch.hvm_domain.pae_enabled ) + if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] ) clear_bit(X86_FEATURE_PAE, &edx); clear_bit(X86_FEATURE_PSE, &edx); clear_bit(X86_FEATURE_PSE36, &edx); @@ -1060,7 +1060,7 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input, #else if ( v->domain->arch.ops->guest_paging_levels == PAGING_L2 ) { - if ( !v->domain->arch.hvm_domain.pae_enabled ) + if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] ) { clear_bit(X86_FEATURE_NX & 31, &edx); clear_bit(X86_FEATURE_PAE, &edx); diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index d87be427bb..700a516b4d 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -33,6 +33,7 @@ #include #include #include +#include /* XXX remove this definition after GFW enabled */ #define VLAPIC_NO_BIOS @@ -57,7 +58,7 @@ static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] = int hvm_apic_support(struct domain *d) { - return d->arch.hvm_domain.apic_enabled; + return d->arch.hvm_domain.params[HVM_PARAM_APIC_ENABLED]; } int vlapic_find_highest_irr(struct vlapic *vlapic) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 292fdab4dd..b13f067675 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -929,7 +929,7 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs) #else if ( v->domain->arch.ops->guest_paging_levels == PAGING_L2 ) { - if ( v->domain->arch.hvm_domain.pae_enabled ) + if ( v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] ) clear_bit(X86_FEATURE_PSE36, &edx); else { diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 71cbe20f68..6b9980fd7a 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -656,6 +656,7 @@ ENTRY(hypercall_table) .long do_xenoprof_op .long do_event_channel_op .long do_physdev_op + .long do_hvm_op /* 34 */ .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -695,6 +696,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_xenoprof_op */ .byte 2 /* do_event_channel_op */ .byte 2 /* do_physdev_op */ + .byte 2 /* do_hvm_op */ /* 34 */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 2318ec9bbc..9680530f43 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -568,6 +568,7 @@ ENTRY(hypercall_table) .quad do_xenoprof_op .quad do_event_channel_op .quad do_physdev_op + .quad do_hvm_op .rept NR_hypercalls-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -607,6 +608,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_xenoprof_op */ .byte 2 /* do_event_channel_op */ .byte 2 /* do_physdev_op */ + .byte 2 /* do_hvm_op */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index 78829b59ea..2d1d977c41 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -27,17 +27,15 @@ #include #include #include +#include #define HVM_PBUF_SIZE 80 struct hvm_domain { unsigned long shared_page_va; - unsigned int nr_vcpus; - unsigned int apic_enabled; - unsigned int pae_enabled; s64 tsc_frequency; struct pl_time pl_time; - + struct hvm_virpic vpic; struct hvm_vioapic vioapic; struct hvm_io_handler io_handler; @@ -48,6 +46,8 @@ struct hvm_domain { int pbuf_index; char pbuf[HVM_PBUF_SIZE]; + + uint64_t params[HVM_NR_PARAMS]; }; #endif /* __ASM_X86_HVM_DOMAIN_H__ */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index b3ab26ed1d..57d5895b9e 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -66,6 +66,7 @@ #define __HYPERVISOR_xenoprof_op 31 #define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_physdev_op 33 +#define __HYPERVISOR_hvm_op 34 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h index 763819170d..5635fa1961 100644 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -87,4 +87,9 @@ do_nmi_op( unsigned int cmd, XEN_GUEST_HANDLE(void) arg); +extern long +do_hvm_op( + unsigned long op, + XEN_GUEST_HANDLE(void) arg); + #endif /* __XEN_HYPERCALL_H__ */ From e661d66f514c52fdb0e56d29f8aa0db5ec5ced64 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 13:54:05 +0100 Subject: [PATCH 063/111] Missing file from previous changeset. --- xen/include/public/hvm/params.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 xen/include/public/hvm/params.h diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h new file mode 100644 index 0000000000..432b32cb67 --- /dev/null +++ b/xen/include/public/hvm/params.h @@ -0,0 +1,24 @@ +#ifndef __XEN_PUBLIC_HVM_PARAMS_H__ +#define __XEN_PUBLIC_HVM_PARAMS_H__ + +/* Parameter space. */ +#define HVM_PARAM_CALLBACK_IRQ 0 +#define HVM_PARAM_STORE_PFN 1 +#define HVM_PARAM_STORE_EVTCHN 2 +#define HVM_PARAM_APIC_ENABLED 3 +#define HVM_PARAM_PAE_ENABLED 4 +#define HVM_NR_PARAMS 5 + +/* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */ +#define HVMOP_set_param 0 +#define HVMOP_get_param 1 + +struct xen_hvm_param { + domid_t domid; /* IN */ + uint32_t index; /* IN */ + uint64_t value; /* IN/OUT */ +}; +typedef struct xen_hvm_param xen_hvm_param_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t); + +#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ From 8a8cef762760a9821650dd4ec385855ce2af9292 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 13:55:41 +0100 Subject: [PATCH 064/111] [HVM] Declare vlapic_ipi() as static. Used only once. Signed-off-by: Steven Smith --- xen/arch/x86/hvm/vlapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 700a516b4d..7ccfdb7aec 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -377,7 +377,7 @@ static int vlapic_check_vector(struct vlapic *vlapic, return 1; } -void vlapic_ipi(struct vlapic *vlapic) +static void vlapic_ipi(struct vlapic *vlapic) { uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR); uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2); From 40460c8425e61e4ab4718ba288075f1e9a297284 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 14:01:09 +0100 Subject: [PATCH 065/111] [HVM][VMX] Get rid of unused 'error' local variable. Signed-off-by: Steven Smith --- xen/arch/x86/hvm/vmx/vmx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index b13f067675..7f5439ddf7 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2184,11 +2184,10 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) * (1) We can get an exception (e.g. #PG) in the guest, or * (2) NMI */ - int error; unsigned int vector; unsigned long va; - if ((error = __vmread(VM_EXIT_INTR_INFO, &vector)) + if (__vmread(VM_EXIT_INTR_INFO, &vector) || !(vector & INTR_INFO_VALID_MASK)) __hvm_bug(®s); vector &= INTR_INFO_VECTOR_MASK; @@ -2261,7 +2260,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) (unsigned long)regs.ecx, (unsigned long)regs.edx, (unsigned long)regs.esi, (unsigned long)regs.edi); - if (!(error = vmx_do_page_fault(va, ®s))) { + if (!vmx_do_page_fault(va, ®s)) { /* * Inject #PG using Interruption-Information Fields */ From 401177d41ae2f83d68998d3420d2f7211c3be66e Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 14:02:29 +0100 Subject: [PATCH 066/111] [HVM] Remove unused ioreq state IORESP_HOOK. Signed-off-by: Steven Smith --- xen/arch/ia64/vmx/vmx_support.c | 3 --- xen/include/public/hvm/ioreq.h | 1 - 2 files changed, 4 deletions(-) diff --git a/xen/arch/ia64/vmx/vmx_support.c b/xen/arch/ia64/vmx/vmx_support.c index 7b90a08bdb..602f077874 100644 --- a/xen/arch/ia64/vmx/vmx_support.c +++ b/xen/arch/ia64/vmx/vmx_support.c @@ -83,9 +83,6 @@ void vmx_io_assist(struct vcpu *v) p = &vio->vp_ioreq; - if (p->state == STATE_IORESP_HOOK) - panic_domain(vcpu_regs(v),"Not supported: No hook available for DM request\n"); - if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { if (p->state != STATE_IORESP_READY) { /* Can't block here, for the same reason as other places to diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h index 76e107045c..7bc5782db9 100644 --- a/xen/include/public/hvm/ioreq.h +++ b/xen/include/public/hvm/ioreq.h @@ -27,7 +27,6 @@ #define STATE_IOREQ_READY 1 #define STATE_IOREQ_INPROCESS 2 #define STATE_IORESP_READY 3 -#define STATE_IORESP_HOOK 4 #define IOREQ_TYPE_PIO 0 /* pio */ #define IOREQ_TYPE_COPY 1 /* mmio ops */ From 69b5fc7b8800767a7cc92b5719d04ae2e771038d Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 14:20:45 +0100 Subject: [PATCH 067/111] [XEN] Allow add_to_physmap to be applied to DOMID_SELF. Also sanitise handling of existing mappings of Xen heap frames. Signed-off-by: Steven Smith Signed-off-by: Keir Fraser --- xen/arch/x86/mm.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 40928a555d..3b457e3a6f 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2976,13 +2976,20 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) case XENMEM_add_to_physmap: { struct xen_add_to_physmap xatp; - unsigned long mfn = 0, gpfn; + unsigned long prev_mfn, mfn = 0, gpfn; struct domain *d; if ( copy_from_guest(&xatp, arg, 1) ) return -EFAULT; - if ( (d = find_domain_by_id(xatp.domid)) == NULL ) + if ( xatp.domid == DOMID_SELF ) + { + d = current->domain; + get_knownalive_domain(d); + } + else if ( !IS_PRIV(current->domain) ) + return -EPERM; + else if ( (d = find_domain_by_id(xatp.domid)) == NULL ) return -ESRCH; switch ( xatp.space ) @@ -3008,8 +3015,16 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) LOCK_BIGLOCK(d); /* Remove previously mapped page if it was present. */ - if ( mfn_valid(gmfn_to_mfn(d, xatp.gpfn)) ) - guest_remove_page(d, xatp.gpfn); + prev_mfn = gmfn_to_mfn(d, xatp.gpfn); + if ( mfn_valid(prev_mfn) ) + { + if ( IS_XEN_HEAP_FRAME(mfn_to_page(prev_mfn)) ) + /* Xen heap frames are simply unhooked from this phys slot. */ + guest_physmap_remove_page(d, xatp.gpfn, prev_mfn); + else + /* Normal domain memory is freed, to avoid leaking memory. */ + guest_remove_page(d, xatp.gpfn); + } /* Unmap from old location, if any. */ gpfn = get_gpfn_from_mfn(mfn); From 04f6e36b47f9b526942dba01c3c69ca9810313df Mon Sep 17 00:00:00 2001 From: "vhanquez@gwig.uk.xensource.com" Date: Thu, 3 Aug 2006 13:44:05 +0000 Subject: [PATCH 068/111] remove '=' between command line name/argument. ease parsing without getopt. Signed-off-by: Vincent Hanquez --- tools/misc/xend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/misc/xend b/tools/misc/xend index e9bd8e18c7..82198fcea3 100644 --- a/tools/misc/xend +++ b/tools/misc/xend @@ -84,7 +84,7 @@ def check_user(): def start_xenstored(): XENSTORED_TRACE = os.getenv("XENSTORED_TRACE") - cmd = "xenstored --pid-file=/var/run/xenstore.pid" + cmd = "xenstored --pid-file /var/run/xenstore.pid" if XENSTORED_TRACE: cmd += " -T /var/log/xenstored-trace.log" s,o = commands.getstatusoutput(cmd) From 96eeda192e6271ff79dc6ba5ba7a586d67b6d535 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 15:02:34 +0100 Subject: [PATCH 069/111] [HVM] Tidy up e820 parsing in Xen. Signed-off-by: Steven Smith --- xen/arch/x86/hvm/hvm.c | 87 ++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 9fcd17be41..9dd0fee66f 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -60,6 +60,8 @@ static void hvm_zap_mmio_range( { unsigned long i, val = INVALID_MFN; + ASSERT(d == current->domain); + for ( i = 0; i < nr_pfn; i++ ) { if ( pfn + i >= 0xfffff ) @@ -69,25 +71,36 @@ static void hvm_zap_mmio_range( } } -static void hvm_map_io_shared_page(struct domain *d) +static void e820_zap_iommu_callback(struct domain *d, + struct e820entry *e, + void *ign) +{ + if ( e->type == E820_IO ) + hvm_zap_mmio_range(d, e->addr >> PAGE_SHIFT, e->size >> PAGE_SHIFT); +} + +static void e820_foreach(struct domain *d, + void (*cb)(struct domain *d, + struct e820entry *e, + void *data), + void *data) { int i; unsigned char e820_map_nr; struct e820entry *e820entry; unsigned char *p; unsigned long mfn; - unsigned long gpfn = 0; - local_flush_tlb_pge(); - - mfn = get_mfn_from_gpfn(E820_MAP_PAGE >> PAGE_SHIFT); - if (mfn == INVALID_MFN) { + mfn = gmfn_to_mfn(d, E820_MAP_PAGE >> PAGE_SHIFT); + if ( mfn == INVALID_MFN ) + { printk("Can not find E820 memory map page for HVM domain.\n"); domain_crash_synchronous(); } p = map_domain_page(mfn); - if (p == NULL) { + if ( p == NULL ) + { printk("Can not map E820 memory map page for HVM domain.\n"); domain_crash_synchronous(); } @@ -96,36 +109,52 @@ static void hvm_map_io_shared_page(struct domain *d) e820entry = (struct e820entry *)(p + E820_MAP_OFFSET); for ( i = 0; i < e820_map_nr; i++ ) - { - if ( e820entry[i].type == E820_SHARED_PAGE ) - gpfn = (e820entry[i].addr >> PAGE_SHIFT); - if ( e820entry[i].type == E820_IO ) - hvm_zap_mmio_range( - d, - e820entry[i].addr >> PAGE_SHIFT, - e820entry[i].size >> PAGE_SHIFT); - } + cb(d, e820entry + i, data); - if ( gpfn == 0 ) { - printk("Can not get io request shared page" - " from E820 memory map for HVM domain.\n"); - unmap_domain_page(p); - domain_crash_synchronous(); - } unmap_domain_page(p); +} - /* Initialise shared page */ - mfn = get_mfn_from_gpfn(gpfn); - if (mfn == INVALID_MFN) { +static void hvm_zap_iommu_pages(struct domain *d) +{ + e820_foreach(d, e820_zap_iommu_callback, NULL); +} + +static void e820_map_io_shared_callback(struct domain *d, + struct e820entry *e, + void *data) +{ + unsigned long *mfn = data; + if ( e->type == E820_SHARED_PAGE ) + { + ASSERT(*mfn == INVALID_MFN); + *mfn = gmfn_to_mfn(d, e->addr >> PAGE_SHIFT); + } +} + +void hvm_map_io_shared_page(struct vcpu *v) +{ + unsigned long mfn = INVALID_MFN; + void *p; + struct domain *d = v->domain; + + if ( d->arch.hvm_domain.shared_page_va ) + return; + + e820_foreach(d, e820_map_io_shared_callback, &mfn); + + if ( mfn == INVALID_MFN ) + { printk("Can not find io request shared page for HVM domain.\n"); domain_crash_synchronous(); } p = map_domain_page_global(mfn); - if (p == NULL) { + if ( p == NULL ) + { printk("Can not map io request shared page for HVM domain.\n"); domain_crash_synchronous(); } + d->arch.hvm_domain.shared_page_va = (unsigned long)p; } @@ -143,7 +172,8 @@ void hvm_setup_platform(struct domain* d) domain_crash_synchronous(); } - hvm_map_io_shared_page(d); + hvm_zap_iommu_pages(d); + hvm_map_io_shared_page(v); platform = &d->arch.hvm_domain; pic_init(&platform->vpic, pic_irq_request, &platform->interrupt_request); @@ -155,7 +185,8 @@ void hvm_setup_platform(struct domain* d) hvm_vioapic_init(d); } - init_timer(&platform->pl_time.periodic_tm.timer, pt_timer_fn, v, v->processor); + init_timer(&platform->pl_time.periodic_tm.timer, + pt_timer_fn, v, v->processor); pit_init(v, cpu_khz); } From 72879391fb78a641b946e8b9e4edcb67e0945278 Mon Sep 17 00:00:00 2001 From: "ack@localhost.localdomain" Date: Thu, 3 Aug 2006 15:05:54 +0100 Subject: [PATCH 070/111] Change default scheduler in user's manual (from sedf to credit). Signed-off-by: Atsushi SAKAI --- docs/src/user.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/user.tex b/docs/src/user.tex index 923b3ae7da..eeec0721c0 100644 --- a/docs/src/user.tex +++ b/docs/src/user.tex @@ -3170,7 +3170,7 @@ editing \path{grub.conf}. \item [ tbuf\_size=xxx ] Set the size of the per-cpu trace buffers, in pages (default 0). \item [ sched=xxx ] Select the CPU scheduler Xen should use. The - current possibilities are `sedf' (default), `credit', and `bvt'. + current possibilities are `credit' (default), `sedf', and `bvt'. \item [ apic\_verbosity=debug,verbose ] Print more detailed information about local APIC and IOAPIC configuration. \item [ lapic ] Force use of local APIC even when left disabled by From 931e1a3a502ec16cd8c7ba154f13620c534e96dd Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 3 Aug 2006 15:22:25 +0100 Subject: [PATCH 071/111] [HVM] Make copy_{to,from}_guest work for HVM domains. Signed-off-by: Steven Smith --- xen/arch/x86/hvm/hvm.c | 9 ++++----- xen/arch/x86/hvm/platform.c | 14 ++++++++++++++ xen/include/asm-x86/guest_access.h | 20 +++++++++++++++++++- xen/include/asm-x86/hvm/guest_access.h | 7 +++++++ xen/include/asm-x86/shadow.h | 7 +++++++ 5 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 xen/include/asm-x86/hvm/guest_access.h diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 9dd0fee66f..7b348e32dd 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -254,7 +254,7 @@ int cpu_get_interrupt(struct vcpu *v, int *type) int hvm_copy(void *buf, unsigned long vaddr, int size, int dir) { - unsigned long gpa, mfn; + unsigned long mfn; char *addr; int count; @@ -263,10 +263,9 @@ hvm_copy(void *buf, unsigned long vaddr, int size, int dir) if (count > size) count = size; - if (hvm_paging_enabled(current)) { - gpa = gva_to_gpa(vaddr); - mfn = get_mfn_from_gpfn(gpa >> PAGE_SHIFT); - } else + if (hvm_paging_enabled(current)) + mfn = gva_to_mfn(vaddr); + else mfn = get_mfn_from_gpfn(vaddr >> PAGE_SHIFT); if (mfn == INVALID_MFN) return 0; diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 1b5c5966af..efe443a8a0 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -1034,6 +1034,20 @@ void handle_mmio(unsigned long va, unsigned long gpa) } } +/* Note that copy_{to,from}_user_hvm don't set the A and D bits on + PTEs, and require the PTE to be writable even when they're only + trying to read from it. The guest is expected to deal with + this. */ +unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len) +{ + return !hvm_copy((void *)from, (unsigned long)to, len, HVM_COPY_OUT); +} + +unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len) +{ + return !hvm_copy(to, (unsigned long)from, len, HVM_COPY_IN); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-x86/guest_access.h b/xen/include/asm-x86/guest_access.h index 7be0f3efe6..7b88aad86b 100644 --- a/xen/include/asm-x86/guest_access.h +++ b/xen/include/asm-x86/guest_access.h @@ -8,6 +8,8 @@ #define __ASM_X86_GUEST_ACCESS_H__ #include +#include +#include /* Is the guest handle a NULL reference? */ #define guest_handle_is_null(hnd) ((hnd).p == NULL) @@ -28,6 +30,8 @@ #define copy_to_guest_offset(hnd, off, ptr, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \ copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ }) @@ -38,6 +42,8 @@ #define copy_from_guest_offset(ptr, hnd, off, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_from_user_hvm(_y, _x+(off), sizeof(*_x)*(nr)) :\ copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ }) @@ -45,6 +51,8 @@ #define copy_field_to_guest(hnd, ptr, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x, _y, sizeof(*_x)) : \ copy_to_user(_x, _y, sizeof(*_x)); \ }) @@ -52,6 +60,8 @@ #define copy_field_from_guest(ptr, hnd, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_from_user_hvm(_y, _x, sizeof(*_x)) : \ copy_from_user(_y, _x, sizeof(*_x)); \ }) @@ -60,29 +70,37 @@ * Allows use of faster __copy_* functions. */ #define guest_handle_okay(hnd, nr) \ - array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)) + (hvm_guest(current) || array_access_ok((hnd).p, (nr), sizeof(*(hnd).p))) #define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \ __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ }) #define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ + hvm_guest(current) ? \ + copy_from_user_hvm(_y, _x+(off),sizeof(*_x)*(nr)) : \ __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ }) #define __copy_field_to_guest(hnd, ptr, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_to_user_hvm(_x, _y, sizeof(*_x)) : \ __copy_to_user(_x, _y, sizeof(*_x)); \ }) #define __copy_field_from_guest(ptr, hnd, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ + hvm_guest(current) ? \ + copy_from_user_hvm(_x, _y, sizeof(*_x)) : \ __copy_from_user(_y, _x, sizeof(*_x)); \ }) diff --git a/xen/include/asm-x86/hvm/guest_access.h b/xen/include/asm-x86/hvm/guest_access.h new file mode 100644 index 0000000000..7a89e81536 --- /dev/null +++ b/xen/include/asm-x86/hvm/guest_access.h @@ -0,0 +1,7 @@ +#ifndef __ASM_X86_HVM_GUEST_ACCESS_H__ +#define __ASM_X86_HVM_GUEST_ACCESS_H__ + +unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len); +unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len); + +#endif /* __ASM_X86_HVM_GUEST_ACCESS_H__ */ diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 397d4beb6b..f7d76af88e 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -1734,6 +1734,13 @@ static inline unsigned long gva_to_gpa(unsigned long gva) return l1e_get_paddr(gpte) + (gva & ~PAGE_MASK); } #endif + +static inline unsigned long gva_to_mfn(unsigned long gva) +{ + unsigned long gpa = gva_to_gpa(gva); + return get_mfn_from_gpfn(gpa >> PAGE_SHIFT); +} + /************************************************************************/ extern void __update_pagetables(struct vcpu *v); From ae97d42025bb00a13fd9562920f743b0a555cff6 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Thu, 3 Aug 2006 18:28:29 +0100 Subject: [PATCH 072/111] [qemu] Use xenstore to configure ioemu block devices. - read ioemu block device config from xenstore - don't require the ioemu: prefix on block devices any longer - allow change of media associated with cdrom drives - replace cdrom= option by :cdrom suffix on regular block device config: 'file:/root/mytest.iso,hdc:cdrom,r' - don't create default cdrom drive anymore - to create default empty cdrom drive use: ',hdc:cdrom,r' Signed-off-by: Christian Limpach --- tools/examples/block | 18 ++- tools/examples/xmexample.hvm | 6 +- tools/ioemu/Makefile.target | 1 + tools/ioemu/block.c | 1 + tools/ioemu/hw/ide.c | 1 + tools/ioemu/monitor.c | 5 +- tools/ioemu/vl.c | 39 +++++- tools/ioemu/vl.h | 9 ++ tools/ioemu/xenstore.c | 187 ++++++++++++++++++++++++++ tools/python/xen/xend/image.py | 25 +--- tools/python/xen/xend/server/blkif.py | 23 ++-- tools/python/xen/xm/create.py | 6 +- 12 files changed, 278 insertions(+), 43 deletions(-) create mode 100644 tools/ioemu/xenstore.c diff --git a/tools/examples/block b/tools/examples/block index dae32dc234..14af64a66d 100644 --- a/tools/examples/block +++ b/tools/examples/block @@ -239,8 +239,11 @@ case "$command" in exit 0 fi - p=$(xenstore_read "$XENBUS_PATH/params") - mode=$(xenstore_read "$XENBUS_PATH/mode") + if [ -n "$t" ] + then + p=$(xenstore_read "$XENBUS_PATH/params") + mode=$(xenstore_read "$XENBUS_PATH/mode") + fi case $t in phy) @@ -370,6 +373,13 @@ mount it read-write in a guest domain." release_lock "block" exit 0 ;; + + "") + claim_lock "block" + success + echo happy gun \"$t\" >>/tmp/block.$$ + release_lock "block" + ;; esac ;; @@ -384,6 +394,10 @@ mount it read-write in a guest domain." losetup -d "$node" exit 0 ;; + + "") + exit 0 + ;; esac ;; diff --git a/tools/examples/xmexample.hvm b/tools/examples/xmexample.hvm index 2d2eef8735..b303adfead 100644 --- a/tools/examples/xmexample.hvm +++ b/tools/examples/xmexample.hvm @@ -66,7 +66,7 @@ vif = [ 'type=ioemu, bridge=xenbr0' ] # and MODE is r for read-only, w for read-write. #disk = [ 'phy:hda1,hda1,r' ] -disk = [ 'file:/var/images/min-el3-i386.img,ioemu:hda,w' ] +disk = [ 'file:/var/images/min-el3-i386.img,hda,w', ',hdc:cdrom,r' ] #---------------------------------------------------------------------------- # Configure the behaviour when a domain exits. There are three 'reasons' @@ -110,10 +110,6 @@ disk = [ 'file:/var/images/min-el3-i386.img,ioemu:hda,w' ] # New stuff device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm' -#----------------------------------------------------------------------------- -# Disk image for -#cdrom= - #----------------------------------------------------------------------------- # boot on floppy (a), hard disk (c) or CD-ROM (d) #boot=[a|c|d] diff --git a/tools/ioemu/Makefile.target b/tools/ioemu/Makefile.target index 253fef1b5d..e08247310d 100644 --- a/tools/ioemu/Makefile.target +++ b/tools/ioemu/Makefile.target @@ -336,6 +336,7 @@ VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o VL_OBJS+= piix4acpi.o +VL_OBJS+= xenstore.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/tools/ioemu/block.c b/tools/ioemu/block.c index b908167186..9c628f93bf 100644 --- a/tools/ioemu/block.c +++ b/tools/ioemu/block.c @@ -750,6 +750,7 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; + bs->total_sectors = 0; close(s->fd); } diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c index 9769dfee5f..444bfe6184 100644 --- a/tools/ioemu/hw/ide.c +++ b/tools/ioemu/hw/ide.c @@ -1279,6 +1279,7 @@ static void ide_atapi_cmd(IDEState *s) } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + xenstore_check_new_media_present(1000); } break; case GPCMD_MODE_SENSE_10: diff --git a/tools/ioemu/monitor.c b/tools/ioemu/monitor.c index e5d49d7192..071c62a35a 100644 --- a/tools/ioemu/monitor.c +++ b/tools/ioemu/monitor.c @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" #include +#include "block_int.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -328,7 +329,7 @@ static int eject_device(BlockDriverState *bs, int force) return 0; } -static void do_eject(int force, const char *filename) +void do_eject(int force, const char *filename) { BlockDriverState *bs; @@ -340,7 +341,7 @@ static void do_eject(int force, const char *filename) eject_device(bs, force); } -static void do_change(const char *device, const char *filename) +void do_change(const char *device, const char *filename) { BlockDriverState *bs; int i; diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index d5f71c45ca..1f2edace32 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -4709,9 +4709,11 @@ void help(void) "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" +#ifndef CONFIG_DM "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" +#endif /* !CONFIG_DM */ "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB [default=%d]\n" @@ -4841,11 +4843,13 @@ enum { QEMU_OPTION_M, QEMU_OPTION_fda, QEMU_OPTION_fdb, +#ifndef CONFIG_DM QEMU_OPTION_hda, QEMU_OPTION_hdb, QEMU_OPTION_hdc, QEMU_OPTION_hdd, QEMU_OPTION_cdrom, +#endif /* !CONFIG_DM */ QEMU_OPTION_boot, QEMU_OPTION_snapshot, QEMU_OPTION_m, @@ -4911,11 +4915,13 @@ const QEMUOption qemu_options[] = { { "M", HAS_ARG, QEMU_OPTION_M }, { "fda", HAS_ARG, QEMU_OPTION_fda }, { "fdb", HAS_ARG, QEMU_OPTION_fdb }, +#ifndef CONFIG_DM { "hda", HAS_ARG, QEMU_OPTION_hda }, { "hdb", HAS_ARG, QEMU_OPTION_hdb }, { "hdc", HAS_ARG, QEMU_OPTION_hdc }, { "hdd", HAS_ARG, QEMU_OPTION_hdd }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, +#endif /* !CONFIG_DM */ { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, { "m", HAS_ARG, QEMU_OPTION_m }, @@ -5250,10 +5256,16 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif - int i, cdrom_index; + int i; +#ifndef CONFIG_DM + int cdrom_index; +#endif /* !CONFIG_DM */ int snapshot, linux_boot; const char *initrd_filename; - const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; +#ifndef CONFIG_DM + const char *hd_filename[MAX_DISKS]; +#endif /* !CONFIG_DM */ + const char *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -5288,8 +5300,10 @@ int main(int argc, char **argv) initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; +#ifndef CONFIG_DM for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; +#endif /* !CONFIG_DM */ ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; @@ -5302,11 +5316,13 @@ int main(int argc, char **argv) vncviewer = 0; kernel_filename = NULL; kernel_cmdline = ""; +#ifndef CONFIG_DM #ifdef TARGET_PPC cdrom_index = 1; #else cdrom_index = 2; #endif +#endif /* !CONFIG_DM */ cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); @@ -5339,7 +5355,11 @@ int main(int argc, char **argv) break; r = argv[optind]; if (r[0] != '-') { +#ifndef CONFIG_DM hd_filename[0] = argv[optind++]; +#else + help(); +#endif /* !CONFIG_DM */ } else { const QEMUOption *popt; @@ -5383,6 +5403,7 @@ int main(int argc, char **argv) case QEMU_OPTION_initrd: initrd_filename = optarg; break; +#ifndef CONFIG_DM case QEMU_OPTION_hda: case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: @@ -5395,6 +5416,7 @@ int main(int argc, char **argv) cdrom_index = -1; } break; +#endif /* !CONFIG_DM */ case QEMU_OPTION_snapshot: snapshot = 1; break; @@ -5447,11 +5469,13 @@ int main(int argc, char **argv) case QEMU_OPTION_append: kernel_cmdline = optarg; break; +#ifndef CONFIG_DM case QEMU_OPTION_cdrom: if (cdrom_index >= 0) { hd_filename[cdrom_index] = optarg; } break; +#endif /* !CONFIG_DM */ case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && @@ -5690,12 +5714,18 @@ int main(int argc, char **argv) } } +#ifdef CONFIG_DM + bdrv_init(); + xenstore_parse_domain_config(domid); +#endif /* CONFIG_DM */ + #ifdef USE_KQEMU if (smp_cpus > 1) kqemu_allowed = 0; #endif linux_boot = (kernel_filename != NULL); +#ifndef CONFIG_DM if (!linux_boot && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && @@ -5709,6 +5739,7 @@ int main(int argc, char **argv) else boot_device = 'd'; } +#endif /* !CONFIG_DM */ #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ @@ -5848,6 +5879,7 @@ int main(int argc, char **argv) #endif /* !CONFIG_DM */ +#ifndef CONFIG_DM /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { @@ -5874,6 +5906,7 @@ int main(int argc, char **argv) } } } +#endif /* !CONFIG_DM */ /* we always create at least one floppy disk */ fd_table[0] = bdrv_new("fda"); @@ -6009,6 +6042,8 @@ int main(int argc, char **argv) #endif init_timers(); + qemu_set_fd_handler(xenstore_fd(), xenstore_process_event, NULL, NULL); + machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename, diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index e10bfcc058..28990cb8dd 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -1092,6 +1092,8 @@ void term_flush(void); void term_print_help(void); void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size); +void do_eject(int force, const char *filename); +void do_change(const char *device, const char *filename); /* readline.c */ typedef void ReadLineFunc(void *opaque, const char *str); @@ -1104,6 +1106,13 @@ const char *readline_get_history(unsigned int index); void readline_start(const char *prompt, int is_password, ReadLineFunc *readline_func, void *opaque); +/* xenstore.c */ +void xenstore_parse_domain_config(int domid); +int xenstore_fd(void); +void xenstore_process_event(void *opaque); +void xenstore_check_new_media_present(int timeout); + + void kqemu_record_dump(void); extern char domain_name[]; diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c new file mode 100644 index 0000000000..e1c20bb180 --- /dev/null +++ b/tools/ioemu/xenstore.c @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2006 Christian Limpach + * Copyright (C) 2006 XenSource Ltd. + * + */ + +#include "vl.h" +#include "block_int.h" + +static struct xs_handle *xsh = NULL; +static char *hd_filename[MAX_DISKS]; +static QEMUTimer *insert_timer = NULL; + +static int pasprintf(char **buf, const char *fmt, ...) +{ + va_list ap; + int ret = 0; + + if (*buf) + free(*buf); + va_start(ap, fmt); + if (vasprintf(buf, fmt, ap) == -1) { + buf = NULL; + ret = -1; + } + va_end(ap); + return ret; +} + +static void insert_media(void *opaque) +{ + int i; + + for (i = 0; i < MAX_DISKS; i++) { + if (hd_filename[i]) { + do_change(bs_table[i]->device_name, hd_filename[i]); + free(hd_filename[i]); + hd_filename[i] = NULL; + } + } +} + +void xenstore_check_new_media_present(int timeout) +{ + + if (insert_timer == NULL) + insert_timer = qemu_new_timer(rt_clock, insert_media, NULL); + qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout); +} + +void xenstore_parse_domain_config(int domid) +{ + char **e = NULL; + char *buf = NULL, *path; + char *bpath = NULL, *dev = NULL, *params = NULL, *type = NULL; + int i; + unsigned int len, num, hd_index; + + for(i = 0; i < MAX_DISKS; i++) + hd_filename[i] = NULL; + + xsh = xs_daemon_open(); + if (xsh == NULL) { + fprintf(logfile, "Could not contact xenstore for domain config\n"); + return; + } + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(logfile, "xs_get_domain_path() error\n"); + goto out; + } + + if (pasprintf(&buf, "%s/device/vbd", path) == -1) + goto out; + + e = xs_directory(xsh, XBT_NULL, buf, &num); + if (e == NULL) + goto out; + + for (i = 0; i < num; i++) { + /* read the backend path */ + if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1) + continue; + free(bpath); + bpath = xs_read(xsh, XBT_NULL, buf, &len); + if (bpath == NULL) + continue; + /* read the name of the device */ + if (pasprintf(&buf, "%s/dev", bpath) == -1) + continue; + free(dev); + dev = xs_read(xsh, XBT_NULL, buf, &len); + if (dev == NULL) + continue; + if (strncmp(dev, "hd", 2) || strlen(dev) != 3) + continue; + hd_index = dev[2] - 'a'; + if (hd_index > MAX_DISKS) + continue; + /* read the type of the device */ + if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1) + continue; + free(type); + type = xs_read(xsh, XBT_NULL, buf, &len); + /* read params to get the patch of the image -- read it last + * so that we have its path in buf when setting up the + * watch */ + if (pasprintf(&buf, "%s/params", bpath) == -1) + continue; + free(params); + params = xs_read(xsh, XBT_NULL, buf, &len); + if (params == NULL) + continue; + if (params[0]) { + hd_filename[hd_index] = params; /* strdup() */ + params = NULL; /* don't free params on re-use */ + } + bs_table[hd_index] = bdrv_new(dev); + /* check if it is a cdrom */ + if (type && !strcmp(type, "cdrom")) { + bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM); + xs_watch(xsh, buf, dev); + } + if (hd_filename[hd_index]) { + if (bdrv_open(bs_table[hd_index], hd_filename[hd_index], + 0 /* snapshot */) < 0) + fprintf(stderr, "qemu: could not open hard disk image '%s'\n", + hd_filename[hd_index]); + } + } + + out: + free(type); + free(params); + free(dev); + free(bpath); + free(buf); + free(path); + free(e); + return; +} + +int xenstore_fd(void) +{ + if (xsh) + return xs_fileno(xsh); + return -1; +} + +void xenstore_process_event(void *opaque) +{ + char **vec, *image = NULL; + unsigned int len, num, hd_index; + + vec = xs_read_watch(xsh, &num); + if (!vec) + return; + + if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) || + strlen(vec[XS_WATCH_TOKEN]) != 3) + goto out; + hd_index = vec[XS_WATCH_TOKEN][2] - 'a'; + image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len); + if (image == NULL || !strcmp(image, bs_table[hd_index]->filename)) + goto out; /* gone or identical */ + + do_eject(0, vec[XS_WATCH_TOKEN]); + bs_table[hd_index]->filename[0] = 0; + if (hd_filename[hd_index]) { + free(hd_filename[hd_index]); + hd_filename[hd_index] = NULL; + } + + if (image[0]) { + hd_filename[hd_index] = strdup(image); + xenstore_check_new_media_present(5000); + } + + out: + free(image); + free(vec); +} diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 12606a58bd..d74668ab27 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -249,7 +249,7 @@ class HVMImageHandler(ImageHandler): # Return a list of cmd line args to the device models based on the # xm config file def parseDeviceModelArgs(self, imageConfig, deviceConfig): - dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'audio', + dmargs = [ 'boot', 'fda', 'fdb', 'audio', 'localtime', 'serial', 'stdvga', 'isa', 'vcpus', 'usb', 'usbdevice'] ret = [] @@ -277,24 +277,11 @@ class HVMImageHandler(ImageHandler): for (name, info) in deviceConfig: if name == 'vbd': uname = sxp.child_value(info, 'uname') - typedev = sxp.child_value(info, 'dev') - (_, vbdparam) = string.split(uname, ':', 1) - - if 'file:' in uname and not os.path.isfile(vbdparam): - raise VmError('Disk image does not exist: %s' % vbdparam) - - if 'ioemu:' in typedev: - (emtype, vbddev) = string.split(typedev, ':', 1) - else: - emtype = 'vbd' - vbddev = typedev - if emtype == 'vbd': - continue; - vbddev_list = ['hda', 'hdb', 'hdc', 'hdd'] - if vbddev not in vbddev_list: - raise VmError("hvm: for qemu vbd type=file&dev=hda~hdd") - ret.append("-%s" % vbddev) - ret.append("%s" % vbdparam) + if 'file:' in uname: + (_, vbdparam) = string.split(uname, ':', 1) + if not os.path.isfile(vbdparam): + raise VmError('Disk image does not exist: %s' % + vbdparam) if name == 'vif': type = sxp.child_value(info, 'type') if type != 'ioemu': diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 986d065be9..d131ea7843 100644 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -45,7 +45,17 @@ class BlkifController(DevController): dev = sxp.child_value(config, 'dev') - (typ, params) = string.split(uname, ':', 1) + if 'ioemu:' in dev: + (_, dev) = string.split(dev, ':', 1) + try: + (dev, dev_type) = string.split(dev, ':', 1) + except ValueError: + dev_type = "disk" + + try: + (typ, params) = string.split(uname, ':', 1) + except ValueError: + (typ, params) = ("", "") back = { 'dev' : dev, 'type' : typ, 'params' : params, @@ -58,13 +68,10 @@ class BlkifController(DevController): 'acm_ssidref': str(ssidref), 'acm_policy' : policy}) - if 'ioemu:' in dev: - (dummy, dev1) = string.split(dev, ':', 1) - devid = blkif.blkdev_name_to_number(dev1) - front = {} - else: - devid = blkif.blkdev_name_to_number(dev) - front = { 'virtual-device' : "%i" % devid } + devid = blkif.blkdev_name_to_number(dev) + front = { 'virtual-device' : "%i" % devid, + 'device-type' : dev_type + } return (devid, back, front) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 77b0301772..109e8a8741 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -392,10 +392,6 @@ gopts.var('isa', val='no|yes', fn=set_bool, default=0, use="Simulate an ISA only system?") -gopts.var('cdrom', val='FILE', - fn=set_value, default='', - use="Path to cdrom") - gopts.var('boot', val="a|b|c|d", fn=set_value, default='c', use="Default boot device") @@ -629,7 +625,7 @@ def configure_vifs(config_devs, vals): def configure_hvm(config_image, vals): """Create the config for HVM devices. """ - args = [ 'device_model', 'pae', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb', + args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'audio', 'vnc', 'vncdisplay', 'vncconsole', 'sdl', 'display', 'acpi', 'apic', 'xauthority', 'usb', 'usbdevice' ] From c944f2233fe58d672c183d0e36aa5830dfab270d Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Thu, 3 Aug 2006 18:34:03 +0100 Subject: [PATCH 073/111] [qemu patches] Update patches for changeset 10921:4c2fab8f8c34. Signed-off-by: Christian Limpach --- tools/ioemu/patches/series | 1 + .../patches/xenstore-block-device-config | 467 ++++++++++++++++++ 2 files changed, 468 insertions(+) create mode 100644 tools/ioemu/patches/xenstore-block-device-config diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index e57ea3caea..8f20f6e166 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -35,3 +35,4 @@ vnc-fixes vnc-start-vncviewer vnc-title-domain-name vnc-access-monitor-vt +xenstore-block-device-config diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config new file mode 100644 index 0000000000..c2b03bf3d5 --- /dev/null +++ b/tools/ioemu/patches/xenstore-block-device-config @@ -0,0 +1,467 @@ +Index: ioemu/Makefile.target +=================================================================== +--- ioemu.orig/Makefile.target 2006-08-03 17:57:38.861210420 +0100 ++++ ioemu/Makefile.target 2006-08-03 17:58:02.317549891 +0100 +@@ -336,6 +336,7 @@ + VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o + VL_OBJS+= cirrus_vga.o mixeng.o parallel.o + VL_OBJS+= piix4acpi.o ++VL_OBJS+= xenstore.o + DEFINES += -DHAS_AUDIO + endif + ifeq ($(TARGET_BASE_ARCH), ppc) +Index: ioemu/xenstore.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/xenstore.c 2006-08-03 17:58:02.326548870 +0100 +@@ -0,0 +1,187 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General ++ * Public License. See the file "COPYING" in the main directory of ++ * this archive for more details. ++ * ++ * Copyright (C) 2006 Christian Limpach ++ * Copyright (C) 2006 XenSource Ltd. ++ * ++ */ ++ ++#include "vl.h" ++#include "block_int.h" ++ ++static struct xs_handle *xsh = NULL; ++static char *hd_filename[MAX_DISKS]; ++static QEMUTimer *insert_timer = NULL; ++ ++static int pasprintf(char **buf, const char *fmt, ...) ++{ ++ va_list ap; ++ int ret = 0; ++ ++ if (*buf) ++ free(*buf); ++ va_start(ap, fmt); ++ if (vasprintf(buf, fmt, ap) == -1) { ++ buf = NULL; ++ ret = -1; ++ } ++ va_end(ap); ++ return ret; ++} ++ ++static void insert_media(void *opaque) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_DISKS; i++) { ++ if (hd_filename[i]) { ++ do_change(bs_table[i]->device_name, hd_filename[i]); ++ free(hd_filename[i]); ++ hd_filename[i] = NULL; ++ } ++ } ++} ++ ++void xenstore_check_new_media_present(int timeout) ++{ ++ ++ if (insert_timer == NULL) ++ insert_timer = qemu_new_timer(rt_clock, insert_media, NULL); ++ qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout); ++} ++ ++void xenstore_parse_domain_config(int domid) ++{ ++ char **e = NULL; ++ char *buf = NULL, *path; ++ char *bpath = NULL, *dev = NULL, *params = NULL, *type = NULL; ++ int i; ++ unsigned int len, num, hd_index; ++ ++ for(i = 0; i < MAX_DISKS; i++) ++ hd_filename[i] = NULL; ++ ++ xsh = xs_daemon_open(); ++ if (xsh == NULL) { ++ fprintf(logfile, "Could not contact xenstore for domain config\n"); ++ return; ++ } ++ ++ path = xs_get_domain_path(xsh, domid); ++ if (path == NULL) { ++ fprintf(logfile, "xs_get_domain_path() error\n"); ++ goto out; ++ } ++ ++ if (pasprintf(&buf, "%s/device/vbd", path) == -1) ++ goto out; ++ ++ e = xs_directory(xsh, XBT_NULL, buf, &num); ++ if (e == NULL) ++ goto out; ++ ++ for (i = 0; i < num; i++) { ++ /* read the backend path */ ++ if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1) ++ continue; ++ free(bpath); ++ bpath = xs_read(xsh, XBT_NULL, buf, &len); ++ if (bpath == NULL) ++ continue; ++ /* read the name of the device */ ++ if (pasprintf(&buf, "%s/dev", bpath) == -1) ++ continue; ++ free(dev); ++ dev = xs_read(xsh, XBT_NULL, buf, &len); ++ if (dev == NULL) ++ continue; ++ if (strncmp(dev, "hd", 2) || strlen(dev) != 3) ++ continue; ++ hd_index = dev[2] - 'a'; ++ if (hd_index > MAX_DISKS) ++ continue; ++ /* read the type of the device */ ++ if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1) ++ continue; ++ free(type); ++ type = xs_read(xsh, XBT_NULL, buf, &len); ++ /* read params to get the patch of the image -- read it last ++ * so that we have its path in buf when setting up the ++ * watch */ ++ if (pasprintf(&buf, "%s/params", bpath) == -1) ++ continue; ++ free(params); ++ params = xs_read(xsh, XBT_NULL, buf, &len); ++ if (params == NULL) ++ continue; ++ if (params[0]) { ++ hd_filename[hd_index] = params; /* strdup() */ ++ params = NULL; /* don't free params on re-use */ ++ } ++ bs_table[hd_index] = bdrv_new(dev); ++ /* check if it is a cdrom */ ++ if (type && !strcmp(type, "cdrom")) { ++ bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM); ++ xs_watch(xsh, buf, dev); ++ } ++ if (hd_filename[hd_index]) { ++ if (bdrv_open(bs_table[hd_index], hd_filename[hd_index], ++ 0 /* snapshot */) < 0) ++ fprintf(stderr, "qemu: could not open hard disk image '%s'\n", ++ hd_filename[hd_index]); ++ } ++ } ++ ++ out: ++ free(type); ++ free(params); ++ free(dev); ++ free(bpath); ++ free(buf); ++ free(path); ++ free(e); ++ return; ++} ++ ++int xenstore_fd(void) ++{ ++ if (xsh) ++ return xs_fileno(xsh); ++ return -1; ++} ++ ++void xenstore_process_event(void *opaque) ++{ ++ char **vec, *image = NULL; ++ unsigned int len, num, hd_index; ++ ++ vec = xs_read_watch(xsh, &num); ++ if (!vec) ++ return; ++ ++ if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) || ++ strlen(vec[XS_WATCH_TOKEN]) != 3) ++ goto out; ++ hd_index = vec[XS_WATCH_TOKEN][2] - 'a'; ++ image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len); ++ if (image == NULL || !strcmp(image, bs_table[hd_index]->filename)) ++ goto out; /* gone or identical */ ++ ++ do_eject(0, vec[XS_WATCH_TOKEN]); ++ bs_table[hd_index]->filename[0] = 0; ++ if (hd_filename[hd_index]) { ++ free(hd_filename[hd_index]); ++ hd_filename[hd_index] = NULL; ++ } ++ ++ if (image[0]) { ++ hd_filename[hd_index] = strdup(image); ++ xenstore_check_new_media_present(5000); ++ } ++ ++ out: ++ free(image); ++ free(vec); ++} +Index: ioemu/vl.c +=================================================================== +--- ioemu.orig/vl.c 2006-08-03 17:57:38.867209740 +0100 ++++ ioemu/vl.c 2006-08-03 17:58:02.323549210 +0100 +@@ -4709,9 +4709,11 @@ + "Standard options:\n" + "-M machine select emulated machine (-M ? for list)\n" + "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" ++#ifndef CONFIG_DM + "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" + "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" + "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" ++#endif /* !CONFIG_DM */ + "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" + "-snapshot write to temporary files instead of disk image files\n" + "-m megs set virtual RAM size to megs MB [default=%d]\n" +@@ -4841,11 +4843,13 @@ + QEMU_OPTION_M, + QEMU_OPTION_fda, + QEMU_OPTION_fdb, ++#ifndef CONFIG_DM + QEMU_OPTION_hda, + QEMU_OPTION_hdb, + QEMU_OPTION_hdc, + QEMU_OPTION_hdd, + QEMU_OPTION_cdrom, ++#endif /* !CONFIG_DM */ + QEMU_OPTION_boot, + QEMU_OPTION_snapshot, + QEMU_OPTION_m, +@@ -4911,11 +4915,13 @@ + { "M", HAS_ARG, QEMU_OPTION_M }, + { "fda", HAS_ARG, QEMU_OPTION_fda }, + { "fdb", HAS_ARG, QEMU_OPTION_fdb }, ++#ifndef CONFIG_DM + { "hda", HAS_ARG, QEMU_OPTION_hda }, + { "hdb", HAS_ARG, QEMU_OPTION_hdb }, + { "hdc", HAS_ARG, QEMU_OPTION_hdc }, + { "hdd", HAS_ARG, QEMU_OPTION_hdd }, + { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, ++#endif /* !CONFIG_DM */ + { "boot", HAS_ARG, QEMU_OPTION_boot }, + { "snapshot", 0, QEMU_OPTION_snapshot }, + { "m", HAS_ARG, QEMU_OPTION_m }, +@@ -5250,10 +5256,16 @@ + #ifdef CONFIG_GDBSTUB + int use_gdbstub, gdbstub_port; + #endif +- int i, cdrom_index; ++ int i; ++#ifndef CONFIG_DM ++ int cdrom_index; ++#endif /* !CONFIG_DM */ + int snapshot, linux_boot; + const char *initrd_filename; +- const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; ++#ifndef CONFIG_DM ++ const char *hd_filename[MAX_DISKS]; ++#endif /* !CONFIG_DM */ ++ const char *fd_filename[MAX_FD]; + const char *kernel_filename, *kernel_cmdline; + DisplayState *ds = &display_state; + int cyls, heads, secs, translation; +@@ -5288,8 +5300,10 @@ + initrd_filename = NULL; + for(i = 0; i < MAX_FD; i++) + fd_filename[i] = NULL; ++#ifndef CONFIG_DM + for(i = 0; i < MAX_DISKS; i++) + hd_filename[i] = NULL; ++#endif /* !CONFIG_DM */ + ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; + vga_ram_size = VGA_RAM_SIZE; + bios_size = BIOS_SIZE; +@@ -5302,11 +5316,13 @@ + vncviewer = 0; + kernel_filename = NULL; + kernel_cmdline = ""; ++#ifndef CONFIG_DM + #ifdef TARGET_PPC + cdrom_index = 1; + #else + cdrom_index = 2; + #endif ++#endif /* !CONFIG_DM */ + cyls = heads = secs = 0; + translation = BIOS_ATA_TRANSLATION_AUTO; + pstrcpy(monitor_device, sizeof(monitor_device), "vc"); +@@ -5339,7 +5355,11 @@ + break; + r = argv[optind]; + if (r[0] != '-') { ++#ifndef CONFIG_DM + hd_filename[0] = argv[optind++]; ++#else ++ help(); ++#endif /* !CONFIG_DM */ + } else { + const QEMUOption *popt; + +@@ -5383,6 +5403,7 @@ + case QEMU_OPTION_initrd: + initrd_filename = optarg; + break; ++#ifndef CONFIG_DM + case QEMU_OPTION_hda: + case QEMU_OPTION_hdb: + case QEMU_OPTION_hdc: +@@ -5395,6 +5416,7 @@ + cdrom_index = -1; + } + break; ++#endif /* !CONFIG_DM */ + case QEMU_OPTION_snapshot: + snapshot = 1; + break; +@@ -5447,11 +5469,13 @@ + case QEMU_OPTION_append: + kernel_cmdline = optarg; + break; ++#ifndef CONFIG_DM + case QEMU_OPTION_cdrom: + if (cdrom_index >= 0) { + hd_filename[cdrom_index] = optarg; + } + break; ++#endif /* !CONFIG_DM */ + case QEMU_OPTION_boot: + boot_device = optarg[0]; + if (boot_device != 'a' && +@@ -5690,12 +5714,18 @@ + } + } + ++#ifdef CONFIG_DM ++ bdrv_init(); ++ xenstore_parse_domain_config(domid); ++#endif /* CONFIG_DM */ ++ + #ifdef USE_KQEMU + if (smp_cpus > 1) + kqemu_allowed = 0; + #endif + linux_boot = (kernel_filename != NULL); + ++#ifndef CONFIG_DM + if (!linux_boot && + hd_filename[0] == '\0' && + (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && +@@ -5709,6 +5739,7 @@ + else + boot_device = 'd'; + } ++#endif /* !CONFIG_DM */ + + #if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ +@@ -5848,6 +5879,7 @@ + + #endif /* !CONFIG_DM */ + ++#ifndef CONFIG_DM + /* we always create the cdrom drive, even if no disk is there */ + bdrv_init(); + if (cdrom_index >= 0) { +@@ -5874,6 +5906,7 @@ + } + } + } ++#endif /* !CONFIG_DM */ + + /* we always create at least one floppy disk */ + fd_table[0] = bdrv_new("fda"); +@@ -6009,6 +6042,8 @@ + #endif + init_timers(); + ++ qemu_set_fd_handler(xenstore_fd(), xenstore_process_event, NULL, NULL); ++ + machine->init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename, +Index: ioemu/monitor.c +=================================================================== +--- ioemu.orig/monitor.c 2006-08-03 17:57:38.864210080 +0100 ++++ ioemu/monitor.c 2006-08-03 17:58:02.321549437 +0100 +@@ -24,6 +24,7 @@ + #include "vl.h" + #include "disas.h" + #include ++#include "block_int.h" + + //#define DEBUG + //#define DEBUG_COMPLETION +@@ -328,7 +329,7 @@ + return 0; + } + +-static void do_eject(int force, const char *filename) ++void do_eject(int force, const char *filename) + { + BlockDriverState *bs; + +@@ -340,7 +341,7 @@ + eject_device(bs, force); + } + +-static void do_change(const char *device, const char *filename) ++void do_change(const char *device, const char *filename) + { + BlockDriverState *bs; + int i; +Index: ioemu/block.c +=================================================================== +--- ioemu.orig/block.c 2006-08-03 17:57:38.861210420 +0100 ++++ ioemu/block.c 2006-08-03 17:58:02.318549777 +0100 +@@ -750,6 +750,7 @@ + static void raw_close(BlockDriverState *bs) + { + BDRVRawState *s = bs->opaque; ++ bs->total_sectors = 0; + close(s->fd); + } + +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-08-03 17:57:38.868209627 +0100 ++++ ioemu/vl.h 2006-08-03 17:58:02.324549097 +0100 +@@ -1092,6 +1092,8 @@ + void term_print_help(void); + void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size); ++void do_eject(int force, const char *filename); ++void do_change(const char *device, const char *filename); + + /* readline.c */ + typedef void ReadLineFunc(void *opaque, const char *str); +@@ -1104,6 +1106,13 @@ + void readline_start(const char *prompt, int is_password, + ReadLineFunc *readline_func, void *opaque); + ++/* xenstore.c */ ++void xenstore_parse_domain_config(int domid); ++int xenstore_fd(void); ++void xenstore_process_event(void *opaque); ++void xenstore_check_new_media_present(int timeout); ++ ++ + void kqemu_record_dump(void); + + extern char domain_name[]; +Index: ioemu/hw/ide.c +=================================================================== +--- ioemu.orig/hw/ide.c 2006-08-03 17:57:38.863210194 +0100 ++++ ioemu/hw/ide.c 2006-08-03 17:58:02.319549664 +0100 +@@ -1279,6 +1279,7 @@ + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); ++ xenstore_check_new_media_present(1000); + } + break; + case GPCMD_MODE_SENSE_10: From 2a33cbb5dbbf18272a2e15147241801df602526c Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Thu, 3 Aug 2006 19:14:41 +0100 Subject: [PATCH 074/111] [qemu] Write the port number where the vnc server is listening to xenstore. Signed-off-by: Christian Limpach --- tools/ioemu/vl.c | 1 + tools/ioemu/vl.h | 1 + tools/ioemu/xenstore.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 1f2edace32..34ae60df0b 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5954,6 +5954,7 @@ int main(int argc, char **argv) vnc_display_init(ds, vnc_display); if (vncviewer) vnc_start_viewer(vnc_display); + xenstore_write_vncport(vnc_display); } else { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 28990cb8dd..517209fb79 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -1111,6 +1111,7 @@ void xenstore_parse_domain_config(int domid); int xenstore_fd(void); void xenstore_process_event(void *opaque); void xenstore_check_new_media_present(int timeout); +void xenstore_write_vncport(int vnc_display); void kqemu_record_dump(void); diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c index e1c20bb180..fde469305a 100644 --- a/tools/ioemu/xenstore.c +++ b/tools/ioemu/xenstore.c @@ -185,3 +185,31 @@ void xenstore_process_event(void *opaque) free(image); free(vec); } + +void xenstore_write_vncport(int display) +{ + char *buf = NULL, *path; + char *portstr = NULL; + + if (xsh == NULL) + return; + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(logfile, "xs_get_domain_path() error\n"); + goto out; + } + + if (pasprintf(&buf, "%s/console/vnc-port", path) == -1) + goto out; + + if (pasprintf(&portstr, "%d", 5900 + display) == -1) + goto out; + + if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0) + fprintf(logfile, "xs_write() vncport failed\n"); + + out: + free(portstr); + free(buf); +} From fff236de340a7c3ade7dfbabaf5a36669721850c Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Thu, 3 Aug 2006 19:19:27 +0100 Subject: [PATCH 075/111] [qemu patches] Update patches for changeset 10923:155385a02d. Signed-off-by: Christian Limpach --- tools/ioemu/patches/series | 1 + tools/ioemu/patches/xenstore-write-vnc-port | 60 +++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tools/ioemu/patches/xenstore-write-vnc-port diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index 8f20f6e166..6a32aa2256 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -36,3 +36,4 @@ vnc-start-vncviewer vnc-title-domain-name vnc-access-monitor-vt xenstore-block-device-config +xenstore-write-vnc-port diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port new file mode 100644 index 0000000000..1d49ef51d8 --- /dev/null +++ b/tools/ioemu/patches/xenstore-write-vnc-port @@ -0,0 +1,60 @@ +Index: ioemu/xenstore.c +=================================================================== +--- ioemu.orig/xenstore.c 2006-08-03 19:17:18.496119877 +0100 ++++ ioemu/xenstore.c 2006-08-03 19:18:29.428258503 +0100 +@@ -185,3 +185,31 @@ + free(image); + free(vec); + } ++ ++void xenstore_write_vncport(int display) ++{ ++ char *buf = NULL, *path; ++ char *portstr = NULL; ++ ++ if (xsh == NULL) ++ return; ++ ++ path = xs_get_domain_path(xsh, domid); ++ if (path == NULL) { ++ fprintf(logfile, "xs_get_domain_path() error\n"); ++ goto out; ++ } ++ ++ if (pasprintf(&buf, "%s/console/vnc-port", path) == -1) ++ goto out; ++ ++ if (pasprintf(&portstr, "%d", 5900 + display) == -1) ++ goto out; ++ ++ if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0) ++ fprintf(logfile, "xs_write() vncport failed\n"); ++ ++ out: ++ free(portstr); ++ free(buf); ++} +Index: ioemu/vl.c +=================================================================== +--- ioemu.orig/vl.c 2006-08-03 19:17:18.499119544 +0100 ++++ ioemu/vl.c 2006-08-03 19:18:29.427258614 +0100 +@@ -5954,6 +5954,7 @@ + vnc_display_init(ds, vnc_display); + if (vncviewer) + vnc_start_viewer(vnc_display); ++ xenstore_write_vncport(vnc_display); + } else { + #if defined(CONFIG_SDL) + sdl_display_init(ds, full_screen); +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-08-03 19:17:18.501119323 +0100 ++++ ioemu/vl.h 2006-08-03 19:18:29.428258503 +0100 +@@ -1111,6 +1111,7 @@ + int xenstore_fd(void); + void xenstore_process_event(void *opaque); + void xenstore_check_new_media_present(int timeout); ++void xenstore_write_vncport(int vnc_display); + + + void kqemu_record_dump(void); From c421252d5a1862227b2360cfe4185918105fe0ce Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Thu, 3 Aug 2006 19:45:14 +0100 Subject: [PATCH 076/111] [blktap] Add dependencies to Makefiles and simplify to avoid needless rebuilds. Signed-off-by: Christian Limpach --- tools/blktap/drivers/Makefile | 15 ++++++--------- tools/blktap/lib/Makefile | 14 +++++++++----- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/tools/blktap/drivers/Makefile b/tools/blktap/drivers/Makefile index 6601a4d005..a2bdd02259 100644 --- a/tools/blktap/drivers/Makefile +++ b/tools/blktap/drivers/Makefile @@ -49,21 +49,18 @@ all: $(IBIN) qcow-util LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse) -blktapctrl: +blktapctrl: blktapctrl.c $(CC) $(CFLAGS) -o blktapctrl $(LIBS) blktapctrl.c -tapdisk: $(BLK-OBJS) +tapdisk: $(BLK-OBJS) tapdisk.c $(CC) $(CFLAGS) -o tapdisk $(BLK-OBJS) tapdisk.c \ $(AIOLIBS) $(LIBS) +.PHONY: qcow-util +qcow-util: img2qcow qcow2raw qcow-create -qcow-util: $(BLK-OBJS) - $(CC) $(CFLAGS) -o img2qcow $(BLK-OBJS) img2qcow.c \ - $(AIOLIBS) $(LIBS) - $(CC) $(CFLAGS) -o qcow2raw $(BLK-OBJS) qcow2raw.c \ - $(AIOLIBS) $(LIBS) - $(CC) $(CFLAGS) -o qcow-create $(BLK-OBJS) qcow-create.c \ - $(AIOLIBS) $(LIBS) +img2qcow qcow2raw qcow-create: %: $(BLK-OBJS) + $(CC) $(CFLAGS) -o $* $(BLK-OBJS) $*.c $(AIOLIBS) $(LIBS) install: all $(INSTALL_PROG) $(IBIN) $(QCOW_UTIL) $(DESTDIR)$(INSTALL_DIR) diff --git a/tools/blktap/lib/Makefile b/tools/blktap/lib/Makefile index 2d5b98e41a..9417b976ac 100644 --- a/tools/blktap/lib/Makefile +++ b/tools/blktap/lib/Makefile @@ -35,10 +35,14 @@ IBINS := LIB = libblktap.a libblktap.so.$(MAJOR).$(MINOR) +.PHONY: all all: build -build: - $(MAKE) libblktap +.PHONY: build +build: libblktap.a + +.PHONY: libblktap +libblktap: libblktap.a install: all $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) @@ -51,13 +55,13 @@ install: all clean: rm -rf *.a *.so* *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS -libblktap: $(OBJS) +libblktap.a: $(OBJS) $(CC) $(CFLAGS) -Wl,-soname -Wl,$(SONAME) -shared \ -L$(XEN_XENSTORE) -l xenstore \ -o libblktap.so.$(MAJOR).$(MINOR) $^ $(LIBS) ln -sf libblktap.so.$(MAJOR).$(MINOR) libblktap.so.$(MAJOR) - ln -sf libblktap.so.$(MAJOR) $@.so - ar rc libblktap.a $@.so + ln -sf libblktap.so.$(MAJOR) libblktap.so + ar rc $@ libblktap.so .PHONY: TAGS all build clean install libblktap From 256050aba517bd5d4fed4671602f718ae24139d4 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 09:27:52 +0100 Subject: [PATCH 077/111] [qemu] Always allow --disable-sdl since there's always vnc support. Signed-off-by: Christian Limpach --- tools/ioemu/configure | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/ioemu/configure b/tools/ioemu/configure index 24b829826b..9b7c8050fa 100644 --- a/tools/ioemu/configure +++ b/tools/ioemu/configure @@ -226,8 +226,6 @@ for opt do ;; --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" ;; - --disable-gfx-check) check_gfx="no" - ;; --disable-gcc-check) check_gcc="no" ;; --disable-system) softmmu="no" @@ -736,14 +734,6 @@ if expr $target : '.*-user' > /dev/null ; then target_user_only="yes" fi -if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ - -a "$sdl" = "no" -a "$cocoa" = "no" ; then - echo "ERROR: QEMU requires SDL or Cocoa for graphical output" - echo "To build QEMU without graphical output configure with --disable-gfx-check" - echo "Note that this will disable all output from the virtual graphics card." - exit 1; -fi - #echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir From 73bf5288a05b8bc396fc31ea1d8b7d4554d1ba97 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 09:28:34 +0100 Subject: [PATCH 078/111] [qemu patches] Update patches for changeset 10926:e47aad0605a3. Signed-off-by: Christian Limpach --- tools/ioemu/patches/qemu-allow-disable-sdl | 28 ++++++++++++++++++++++ tools/ioemu/patches/series | 1 + 2 files changed, 29 insertions(+) create mode 100644 tools/ioemu/patches/qemu-allow-disable-sdl diff --git a/tools/ioemu/patches/qemu-allow-disable-sdl b/tools/ioemu/patches/qemu-allow-disable-sdl new file mode 100644 index 0000000000..caa7105187 --- /dev/null +++ b/tools/ioemu/patches/qemu-allow-disable-sdl @@ -0,0 +1,28 @@ +Index: ioemu/configure +=================================================================== +--- ioemu.orig/configure 2006-08-03 19:19:38.000000000 +0100 ++++ ioemu/configure 2006-08-03 23:38:19.000000000 +0100 +@@ -226,8 +226,6 @@ + ;; + --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" + ;; +- --disable-gfx-check) check_gfx="no" +- ;; + --disable-gcc-check) check_gcc="no" + ;; + --disable-system) softmmu="no" +@@ -736,14 +734,6 @@ + target_user_only="yes" + fi + +-if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ +- -a "$sdl" = "no" -a "$cocoa" = "no" ; then +- echo "ERROR: QEMU requires SDL or Cocoa for graphical output" +- echo "To build QEMU without graphical output configure with --disable-gfx-check" +- echo "Note that this will disable all output from the virtual graphics card." +- exit 1; +-fi +- + #echo "Creating $config_mak, $config_h and $target_dir/Makefile" + + mkdir -p $target_dir diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index 6a32aa2256..4e4b48c508 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -37,3 +37,4 @@ vnc-title-domain-name vnc-access-monitor-vt xenstore-block-device-config xenstore-write-vnc-port +qemu-allow-disable-sdl From a3188a47d8990dc924b330ffab2afe0cfcdf6018 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 09:31:06 +0100 Subject: [PATCH 079/111] [HVM] Wnable sound card support for qemu. Need a sound card to pass some benchmark check. Signed-off-by: Edwin Zhai --- tools/examples/xmexample.hvm | 4 ++-- tools/python/xen/xend/image.py | 5 ++--- tools/python/xen/xm/create.py | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tools/examples/xmexample.hvm b/tools/examples/xmexample.hvm index b303adfead..3d7f85263f 100644 --- a/tools/examples/xmexample.hvm +++ b/tools/examples/xmexample.hvm @@ -149,8 +149,8 @@ serial='pty' #----------------------------------------------------------------------------- -# enable audio support -#audio=1 +# enable sound card support, [sb16|es1370|all|..,..], default none +#soundhw='sb16' #----------------------------------------------------------------------------- diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index d74668ab27..f3fa7d11c6 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -249,7 +249,7 @@ class HVMImageHandler(ImageHandler): # Return a list of cmd line args to the device models based on the # xm config file def parseDeviceModelArgs(self, imageConfig, deviceConfig): - dmargs = [ 'boot', 'fda', 'fdb', 'audio', + dmargs = [ 'boot', 'fda', 'fdb', 'soundhw', 'localtime', 'serial', 'stdvga', 'isa', 'vcpus', 'usb', 'usbdevice'] ret = [] @@ -258,10 +258,9 @@ class HVMImageHandler(ImageHandler): # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' - if a == 'audio': a = 'enable-audio' # Handle booleans gracefully - if a in ['localtime', 'std-vga', 'isa', 'enable-audio', 'usb']: + if a in ['localtime', 'std-vga', 'isa', 'usb']: if v != None: v = int(v) if v: ret.append("-%s" % a) else: diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 109e8a8741..c19c7ff515 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -400,9 +400,9 @@ gopts.var('nographic', val='no|yes', fn=set_bool, default=0, use="Should device models use graphics?") -gopts.var('audio', val='no|yes', - fn=set_bool, default=0, - use="Should device models enable audio?") +gopts.var('soundhw', val='audiodev', + fn=set_value, default='', + use="Should device models enable audio device?") gopts.var('vnc', val='', fn=set_value, default=None, @@ -626,7 +626,7 @@ def configure_hvm(config_image, vals): """Create the config for HVM devices. """ args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', - 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'audio', + 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw', 'vnc', 'vncdisplay', 'vncconsole', 'sdl', 'display', 'acpi', 'apic', 'xauthority', 'usb', 'usbdevice' ] for a in args: From ccdaf36c893450ff18501eab08d63699083a4b2b Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:19:53 +0100 Subject: [PATCH 080/111] [qemu] Fix memset arguments in qemu audio code. The arguments for the calls to memset are reversed in audio.c. Signed-off-by: Charles Coffing --- tools/ioemu/audio/audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/audio/audio.c b/tools/ioemu/audio/audio.c index 7634535230..811b207c55 100644 --- a/tools/ioemu/audio/audio.c +++ b/tools/ioemu/audio/audio.c @@ -597,11 +597,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) } if (info->sign) { - memset (buf, len << info->shift, 0x00); + memset (buf, 0x00, len << info->shift); } else { if (info->bits == 8) { - memset (buf, len << info->shift, 0x80); + memset (buf, 0x80, len << info->shift); } else { int i; From e71d659c42d2b287eef75426ac81be0efc09986e Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:20:33 +0100 Subject: [PATCH 081/111] [qemu patches] Update patches for changeset 10929:4dd640c6ce57. Signed-off-by: Christian Limpach --- tools/ioemu/patches/qemu-fix-memset-args | 18 ++++++++++++++++++ tools/ioemu/patches/series | 1 + 2 files changed, 19 insertions(+) create mode 100644 tools/ioemu/patches/qemu-fix-memset-args diff --git a/tools/ioemu/patches/qemu-fix-memset-args b/tools/ioemu/patches/qemu-fix-memset-args new file mode 100644 index 0000000000..6fa83c22e5 --- /dev/null +++ b/tools/ioemu/patches/qemu-fix-memset-args @@ -0,0 +1,18 @@ +Index: ioemu/audio/audio.c +=================================================================== +--- ioemu.orig/audio/audio.c 2006-07-14 13:43:45.000000000 +0100 ++++ ioemu/audio/audio.c 2006-08-04 10:18:17.243240246 +0100 +@@ -597,11 +597,11 @@ + } + + if (info->sign) { +- memset (buf, len << info->shift, 0x00); ++ memset (buf, 0x00, len << info->shift); + } + else { + if (info->bits == 8) { +- memset (buf, len << info->shift, 0x80); ++ memset (buf, 0x80, len << info->shift); + } + else { + int i; diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index 4e4b48c508..ce2cf0b70a 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -38,3 +38,4 @@ vnc-access-monitor-vt xenstore-block-device-config xenstore-write-vnc-port qemu-allow-disable-sdl +qemu-fix-memset-args From 0a30ab00718eb664002924699d31a02ce1f27370 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:28:51 +0100 Subject: [PATCH 082/111] [qemu] Make sure disk writes really made it to disk before we report I/O completion to the guest domain. The DMA_MULTI_THREAD functionality from the qemu-dm IDE emulation should make the performance overhead of synchronous writes bearable, or at least comparable to native hardware. Signed-off-by: Rik van Riel --- tools/ioemu/block-bochs.c | 2 +- tools/ioemu/block-cloop.c | 2 +- tools/ioemu/block-cow.c | 2 +- tools/ioemu/block-qcow.c | 2 +- tools/ioemu/block-vmdk.c | 2 +- tools/ioemu/block.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/ioemu/block-bochs.c b/tools/ioemu/block-bochs.c index 62317aff38..d82c239281 100644 --- a/tools/ioemu/block-bochs.c +++ b/tools/ioemu/block-bochs.c @@ -91,7 +91,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename) int fd, i; struct bochs_header bochs; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); if (fd < 0) { fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) diff --git a/tools/ioemu/block-cloop.c b/tools/ioemu/block-cloop.c index c617e1b64b..0f56685664 100644 --- a/tools/ioemu/block-cloop.c +++ b/tools/ioemu/block-cloop.c @@ -55,7 +55,7 @@ static int cloop_open(BlockDriverState *bs, const char *filename) BDRVCloopState *s = bs->opaque; uint32_t offsets_size,max_compressed_block_size=1,i; - s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE | O_SYNC); if (s->fd < 0) return -1; bs->read_only = 1; diff --git a/tools/ioemu/block-cow.c b/tools/ioemu/block-cow.c index eeeab7068b..6a42a46ef4 100644 --- a/tools/ioemu/block-cow.c +++ b/tools/ioemu/block-cow.c @@ -69,7 +69,7 @@ static int cow_open(BlockDriverState *bs, const char *filename) struct cow_header_v2 cow_header; int64_t size; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); if (fd < 0) { fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) diff --git a/tools/ioemu/block-qcow.c b/tools/ioemu/block-qcow.c index 34026a4f2c..b28fe58d72 100644 --- a/tools/ioemu/block-qcow.c +++ b/tools/ioemu/block-qcow.c @@ -95,7 +95,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename) int fd, len, i, shift; QCowHeader header; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); if (fd < 0) { fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) diff --git a/tools/ioemu/block-vmdk.c b/tools/ioemu/block-vmdk.c index fc87be353b..03bbb7a765 100644 --- a/tools/ioemu/block-vmdk.c +++ b/tools/ioemu/block-vmdk.c @@ -96,7 +96,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) uint32_t magic; int l1_size; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); if (fd < 0) { fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) diff --git a/tools/ioemu/block.c b/tools/ioemu/block.c index 9c628f93bf..330d5c146d 100644 --- a/tools/ioemu/block.c +++ b/tools/ioemu/block.c @@ -677,7 +677,7 @@ static int raw_open(BlockDriverState *bs, const char *filename) int rv; #endif - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); if (fd < 0) { fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) From 63c4050403ea14c28df6c8c4b3ce330a97d9036a Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:29:18 +0100 Subject: [PATCH 083/111] [qemu patches] Update patches for changeset 10931:3ea0a6847198. Signed-off-by: Christian Limpach --- .../qemu-fix-write-to-disk-synchronous | 78 +++++++++++++++++++ tools/ioemu/patches/series | 1 + 2 files changed, 79 insertions(+) create mode 100644 tools/ioemu/patches/qemu-fix-write-to-disk-synchronous diff --git a/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous b/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous new file mode 100644 index 0000000000..65bd03490c --- /dev/null +++ b/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous @@ -0,0 +1,78 @@ +Index: ioemu/block-vmdk.c +=================================================================== +--- ioemu.orig/block-vmdk.c 2006-07-14 13:43:45.000000000 +0100 ++++ ioemu/block-vmdk.c 2006-08-04 10:27:15.368803650 +0100 +@@ -96,7 +96,7 @@ + uint32_t magic; + int l1_size; + +- fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); ++ fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) +Index: ioemu/block-qcow.c +=================================================================== +--- ioemu.orig/block-qcow.c 2006-07-14 13:43:45.000000000 +0100 ++++ ioemu/block-qcow.c 2006-08-04 10:27:15.367803766 +0100 +@@ -95,7 +95,7 @@ + int fd, len, i, shift; + QCowHeader header; + +- fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); ++ fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) +Index: ioemu/block-bochs.c +=================================================================== +--- ioemu.orig/block-bochs.c 2006-07-14 13:43:45.000000000 +0100 ++++ ioemu/block-bochs.c 2006-08-04 10:27:15.345806311 +0100 +@@ -91,7 +91,7 @@ + int fd, i; + struct bochs_header bochs; + +- fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); ++ fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) +Index: ioemu/block.c +=================================================================== +--- ioemu.orig/block.c 2006-08-03 19:19:39.000000000 +0100 ++++ ioemu/block.c 2006-08-04 10:27:15.357804923 +0100 +@@ -677,7 +677,7 @@ + int rv; + #endif + +- fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); ++ fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) +Index: ioemu/block-cow.c +=================================================================== +--- ioemu.orig/block-cow.c 2006-07-14 13:43:45.000000000 +0100 ++++ ioemu/block-cow.c 2006-08-04 10:27:15.366803882 +0100 +@@ -69,7 +69,7 @@ + struct cow_header_v2 cow_header; + int64_t size; + +- fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); ++ fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE | O_SYNC); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) +Index: ioemu/block-cloop.c +=================================================================== +--- ioemu.orig/block-cloop.c 2006-07-14 13:43:45.000000000 +0100 ++++ ioemu/block-cloop.c 2006-08-04 10:27:15.365803997 +0100 +@@ -55,7 +55,7 @@ + BDRVCloopState *s = bs->opaque; + uint32_t offsets_size,max_compressed_block_size=1,i; + +- s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); ++ s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE | O_SYNC); + if (s->fd < 0) + return -1; + bs->read_only = 1; diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index ce2cf0b70a..eecf8819c3 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -39,3 +39,4 @@ xenstore-block-device-config xenstore-write-vnc-port qemu-allow-disable-sdl qemu-fix-memset-args +qemu-fix-write-to-disk-synchronous From 621578a369421fdf29e4f4ffc7ff5d71485eee6a Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:41:27 +0100 Subject: [PATCH 084/111] [qemu] Add switch to control whether acpi bridge is enabled. Signed-off-by: Winston Wang --- tools/ioemu/hw/pc.c | 2 +- tools/ioemu/vl.c | 8 ++++++++ tools/ioemu/vl.h | 1 + tools/python/xen/sv/CreateDomain.py | 1 + tools/python/xen/xend/image.py | 2 +- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/hw/pc.c b/tools/ioemu/hw/pc.c index 3a7b021e0c..d4e4b1b9ca 100644 --- a/tools/ioemu/hw/pc.c +++ b/tools/ioemu/hw/pc.c @@ -871,7 +871,7 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, cmos_init(ram_size, boot_device, bs_table, timeoffset); /* using PIIX4 acpi model */ - if (pci_enabled) + if (pci_enabled && acpi_enabled) pci_piix4_acpi_init(pci_bus); if (pci_enabled && usb_enabled) { diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 34ae60df0b..b3ccf6b04a 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -167,6 +167,8 @@ int xc_handle; time_t timeoffset = 0; +int acpi_enabled = 0; + char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; extern int domid; @@ -4807,6 +4809,7 @@ void help(void) "-vnc display start a VNC server on display\n" "-vncviewer start a vncviewer process for this domain\n" "-timeoffset time offset (in seconds) from local time\n" + "-acpi disable or enable ACPI of HVM domain \n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -4901,6 +4904,7 @@ enum { QEMU_OPTION_d, QEMU_OPTION_vcpus, QEMU_OPTION_timeoffset, + QEMU_OPTION_acpi, }; typedef struct QEMUOption { @@ -4983,6 +4987,7 @@ const QEMUOption qemu_options[] = { { "d", HAS_ARG, QEMU_OPTION_d }, { "vcpus", 1, QEMU_OPTION_vcpus }, { "timeoffset", HAS_ARG, QEMU_OPTION_timeoffset }, + { "acpi", 0, QEMU_OPTION_acpi }, { NULL }, }; @@ -5710,6 +5715,9 @@ int main(int argc, char **argv) case QEMU_OPTION_timeoffset: timeoffset = strtol(optarg, NULL, 0); break; + case QEMU_OPTION_acpi: + acpi_enabled = 1; + break; } } } diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 517209fb79..5eca554463 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -159,6 +159,7 @@ extern const char *keyboard_layout; extern int kqemu_allowed; extern int win2k_install_hack; extern int usb_enabled; +extern int acpi_enabled; extern int smp_cpus; /* XXX: make it dynamic */ diff --git a/tools/python/xen/sv/CreateDomain.py b/tools/python/xen/sv/CreateDomain.py index 77a3483a44..ee5e62eb4a 100755 --- a/tools/python/xen/sv/CreateDomain.py +++ b/tools/python/xen/sv/CreateDomain.py @@ -180,6 +180,7 @@ class CreateFinish( Sheet ): vals.ssidref = -1 vals.bootloader = None vals.usb = [] + vals.acpi = [] #setup vifs diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index f3fa7d11c6..1adfa98ccc 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -251,7 +251,7 @@ class HVMImageHandler(ImageHandler): def parseDeviceModelArgs(self, imageConfig, deviceConfig): dmargs = [ 'boot', 'fda', 'fdb', 'soundhw', 'localtime', 'serial', 'stdvga', 'isa', 'vcpus', - 'usb', 'usbdevice'] + 'acpi', 'usb', 'usbdevice'] ret = [] for a in dmargs: v = sxp.child_value(imageConfig, a) From 24bb37df7fc8be2e53eed19b193b6fe6615557ca Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:42:02 +0100 Subject: [PATCH 085/111] [qemu patches] Update patches for changeset 10933:386990d004b8. Signed-off-by: Christian Limpach --- tools/ioemu/patches/acpi-support | 101 +++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/tools/ioemu/patches/acpi-support b/tools/ioemu/patches/acpi-support index bb48015ad5..c0b422bf5d 100644 --- a/tools/ioemu/patches/acpi-support +++ b/tools/ioemu/patches/acpi-support @@ -1,7 +1,8 @@ -diff -r 2612be97caad Makefile.target ---- a/Makefile.target Mon Jun 26 16:07:22 2006 +0100 -+++ b/Makefile.target Mon Jun 26 18:38:49 2006 +0100 -@@ -335,6 +335,7 @@ VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SO +Index: ioemu/Makefile.target +=================================================================== +--- ioemu.orig/Makefile.target 2006-08-03 19:19:39.000000000 +0100 ++++ ioemu/Makefile.target 2006-08-04 10:35:36.445703379 +0100 +@@ -335,6 +335,7 @@ VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o @@ -9,10 +10,11 @@ diff -r 2612be97caad Makefile.target DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) -diff -r 2612be97caad hw/pc.c ---- a/hw/pc.c Mon Jun 26 16:07:22 2006 +0100 -+++ b/hw/pc.c Mon Jun 26 18:38:49 2006 +0100 -@@ -566,6 +566,9 @@ static int parallel_io[MAX_PARALLEL_PORT +Index: ioemu/hw/pc.c +=================================================================== +--- ioemu.orig/hw/pc.c 2006-08-03 19:19:39.000000000 +0100 ++++ ioemu/hw/pc.c 2006-08-04 10:38:05.559415853 +0100 +@@ -566,6 +566,9 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; @@ -22,21 +24,22 @@ diff -r 2612be97caad hw/pc.c #ifdef HAS_AUDIO static void audio_init (PCIBus *pci_bus) { -@@ -867,6 +870,10 @@ static void pc_init1(uint64_t ram_size, +@@ -867,6 +870,10 @@ cmos_init(ram_size, boot_device, bs_table, timeoffset); + /* using PIIX4 acpi model */ -+ if (pci_enabled) ++ if (pci_enabled && acpi_enabled) + pci_piix4_acpi_init(pci_bus); + if (pci_enabled && usb_enabled) { usb_uhci_init(pci_bus, usb_root_ports); usb_attach(usb_root_ports[0], vm_usb_hub); -diff -r 2612be97caad hw/pci.c ---- a/hw/pci.c Mon Jun 26 16:07:22 2006 +0100 -+++ b/hw/pci.c Mon Jun 26 18:38:49 2006 +0100 -@@ -1697,7 +1697,7 @@ static uint32_t pci_bios_io_addr; +Index: ioemu/hw/pci.c +=================================================================== +--- ioemu.orig/hw/pci.c 2006-08-03 19:19:35.000000000 +0100 ++++ ioemu/hw/pci.c 2006-08-03 19:19:39.000000000 +0100 +@@ -1697,7 +1697,7 @@ static uint32_t pci_bios_io_addr; static uint32_t pci_bios_mem_addr; /* host irqs corresponding to PCI irqs A-D */ @@ -45,7 +48,7 @@ diff -r 2612be97caad hw/pci.c static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) { -@@ -1750,12 +1750,22 @@ static void pci_bios_init_device(PCIDevi +@@ -1750,12 +1750,22 @@ pci_set_io_region_addr(d, 3, 0x374); } break; @@ -68,7 +71,7 @@ diff -r 2612be97caad hw/pci.c case 0x0800: /* PIC */ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); -@@ -1800,6 +1810,13 @@ static void pci_bios_init_device(PCIDevi +@@ -1800,6 +1810,13 @@ pic_irq = pci_irqs[pin]; pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); } @@ -82,9 +85,10 @@ diff -r 2612be97caad hw/pci.c } /* -diff -r 2612be97caad hw/piix4acpi.c ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/hw/piix4acpi.c Mon Jun 26 18:38:49 2006 +0100 +Index: ioemu/hw/piix4acpi.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/hw/piix4acpi.c 2006-08-04 10:35:36.762666604 +0100 @@ -0,0 +1,388 @@ +/* + * PIIX4 ACPI controller emulation @@ -474,3 +478,62 @@ diff -r 2612be97caad hw/piix4acpi.c + + acpi_reset (d); +} +Index: ioemu/vl.c +=================================================================== +--- ioemu.orig/vl.c 2006-08-04 10:35:36.697674145 +0100 ++++ ioemu/vl.c 2006-08-04 10:37:38.001608828 +0100 +@@ -166,6 +166,8 @@ + + time_t timeoffset = 0; + ++int acpi_enabled = 0; ++ + char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; + extern int domid; + +@@ -4803,6 +4805,7 @@ + "-loadvm file start right away with a saved state (loadvm in monitor)\n" + "-vnc display start a VNC server on display\n" + "-timeoffset time offset (in seconds) from local time\n" ++ "-acpi disable or enable ACPI of HVM domain \n" + "\n" + "During emulation, the following keys are useful:\n" + "ctrl-alt-f toggle full screen\n" +@@ -4894,6 +4897,7 @@ + QEMU_OPTION_d, + QEMU_OPTION_vcpus, + QEMU_OPTION_timeoffset, ++ QEMU_OPTION_acpi, + }; + + typedef struct QEMUOption { +@@ -4973,6 +4977,7 @@ + { "d", HAS_ARG, QEMU_OPTION_d }, + { "vcpus", 1, QEMU_OPTION_vcpus }, + { "timeoffset", HAS_ARG, QEMU_OPTION_timeoffset }, ++ { "acpi", 0, QEMU_OPTION_acpi }, + { NULL }, + }; + +@@ -5678,6 +5683,9 @@ + case QEMU_OPTION_timeoffset: + timeoffset = strtol(optarg, NULL, 0); + break; ++ case QEMU_OPTION_acpi: ++ acpi_enabled = 1; ++ break; + } + } + } +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-08-04 10:35:36.629682033 +0100 ++++ ioemu/vl.h 2006-08-04 10:36:21.513475699 +0100 +@@ -159,6 +159,7 @@ + extern int kqemu_allowed; + extern int win2k_install_hack; + extern int usb_enabled; ++extern int acpi_enabled; + extern int smp_cpus; + + /* XXX: make it dynamic */ From 6297f1d9d38bb795c8d940c608bbb318e0c2cb7f Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:43:02 +0100 Subject: [PATCH 086/111] [qemu patches] Refresh patches. Signed-off-by: Christian Limpach --- tools/ioemu/patches/domain-timeoffset | 16 ++--- tools/ioemu/patches/vnc-cleanup | 10 ++-- tools/ioemu/patches/vnc-fixes | 16 ++--- tools/ioemu/patches/vnc-start-vncviewer | 28 ++++----- .../patches/xenstore-block-device-config | 60 +++++++++---------- tools/ioemu/patches/xenstore-write-vnc-port | 16 ++--- 6 files changed, 73 insertions(+), 73 deletions(-) diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset index dbc4e4e2c7..72b5b6165a 100644 --- a/tools/ioemu/patches/domain-timeoffset +++ b/tools/ioemu/patches/domain-timeoffset @@ -1,7 +1,7 @@ Index: ioemu/hw/mc146818rtc.c =================================================================== ---- ioemu.orig/hw/mc146818rtc.c 2006-07-27 11:17:18.007225084 +0100 -+++ ioemu/hw/mc146818rtc.c 2006-07-27 11:17:48.250876949 +0100 +--- ioemu.orig/hw/mc146818rtc.c 2006-08-04 10:42:19.796998954 +0100 ++++ ioemu/hw/mc146818rtc.c 2006-08-04 10:42:26.456229392 +0100 @@ -178,10 +178,27 @@ } } @@ -46,8 +46,8 @@ Index: ioemu/hw/mc146818rtc.c static void rtc_copy_date(RTCState *s) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-27 11:17:47.993905398 +0100 -+++ ioemu/hw/pc.c 2006-07-27 11:17:48.251876839 +0100 +--- ioemu.orig/hw/pc.c 2006-08-04 10:42:26.185260705 +0100 ++++ ioemu/hw/pc.c 2006-08-04 10:42:26.457229276 +0100 @@ -151,7 +151,7 @@ } @@ -117,8 +117,8 @@ Index: ioemu/hw/pc.c QEMUMachine pc_machine = { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:17:48.126890676 +0100 -+++ ioemu/vl.c 2006-07-27 11:17:48.254876507 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:42:26.324244644 +0100 ++++ ioemu/vl.c 2006-08-04 10:42:26.459229045 +0100 @@ -164,6 +164,8 @@ int xc_handle; @@ -174,8 +174,8 @@ Index: ioemu/vl.c qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-27 11:17:47.998904845 +0100 -+++ ioemu/vl.h 2006-07-27 11:17:48.254876507 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:42:26.190260127 +0100 ++++ ioemu/vl.h 2006-08-04 10:42:26.460228930 +0100 @@ -556,7 +556,7 @@ int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/tools/ioemu/patches/vnc-cleanup b/tools/ioemu/patches/vnc-cleanup index b806dadc91..7041e1670c 100644 --- a/tools/ioemu/patches/vnc-cleanup +++ b/tools/ioemu/patches/vnc-cleanup @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-07-27 11:16:52.783017443 +0100 -+++ ioemu/vnc.c 2006-07-27 11:17:00.722138579 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:42:19.575024607 +0100 ++++ ioemu/vnc.c 2006-08-04 10:42:26.918176009 +0100 @@ -83,13 +83,16 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) { @@ -65,9 +65,9 @@ Index: ioemu/vnc.c static void vnc_timer_init(VncState *vs) Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:17:00.311184072 +0100 -+++ ioemu/vl.c 2006-07-27 11:17:00.724138358 +0100 -@@ -4587,10 +4587,10 @@ +--- ioemu.orig/vl.c 2006-08-04 10:42:26.723198541 +0100 ++++ ioemu/vl.c 2006-08-04 10:42:26.921175663 +0100 +@@ -4589,10 +4589,10 @@ /* XXX: better handling of removal */ for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { ioh_next = ioh->next; diff --git a/tools/ioemu/patches/vnc-fixes b/tools/ioemu/patches/vnc-fixes index 99c538f60d..36f04f4bab 100644 --- a/tools/ioemu/patches/vnc-fixes +++ b/tools/ioemu/patches/vnc-fixes @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:17:00.724138358 +0100 -+++ ioemu/vl.c 2006-07-27 11:17:00.874121755 +0100 -@@ -6004,8 +6004,10 @@ +--- ioemu.orig/vl.c 2006-08-04 10:42:26.921175663 +0100 ++++ ioemu/vl.c 2006-08-04 10:42:27.107154171 +0100 +@@ -6012,8 +6012,10 @@ kernel_filename, kernel_cmdline, initrd_filename, timeoffset); @@ -17,8 +17,8 @@ Index: ioemu/vl.c if (use_gdbstub) { Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-07-27 11:17:00.722138579 +0100 -+++ ioemu/vnc.c 2006-07-27 11:17:00.875121644 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:42:26.918176009 +0100 ++++ ioemu/vnc.c 2006-08-04 10:42:27.108154056 +0100 @@ -3,6 +3,7 @@ * * Copyright (C) 2006 Anthony Liguori @@ -493,9 +493,9 @@ Index: ioemu/vnc.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-27 11:17:00.311184072 +0100 -+++ ioemu/vl.h 2006-07-27 11:17:00.875121644 +0100 -@@ -301,6 +301,7 @@ +--- ioemu.orig/vl.h 2006-08-04 10:42:26.724198425 +0100 ++++ ioemu/vl.h 2006-08-04 10:42:27.108154056 +0100 +@@ -302,6 +302,7 @@ int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds); void console_select(unsigned int index); diff --git a/tools/ioemu/patches/vnc-start-vncviewer b/tools/ioemu/patches/vnc-start-vncviewer index 110bdd1e89..31caaae19e 100644 --- a/tools/ioemu/patches/vnc-start-vncviewer +++ b/tools/ioemu/patches/vnc-start-vncviewer @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-07-27 11:17:00.875121644 +0100 -+++ ioemu/vnc.c 2006-07-27 11:17:01.032104266 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:42:27.108154056 +0100 ++++ ioemu/vnc.c 2006-08-04 10:42:27.272135106 +0100 @@ -1002,3 +1002,25 @@ vnc_dpy_resize(vs->ds, 640, 400); @@ -30,8 +30,8 @@ Index: ioemu/vnc.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:17:00.874121755 +0100 -+++ ioemu/vl.c 2006-07-27 11:17:01.035103934 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:42:27.107154171 +0100 ++++ ioemu/vl.c 2006-08-04 10:42:27.276134644 +0100 @@ -121,6 +121,7 @@ int bios_size; static DisplayState display_state; @@ -40,15 +40,15 @@ Index: ioemu/vl.c const char* keyboard_layout = NULL; int64_t ticks_per_sec; int boot_device = 'c'; -@@ -4802,6 +4803,7 @@ +@@ -4804,6 +4805,7 @@ #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" + "-vncviewer start a vncviewer process for this domain\n" "-timeoffset time offset (in seconds) from local time\n" + "-acpi disable or enable ACPI of HVM domain \n" "\n" - "During emulation, the following keys are useful:\n" -@@ -4890,6 +4892,7 @@ +@@ -4893,6 +4895,7 @@ QEMU_OPTION_usbdevice, QEMU_OPTION_smp, QEMU_OPTION_vnc, @@ -56,7 +56,7 @@ Index: ioemu/vl.c QEMU_OPTION_d, QEMU_OPTION_vcpus, -@@ -4965,6 +4968,7 @@ +@@ -4969,6 +4972,7 @@ { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, @@ -64,7 +64,7 @@ Index: ioemu/vl.c /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, -@@ -5295,6 +5299,7 @@ +@@ -5300,6 +5304,7 @@ #endif snapshot = 0; nographic = 0; @@ -72,7 +72,7 @@ Index: ioemu/vl.c kernel_filename = NULL; kernel_cmdline = ""; #ifdef TARGET_PPC -@@ -5664,6 +5669,9 @@ +@@ -5669,6 +5674,9 @@ exit(1); } break; @@ -82,7 +82,7 @@ Index: ioemu/vl.c case QEMU_OPTION_domainname: strncat(domain_name, optarg, sizeof(domain_name) - 20); break; -@@ -5911,6 +5919,8 @@ +@@ -5919,6 +5927,8 @@ dumb_display_init(ds); } else if (vnc_display != -1) { vnc_display_init(ds, vnc_display); @@ -93,9 +93,9 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-27 11:17:00.875121644 +0100 -+++ ioemu/vl.h 2006-07-27 11:17:01.036103823 +0100 -@@ -733,6 +733,7 @@ +--- ioemu.orig/vl.h 2006-08-04 10:42:27.108154056 +0100 ++++ ioemu/vl.h 2006-08-04 10:42:27.277134528 +0100 +@@ -734,6 +734,7 @@ /* vnc.c */ void vnc_display_init(DisplayState *ds, int display); diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config index c2b03bf3d5..40a7418959 100644 --- a/tools/ioemu/patches/xenstore-block-device-config +++ b/tools/ioemu/patches/xenstore-block-device-config @@ -1,7 +1,7 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-03 17:57:38.861210420 +0100 -+++ ioemu/Makefile.target 2006-08-03 17:58:02.317549891 +0100 +--- ioemu.orig/Makefile.target 2006-08-04 10:42:26.718199119 +0100 ++++ ioemu/Makefile.target 2006-08-04 10:42:27.563101483 +0100 @@ -336,6 +336,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o @@ -13,7 +13,7 @@ Index: ioemu/Makefile.target Index: ioemu/xenstore.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/xenstore.c 2006-08-03 17:58:02.326548870 +0100 ++++ ioemu/xenstore.c 2006-08-04 10:42:27.564101367 +0100 @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms and conditions of the GNU General @@ -204,9 +204,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-03 17:57:38.867209740 +0100 -+++ ioemu/vl.c 2006-08-03 17:58:02.323549210 +0100 -@@ -4709,9 +4709,11 @@ +--- ioemu.orig/vl.c 2006-08-04 10:42:27.276134644 +0100 ++++ ioemu/vl.c 2006-08-04 10:42:27.567101020 +0100 +@@ -4711,9 +4711,11 @@ "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" @@ -218,7 +218,7 @@ Index: ioemu/vl.c "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB [default=%d]\n" -@@ -4841,11 +4843,13 @@ +@@ -4844,11 +4846,13 @@ QEMU_OPTION_M, QEMU_OPTION_fda, QEMU_OPTION_fdb, @@ -232,7 +232,7 @@ Index: ioemu/vl.c QEMU_OPTION_boot, QEMU_OPTION_snapshot, QEMU_OPTION_m, -@@ -4911,11 +4915,13 @@ +@@ -4915,11 +4919,13 @@ { "M", HAS_ARG, QEMU_OPTION_M }, { "fda", HAS_ARG, QEMU_OPTION_fda }, { "fdb", HAS_ARG, QEMU_OPTION_fdb }, @@ -246,7 +246,7 @@ Index: ioemu/vl.c { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, { "m", HAS_ARG, QEMU_OPTION_m }, -@@ -5250,10 +5256,16 @@ +@@ -5255,10 +5261,16 @@ #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif @@ -265,7 +265,7 @@ Index: ioemu/vl.c const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; -@@ -5288,8 +5300,10 @@ +@@ -5293,8 +5305,10 @@ initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; @@ -276,7 +276,7 @@ Index: ioemu/vl.c ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; -@@ -5302,11 +5316,13 @@ +@@ -5307,11 +5321,13 @@ vncviewer = 0; kernel_filename = NULL; kernel_cmdline = ""; @@ -290,7 +290,7 @@ Index: ioemu/vl.c cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); -@@ -5339,7 +5355,11 @@ +@@ -5344,7 +5360,11 @@ break; r = argv[optind]; if (r[0] != '-') { @@ -302,7 +302,7 @@ Index: ioemu/vl.c } else { const QEMUOption *popt; -@@ -5383,6 +5403,7 @@ +@@ -5388,6 +5408,7 @@ case QEMU_OPTION_initrd: initrd_filename = optarg; break; @@ -310,7 +310,7 @@ Index: ioemu/vl.c case QEMU_OPTION_hda: case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: -@@ -5395,6 +5416,7 @@ +@@ -5400,6 +5421,7 @@ cdrom_index = -1; } break; @@ -318,7 +318,7 @@ Index: ioemu/vl.c case QEMU_OPTION_snapshot: snapshot = 1; break; -@@ -5447,11 +5469,13 @@ +@@ -5452,11 +5474,13 @@ case QEMU_OPTION_append: kernel_cmdline = optarg; break; @@ -332,7 +332,7 @@ Index: ioemu/vl.c case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && -@@ -5690,12 +5714,18 @@ +@@ -5698,12 +5722,18 @@ } } @@ -351,7 +351,7 @@ Index: ioemu/vl.c if (!linux_boot && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && -@@ -5709,6 +5739,7 @@ +@@ -5717,6 +5747,7 @@ else boot_device = 'd'; } @@ -359,7 +359,7 @@ Index: ioemu/vl.c #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ -@@ -5848,6 +5879,7 @@ +@@ -5856,6 +5887,7 @@ #endif /* !CONFIG_DM */ @@ -367,7 +367,7 @@ Index: ioemu/vl.c /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { -@@ -5874,6 +5906,7 @@ +@@ -5882,6 +5914,7 @@ } } } @@ -375,7 +375,7 @@ Index: ioemu/vl.c /* we always create at least one floppy disk */ fd_table[0] = bdrv_new("fda"); -@@ -6009,6 +6042,8 @@ +@@ -6017,6 +6050,8 @@ #endif init_timers(); @@ -386,8 +386,8 @@ Index: ioemu/vl.c kernel_filename, kernel_cmdline, initrd_filename, Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-08-03 17:57:38.864210080 +0100 -+++ ioemu/monitor.c 2006-08-03 17:58:02.321549437 +0100 +--- ioemu.orig/monitor.c 2006-08-04 10:42:25.965286125 +0100 ++++ ioemu/monitor.c 2006-08-04 10:42:27.568100905 +0100 @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" @@ -416,8 +416,8 @@ Index: ioemu/monitor.c int i; Index: ioemu/block.c =================================================================== ---- ioemu.orig/block.c 2006-08-03 17:57:38.861210420 +0100 -+++ ioemu/block.c 2006-08-03 17:58:02.318549777 +0100 +--- ioemu.orig/block.c 2006-08-04 10:42:19.406044135 +0100 ++++ ioemu/block.c 2006-08-04 10:42:27.568100905 +0100 @@ -750,6 +750,7 @@ static void raw_close(BlockDriverState *bs) { @@ -428,9 +428,9 @@ Index: ioemu/block.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-03 17:57:38.868209627 +0100 -+++ ioemu/vl.h 2006-08-03 17:58:02.324549097 +0100 -@@ -1092,6 +1092,8 @@ +--- ioemu.orig/vl.h 2006-08-04 10:42:27.277134528 +0100 ++++ ioemu/vl.h 2006-08-04 10:42:27.569100789 +0100 +@@ -1093,6 +1093,8 @@ void term_print_help(void); void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size); @@ -439,7 +439,7 @@ Index: ioemu/vl.h /* readline.c */ typedef void ReadLineFunc(void *opaque, const char *str); -@@ -1104,6 +1106,13 @@ +@@ -1105,6 +1107,13 @@ void readline_start(const char *prompt, int is_password, ReadLineFunc *readline_func, void *opaque); @@ -455,8 +455,8 @@ Index: ioemu/vl.h extern char domain_name[]; Index: ioemu/hw/ide.c =================================================================== ---- ioemu.orig/hw/ide.c 2006-08-03 17:57:38.863210194 +0100 -+++ ioemu/hw/ide.c 2006-08-03 17:58:02.319549664 +0100 +--- ioemu.orig/hw/ide.c 2006-08-04 10:42:26.391236902 +0100 ++++ ioemu/hw/ide.c 2006-08-04 10:42:27.571100558 +0100 @@ -1279,6 +1279,7 @@ } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port index 1d49ef51d8..e7ef529410 100644 --- a/tools/ioemu/patches/xenstore-write-vnc-port +++ b/tools/ioemu/patches/xenstore-write-vnc-port @@ -1,7 +1,7 @@ Index: ioemu/xenstore.c =================================================================== ---- ioemu.orig/xenstore.c 2006-08-03 19:17:18.496119877 +0100 -+++ ioemu/xenstore.c 2006-08-03 19:18:29.428258503 +0100 +--- ioemu.orig/xenstore.c 2006-08-04 10:42:27.564101367 +0100 ++++ ioemu/xenstore.c 2006-08-04 10:42:27.771077449 +0100 @@ -185,3 +185,31 @@ free(image); free(vec); @@ -36,9 +36,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-03 19:17:18.499119544 +0100 -+++ ioemu/vl.c 2006-08-03 19:18:29.427258614 +0100 -@@ -5954,6 +5954,7 @@ +--- ioemu.orig/vl.c 2006-08-04 10:42:27.567101020 +0100 ++++ ioemu/vl.c 2006-08-04 10:42:27.774077103 +0100 +@@ -5962,6 +5962,7 @@ vnc_display_init(ds, vnc_display); if (vncviewer) vnc_start_viewer(vnc_display); @@ -48,9 +48,9 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-03 19:17:18.501119323 +0100 -+++ ioemu/vl.h 2006-08-03 19:18:29.428258503 +0100 -@@ -1111,6 +1111,7 @@ +--- ioemu.orig/vl.h 2006-08-04 10:42:27.569100789 +0100 ++++ ioemu/vl.h 2006-08-04 10:42:27.775076987 +0100 +@@ -1112,6 +1112,7 @@ int xenstore_fd(void); void xenstore_process_event(void *opaque); void xenstore_check_new_media_present(int timeout); From 300af9fa6eb5f6d5a565874c3a980a6c407776d5 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:52:25 +0100 Subject: [PATCH 087/111] [qemu] Fix qemu memory access beyond 3G @VTi side. Signed-off-by: Zhang xiantao --- tools/ioemu/vl.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index b3ccf6b04a..010cc152e0 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5783,6 +5783,11 @@ int main(int argc, char **argv) /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; +#if defined (__ia64__) + if (ram_size > MMIO_START) + ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */ +#endif + #ifdef CONFIG_DM nr_pages = ram_size/PAGE_SIZE; @@ -5816,22 +5821,9 @@ int main(int argc, char **argv) (uint64_t)(page_array[nr_pages - 1])); #elif defined(__ia64__) - if (xc_ia64_get_pfn_list(xc_handle, domid, - page_array, 0, nr_pages) != nr_pages) { - fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); - exit(-1); - } - - phys_ram_base = xc_map_foreign_batch(xc_handle, domid, - PROT_READ|PROT_WRITE, - page_array, nr_pages); - if (phys_ram_base == 0) { - fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); - exit(-1); - } - + if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, - IO_PAGE_START >> PAGE_SHIFT, 1) != 1){ + IO_PAGE_START >> PAGE_SHIFT, 1) != 1) { fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); exit(-1); } @@ -5842,6 +5834,26 @@ int main(int argc, char **argv) fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n", IO_PAGE_START >> PAGE_SHIFT, page_array[0]); + + if (xc_ia64_get_pfn_list(xc_handle, domid, + page_array, 0, nr_pages) != nr_pages) { + fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); + exit(-1); + } + + if (ram_size > MMIO_START) { + for (i = 0 ; i < MEM_G >> PAGE_SHIFT; i++) + page_array[MMIO_START >> PAGE_SHIFT + i] = + page_array[IO_PAGE_START >> PAGE_SHIFT + 1]; + } + + phys_ram_base = xc_map_foreign_batch(xc_handle, domid, + PROT_READ|PROT_WRITE, + page_array, nr_pages); + if (phys_ram_base == 0) { + fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); + exit(-1); + } #endif #else /* !CONFIG_DM */ From f2021fe86ccfecb62a5aba927696e23c72c3ad76 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:52:49 +0100 Subject: [PATCH 088/111] [qemu patches] Update patches for changeset 10936:a0b3cf802d99. Signed-off-by: Christian Limpach --- tools/ioemu/patches/ioemu-ia64 | 79 +++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/tools/ioemu/patches/ioemu-ia64 b/tools/ioemu/patches/ioemu-ia64 index 0fc91b92ee..69d2312802 100644 --- a/tools/ioemu/patches/ioemu-ia64 +++ b/tools/ioemu/patches/ioemu-ia64 @@ -1,7 +1,7 @@ Index: ioemu/hw/iommu.c =================================================================== ---- ioemu.orig/hw/iommu.c 2006-08-02 09:46:38.774790244 +0100 -+++ ioemu/hw/iommu.c 2006-08-02 09:46:39.030761544 +0100 +--- ioemu.orig/hw/iommu.c 2006-08-04 10:42:20.772886174 +0100 ++++ ioemu/hw/iommu.c 2006-08-04 10:42:25.397351756 +0100 @@ -82,7 +82,11 @@ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -16,8 +16,8 @@ Index: ioemu/hw/iommu.c Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-08-02 09:46:38.969768383 +0100 -+++ ioemu/cpu-all.h 2006-08-02 09:46:39.030761544 +0100 +--- ioemu.orig/cpu-all.h 2006-08-04 10:42:25.029394277 +0100 ++++ ioemu/cpu-all.h 2006-08-04 10:42:25.398351640 +0100 @@ -835,6 +835,31 @@ :"=m" (*(volatile long *)addr) :"dIr" (nr)); @@ -52,9 +52,21 @@ Index: ioemu/cpu-all.h /* memory API */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-02 09:46:39.020762665 +0100 -+++ ioemu/vl.c 2006-08-02 09:47:02.896085814 +0100 -@@ -5578,6 +5578,7 @@ +--- ioemu.orig/vl.c 2006-08-04 10:42:25.326359960 +0100 ++++ ioemu/vl.c 2006-08-04 10:51:21.239442976 +0100 +@@ -5567,6 +5567,11 @@ + /* init the memory */ + phys_ram_size = ram_size + vga_ram_size + bios_size; + ++#if defined (__ia64__) ++ if (ram_size > MMIO_START) ++ ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */ ++#endif ++ + #ifdef CONFIG_DM + + nr_pages = ram_size/PAGE_SIZE; +@@ -5578,6 +5583,7 @@ exit(-1); } @@ -62,27 +74,14 @@ Index: ioemu/vl.c if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) { fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno); exit(-1); -@@ -5598,6 +5599,34 @@ +@@ -5598,6 +5604,41 @@ fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", nr_pages - 1, (uint64_t)(page_array[nr_pages - 1])); +#elif defined(__ia64__) -+ if (xc_ia64_get_pfn_list(xc_handle, domid, -+ page_array, 0, nr_pages) != nr_pages) { -+ fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); -+ exit(-1); -+ } -+ -+ phys_ram_base = xc_map_foreign_batch(xc_handle, domid, -+ PROT_READ|PROT_WRITE, -+ page_array, nr_pages); -+ if (phys_ram_base == 0) { -+ fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); -+ exit(-1); -+ } -+ ++ + if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, -+ IO_PAGE_START >> PAGE_SHIFT, 1) != 1){ ++ IO_PAGE_START >> PAGE_SHIFT, 1) != 1) { + fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); + exit(-1); + } @@ -93,14 +92,34 @@ Index: ioemu/vl.c + + fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n", + IO_PAGE_START >> PAGE_SHIFT, page_array[0]); ++ ++ if (xc_ia64_get_pfn_list(xc_handle, domid, ++ page_array, 0, nr_pages) != nr_pages) { ++ fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); ++ exit(-1); ++ } ++ ++ if (ram_size > MMIO_START) { ++ for (i = 0 ; i < MEM_G >> PAGE_SHIFT; i++) ++ page_array[MMIO_START >> PAGE_SHIFT + i] = ++ page_array[IO_PAGE_START >> PAGE_SHIFT + 1]; ++ } ++ ++ phys_ram_base = xc_map_foreign_batch(xc_handle, domid, ++ PROT_READ|PROT_WRITE, ++ page_array, nr_pages); ++ if (phys_ram_base == 0) { ++ fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); ++ exit(-1); ++ } +#endif #else /* !CONFIG_DM */ #ifdef CONFIG_SOFTMMU Index: ioemu/target-i386-dm/exec-dm.c =================================================================== ---- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-02 09:46:38.903775782 +0100 -+++ ioemu/target-i386-dm/exec-dm.c 2006-08-02 09:46:39.034761096 +0100 +--- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-04 10:42:24.647438417 +0100 ++++ ioemu/target-i386-dm/exec-dm.c 2006-08-04 10:42:25.401351294 +0100 @@ -341,6 +341,23 @@ return io_mem_read[io_index >> IO_MEM_SHIFT]; } @@ -137,8 +156,8 @@ Index: ioemu/target-i386-dm/exec-dm.c memset(buf, 0xff, len); Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-08-02 09:46:38.881778248 +0100 -+++ ioemu/exec-all.h 2006-08-02 09:46:39.034761096 +0100 +--- ioemu.orig/exec-all.h 2006-08-04 10:42:24.518453323 +0100 ++++ ioemu/exec-all.h 2006-08-04 10:42:25.401351294 +0100 @@ -462,12 +462,13 @@ } #endif @@ -158,8 +177,8 @@ Index: ioemu/exec-all.h Index: ioemu/target-i386-dm/cpu.h =================================================================== ---- ioemu.orig/target-i386-dm/cpu.h 2006-08-02 09:46:38.902775894 +0100 -+++ ioemu/target-i386-dm/cpu.h 2006-08-02 09:46:39.034761096 +0100 +--- ioemu.orig/target-i386-dm/cpu.h 2006-08-04 10:42:24.647438417 +0100 ++++ ioemu/target-i386-dm/cpu.h 2006-08-04 10:42:25.401351294 +0100 @@ -80,7 +80,11 @@ /* helper2.c */ int main_loop(void); @@ -175,7 +194,7 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/ia64_intrinsic.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/ia64_intrinsic.h 2006-08-02 09:46:39.035760983 +0100 ++++ ioemu/ia64_intrinsic.h 2006-08-04 10:42:25.402351178 +0100 @@ -0,0 +1,276 @@ +#ifndef IA64_INTRINSIC_H +#define IA64_INTRINSIC_H From 6321bfff99133c83f02863d063504b062b21a9d0 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:53:11 +0100 Subject: [PATCH 089/111] [qemu patches] Refresh patches. Signed-off-by: Christian Limpach --- tools/ioemu/patches/domain-timeoffset | 18 +++++------ tools/ioemu/patches/vnc-fixes | 14 ++++---- tools/ioemu/patches/vnc-start-vncviewer | 14 ++++---- .../patches/xenstore-block-device-config | 32 +++++++++---------- tools/ioemu/patches/xenstore-write-vnc-port | 14 ++++---- 5 files changed, 46 insertions(+), 46 deletions(-) diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset index 72b5b6165a..526173e776 100644 --- a/tools/ioemu/patches/domain-timeoffset +++ b/tools/ioemu/patches/domain-timeoffset @@ -1,7 +1,7 @@ Index: ioemu/hw/mc146818rtc.c =================================================================== ---- ioemu.orig/hw/mc146818rtc.c 2006-08-04 10:42:19.796998954 +0100 -+++ ioemu/hw/mc146818rtc.c 2006-08-04 10:42:26.456229392 +0100 +--- ioemu.orig/hw/mc146818rtc.c 2006-08-04 10:52:55.914499631 +0100 ++++ ioemu/hw/mc146818rtc.c 2006-08-04 10:53:03.701599955 +0100 @@ -178,10 +178,27 @@ } } @@ -46,8 +46,8 @@ Index: ioemu/hw/mc146818rtc.c static void rtc_copy_date(RTCState *s) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-04 10:42:26.185260705 +0100 -+++ ioemu/hw/pc.c 2006-08-04 10:42:26.457229276 +0100 +--- ioemu.orig/hw/pc.c 2006-08-04 10:53:03.431631144 +0100 ++++ ioemu/hw/pc.c 2006-08-04 10:53:03.701599955 +0100 @@ -151,7 +151,7 @@ } @@ -117,8 +117,8 @@ Index: ioemu/hw/pc.c QEMUMachine pc_machine = { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:26.324244644 +0100 -+++ ioemu/vl.c 2006-08-04 10:42:26.459229045 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:53:03.571614972 +0100 ++++ ioemu/vl.c 2006-08-04 10:53:03.704599608 +0100 @@ -164,6 +164,8 @@ int xc_handle; @@ -162,7 +162,7 @@ Index: ioemu/vl.c } } } -@@ -5993,7 +6001,8 @@ +@@ -6005,7 +6013,8 @@ machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, @@ -174,8 +174,8 @@ Index: ioemu/vl.c qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:42:26.190260127 +0100 -+++ ioemu/vl.h 2006-08-04 10:42:26.460228930 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:53:03.436630567 +0100 ++++ ioemu/vl.h 2006-08-04 10:53:03.705599493 +0100 @@ -556,7 +556,7 @@ int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/tools/ioemu/patches/vnc-fixes b/tools/ioemu/patches/vnc-fixes index 36f04f4bab..b001ed2d11 100644 --- a/tools/ioemu/patches/vnc-fixes +++ b/tools/ioemu/patches/vnc-fixes @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:26.921175663 +0100 -+++ ioemu/vl.c 2006-08-04 10:42:27.107154171 +0100 -@@ -6012,8 +6012,10 @@ +--- ioemu.orig/vl.c 2006-08-04 10:53:04.142549012 +0100 ++++ ioemu/vl.c 2006-08-04 10:53:04.206541619 +0100 +@@ -6024,8 +6024,10 @@ kernel_filename, kernel_cmdline, initrd_filename, timeoffset); @@ -17,8 +17,8 @@ Index: ioemu/vl.c if (use_gdbstub) { Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:42:26.918176009 +0100 -+++ ioemu/vnc.c 2006-08-04 10:42:27.108154056 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:53:04.139549358 +0100 ++++ ioemu/vnc.c 2006-08-04 10:53:04.207541503 +0100 @@ -3,6 +3,7 @@ * * Copyright (C) 2006 Anthony Liguori @@ -493,8 +493,8 @@ Index: ioemu/vnc.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:42:26.724198425 +0100 -+++ ioemu/vl.h 2006-08-04 10:42:27.108154056 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:53:03.950571191 +0100 ++++ ioemu/vl.h 2006-08-04 10:53:04.207541503 +0100 @@ -302,6 +302,7 @@ int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds); diff --git a/tools/ioemu/patches/vnc-start-vncviewer b/tools/ioemu/patches/vnc-start-vncviewer index 31caaae19e..3305167117 100644 --- a/tools/ioemu/patches/vnc-start-vncviewer +++ b/tools/ioemu/patches/vnc-start-vncviewer @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:42:27.108154056 +0100 -+++ ioemu/vnc.c 2006-08-04 10:42:27.272135106 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:53:04.207541503 +0100 ++++ ioemu/vnc.c 2006-08-04 10:53:04.370522674 +0100 @@ -1002,3 +1002,25 @@ vnc_dpy_resize(vs->ds, 640, 400); @@ -30,8 +30,8 @@ Index: ioemu/vnc.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:27.107154171 +0100 -+++ ioemu/vl.c 2006-08-04 10:42:27.276134644 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:53:04.206541619 +0100 ++++ ioemu/vl.c 2006-08-04 10:53:04.373522328 +0100 @@ -121,6 +121,7 @@ int bios_size; static DisplayState display_state; @@ -82,7 +82,7 @@ Index: ioemu/vl.c case QEMU_OPTION_domainname: strncat(domain_name, optarg, sizeof(domain_name) - 20); break; -@@ -5919,6 +5927,8 @@ +@@ -5931,6 +5939,8 @@ dumb_display_init(ds); } else if (vnc_display != -1) { vnc_display_init(ds, vnc_display); @@ -93,8 +93,8 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:42:27.108154056 +0100 -+++ ioemu/vl.h 2006-08-04 10:42:27.277134528 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:53:04.207541503 +0100 ++++ ioemu/vl.h 2006-08-04 10:53:04.374522212 +0100 @@ -734,6 +734,7 @@ /* vnc.c */ diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config index 40a7418959..ad51023183 100644 --- a/tools/ioemu/patches/xenstore-block-device-config +++ b/tools/ioemu/patches/xenstore-block-device-config @@ -1,7 +1,7 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-04 10:42:26.718199119 +0100 -+++ ioemu/Makefile.target 2006-08-04 10:42:27.563101483 +0100 +--- ioemu.orig/Makefile.target 2006-08-04 10:53:03.944571884 +0100 ++++ ioemu/Makefile.target 2006-08-04 10:53:04.659489290 +0100 @@ -336,6 +336,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o @@ -13,7 +13,7 @@ Index: ioemu/Makefile.target Index: ioemu/xenstore.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/xenstore.c 2006-08-04 10:42:27.564101367 +0100 ++++ ioemu/xenstore.c 2006-08-04 10:53:04.660489174 +0100 @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms and conditions of the GNU General @@ -204,8 +204,8 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:27.276134644 +0100 -+++ ioemu/vl.c 2006-08-04 10:42:27.567101020 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:53:04.373522328 +0100 ++++ ioemu/vl.c 2006-08-04 10:53:04.663488828 +0100 @@ -4711,9 +4711,11 @@ "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" @@ -359,7 +359,7 @@ Index: ioemu/vl.c #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ -@@ -5856,6 +5887,7 @@ +@@ -5868,6 +5899,7 @@ #endif /* !CONFIG_DM */ @@ -367,7 +367,7 @@ Index: ioemu/vl.c /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { -@@ -5882,6 +5914,7 @@ +@@ -5894,6 +5926,7 @@ } } } @@ -375,7 +375,7 @@ Index: ioemu/vl.c /* we always create at least one floppy disk */ fd_table[0] = bdrv_new("fda"); -@@ -6017,6 +6050,8 @@ +@@ -6029,6 +6062,8 @@ #endif init_timers(); @@ -386,8 +386,8 @@ Index: ioemu/vl.c kernel_filename, kernel_cmdline, initrd_filename, Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-08-04 10:42:25.965286125 +0100 -+++ ioemu/monitor.c 2006-08-04 10:42:27.568100905 +0100 +--- ioemu.orig/monitor.c 2006-08-04 10:53:03.222655287 +0100 ++++ ioemu/monitor.c 2006-08-04 10:53:04.664488712 +0100 @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" @@ -416,8 +416,8 @@ Index: ioemu/monitor.c int i; Index: ioemu/block.c =================================================================== ---- ioemu.orig/block.c 2006-08-04 10:42:19.406044135 +0100 -+++ ioemu/block.c 2006-08-04 10:42:27.568100905 +0100 +--- ioemu.orig/block.c 2006-08-04 10:52:55.582537986 +0100 ++++ ioemu/block.c 2006-08-04 10:53:04.664488712 +0100 @@ -750,6 +750,7 @@ static void raw_close(BlockDriverState *bs) { @@ -428,8 +428,8 @@ Index: ioemu/block.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:42:27.277134528 +0100 -+++ ioemu/vl.h 2006-08-04 10:42:27.569100789 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:53:04.374522212 +0100 ++++ ioemu/vl.h 2006-08-04 10:53:04.665488597 +0100 @@ -1093,6 +1093,8 @@ void term_print_help(void); void monitor_readline(const char *prompt, int is_password, @@ -455,8 +455,8 @@ Index: ioemu/vl.h extern char domain_name[]; Index: ioemu/hw/ide.c =================================================================== ---- ioemu.orig/hw/ide.c 2006-08-04 10:42:26.391236902 +0100 -+++ ioemu/hw/ide.c 2006-08-04 10:42:27.571100558 +0100 +--- ioemu.orig/hw/ide.c 2006-08-04 10:53:03.636607463 +0100 ++++ ioemu/hw/ide.c 2006-08-04 10:53:04.666488481 +0100 @@ -1279,6 +1279,7 @@ } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port index e7ef529410..189430d425 100644 --- a/tools/ioemu/patches/xenstore-write-vnc-port +++ b/tools/ioemu/patches/xenstore-write-vnc-port @@ -1,7 +1,7 @@ Index: ioemu/xenstore.c =================================================================== ---- ioemu.orig/xenstore.c 2006-08-04 10:42:27.564101367 +0100 -+++ ioemu/xenstore.c 2006-08-04 10:42:27.771077449 +0100 +--- ioemu.orig/xenstore.c 2006-08-04 10:53:04.660489174 +0100 ++++ ioemu/xenstore.c 2006-08-04 10:53:04.865465494 +0100 @@ -185,3 +185,31 @@ free(image); free(vec); @@ -36,9 +36,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:27.567101020 +0100 -+++ ioemu/vl.c 2006-08-04 10:42:27.774077103 +0100 -@@ -5962,6 +5962,7 @@ +--- ioemu.orig/vl.c 2006-08-04 10:53:04.663488828 +0100 ++++ ioemu/vl.c 2006-08-04 10:53:04.868465147 +0100 +@@ -5974,6 +5974,7 @@ vnc_display_init(ds, vnc_display); if (vncviewer) vnc_start_viewer(vnc_display); @@ -48,8 +48,8 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:42:27.569100789 +0100 -+++ ioemu/vl.h 2006-08-04 10:42:27.775076987 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:53:04.665488597 +0100 ++++ ioemu/vl.h 2006-08-04 10:53:04.869465032 +0100 @@ -1112,6 +1112,7 @@ int xenstore_fd(void); void xenstore_process_event(void *opaque); From 1670f1a42254ca05d5f9f88fc4868f4014307554 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:56:53 +0100 Subject: [PATCH 090/111] [qemu] Free page_array when it's no longer used. Seems no special reason for keeping page_array, free it to avoid memroy leak in Qemu. Signed-off-by : Zhang xiantao --- tools/ioemu/vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 010cc152e0..7084b78c57 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5820,6 +5820,8 @@ int main(int argc, char **argv) fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", nr_pages - 1, (uint64_t)(page_array[nr_pages - 1])); + free(page_array); + #elif defined(__ia64__) if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, From 16304772eb18a92498de74cb28032254e91655ff Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:57:13 +0100 Subject: [PATCH 091/111] [qemu patches] Update patches for changeset 10939:5980fb28b050. Signed-off-by: Christian Limpach --- tools/ioemu/patches/xen-mm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/ioemu/patches/xen-mm b/tools/ioemu/patches/xen-mm index da4a7112f3..ac54eefc98 100644 --- a/tools/ioemu/patches/xen-mm +++ b/tools/ioemu/patches/xen-mm @@ -1,7 +1,7 @@ Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-27 11:16:57.678475515 +0100 -+++ ioemu/hw/pc.c 2006-07-27 11:16:58.447390396 +0100 +--- ioemu.orig/hw/pc.c 2006-08-04 10:53:02.019794255 +0100 ++++ ioemu/hw/pc.c 2006-08-04 10:54:56.876531492 +0100 @@ -639,7 +639,9 @@ } @@ -25,8 +25,8 @@ Index: ioemu/hw/pc.c isa_bios_size = bios_size; Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:58.296407110 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:58.450390064 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:53:02.472741926 +0100 ++++ ioemu/vl.c 2006-08-04 10:55:48.361590787 +0100 @@ -159,6 +159,8 @@ #define MAX_CPUS 1 #endif @@ -60,7 +60,7 @@ Index: ioemu/vl.c break; case QEMU_OPTION_l: { -@@ -5560,6 +5567,39 @@ +@@ -5560,6 +5567,41 @@ /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; @@ -95,12 +95,14 @@ Index: ioemu/vl.c + fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", nr_pages - 1, + (uint64_t)(page_array[nr_pages - 1])); + ++ free(page_array); ++ +#else /* !CONFIG_DM */ + #ifdef CONFIG_SOFTMMU phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { -@@ -5600,6 +5640,8 @@ +@@ -5600,6 +5642,8 @@ } #endif From 28f1d62e4930893584bf21b197e54cd1a0cc53c4 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 10:57:34 +0100 Subject: [PATCH 092/111] [qemu patches] Refresh patches. Signed-off-by: Christian Limpach --- tools/ioemu/patches/domain-timeoffset | 18 +++++------ tools/ioemu/patches/ioemu-ia64 | 32 +++++++++---------- tools/ioemu/patches/vnc-fixes | 14 ++++---- tools/ioemu/patches/vnc-start-vncviewer | 14 ++++---- .../patches/xenstore-block-device-config | 32 +++++++++---------- tools/ioemu/patches/xenstore-write-vnc-port | 14 ++++---- 6 files changed, 62 insertions(+), 62 deletions(-) diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset index 526173e776..ec526bb4ff 100644 --- a/tools/ioemu/patches/domain-timeoffset +++ b/tools/ioemu/patches/domain-timeoffset @@ -1,7 +1,7 @@ Index: ioemu/hw/mc146818rtc.c =================================================================== ---- ioemu.orig/hw/mc146818rtc.c 2006-08-04 10:52:55.914499631 +0100 -+++ ioemu/hw/mc146818rtc.c 2006-08-04 10:53:03.701599955 +0100 +--- ioemu.orig/hw/mc146818rtc.c 2006-08-04 10:57:22.049787220 +0100 ++++ ioemu/hw/mc146818rtc.c 2006-08-04 10:57:28.677023336 +0100 @@ -178,10 +178,27 @@ } } @@ -46,8 +46,8 @@ Index: ioemu/hw/mc146818rtc.c static void rtc_copy_date(RTCState *s) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-04 10:53:03.431631144 +0100 -+++ ioemu/hw/pc.c 2006-08-04 10:53:03.701599955 +0100 +--- ioemu.orig/hw/pc.c 2006-08-04 10:57:28.406054568 +0100 ++++ ioemu/hw/pc.c 2006-08-04 10:57:28.678023221 +0100 @@ -151,7 +151,7 @@ } @@ -117,8 +117,8 @@ Index: ioemu/hw/pc.c QEMUMachine pc_machine = { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:53:03.571614972 +0100 -+++ ioemu/vl.c 2006-08-04 10:53:03.704599608 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:57:28.545038549 +0100 ++++ ioemu/vl.c 2006-08-04 10:57:28.680022990 +0100 @@ -164,6 +164,8 @@ int xc_handle; @@ -162,7 +162,7 @@ Index: ioemu/vl.c } } } -@@ -6005,7 +6013,8 @@ +@@ -6007,7 +6015,8 @@ machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, @@ -174,8 +174,8 @@ Index: ioemu/vl.c qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:53:03.436630567 +0100 -+++ ioemu/vl.h 2006-08-04 10:53:03.705599493 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:57:28.411053992 +0100 ++++ ioemu/vl.h 2006-08-04 10:57:28.681022875 +0100 @@ -556,7 +556,7 @@ int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/tools/ioemu/patches/ioemu-ia64 b/tools/ioemu/patches/ioemu-ia64 index 69d2312802..bf8d4b04b5 100644 --- a/tools/ioemu/patches/ioemu-ia64 +++ b/tools/ioemu/patches/ioemu-ia64 @@ -1,7 +1,7 @@ Index: ioemu/hw/iommu.c =================================================================== ---- ioemu.orig/hw/iommu.c 2006-08-04 10:42:20.772886174 +0100 -+++ ioemu/hw/iommu.c 2006-08-04 10:42:25.397351756 +0100 +--- ioemu.orig/hw/iommu.c 2006-08-04 10:57:22.606723023 +0100 ++++ ioemu/hw/iommu.c 2006-08-04 10:57:27.489160251 +0100 @@ -82,7 +82,11 @@ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -16,8 +16,8 @@ Index: ioemu/hw/iommu.c Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-08-04 10:42:25.029394277 +0100 -+++ ioemu/cpu-all.h 2006-08-04 10:42:25.398351640 +0100 +--- ioemu.orig/cpu-all.h 2006-08-04 10:57:27.123202432 +0100 ++++ ioemu/cpu-all.h 2006-08-04 10:57:27.490160136 +0100 @@ -835,6 +835,31 @@ :"=m" (*(volatile long *)addr) :"dIr" (nr)); @@ -52,8 +52,8 @@ Index: ioemu/cpu-all.h /* memory API */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:25.326359960 +0100 -+++ ioemu/vl.c 2006-08-04 10:51:21.239442976 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:57:27.419168318 +0100 ++++ ioemu/vl.c 2006-08-04 10:57:27.493159790 +0100 @@ -5567,6 +5567,11 @@ /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; @@ -74,9 +74,9 @@ Index: ioemu/vl.c if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) { fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno); exit(-1); -@@ -5598,6 +5604,41 @@ - fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", nr_pages - 1, - (uint64_t)(page_array[nr_pages - 1])); +@@ -5600,6 +5606,41 @@ + + free(page_array); +#elif defined(__ia64__) + @@ -118,8 +118,8 @@ Index: ioemu/vl.c #ifdef CONFIG_SOFTMMU Index: ioemu/target-i386-dm/exec-dm.c =================================================================== ---- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-04 10:42:24.647438417 +0100 -+++ ioemu/target-i386-dm/exec-dm.c 2006-08-04 10:42:25.401351294 +0100 +--- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-04 10:57:26.738246803 +0100 ++++ ioemu/target-i386-dm/exec-dm.c 2006-08-04 10:57:27.493159790 +0100 @@ -341,6 +341,23 @@ return io_mem_read[io_index >> IO_MEM_SHIFT]; } @@ -156,8 +156,8 @@ Index: ioemu/target-i386-dm/exec-dm.c memset(buf, 0xff, len); Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-08-04 10:42:24.518453323 +0100 -+++ ioemu/exec-all.h 2006-08-04 10:42:25.401351294 +0100 +--- ioemu.orig/exec-all.h 2006-08-04 10:57:26.651256830 +0100 ++++ ioemu/exec-all.h 2006-08-04 10:57:27.494159675 +0100 @@ -462,12 +462,13 @@ } #endif @@ -177,8 +177,8 @@ Index: ioemu/exec-all.h Index: ioemu/target-i386-dm/cpu.h =================================================================== ---- ioemu.orig/target-i386-dm/cpu.h 2006-08-04 10:42:24.647438417 +0100 -+++ ioemu/target-i386-dm/cpu.h 2006-08-04 10:42:25.401351294 +0100 +--- ioemu.orig/target-i386-dm/cpu.h 2006-08-04 10:57:26.737246918 +0100 ++++ ioemu/target-i386-dm/cpu.h 2006-08-04 10:57:27.494159675 +0100 @@ -80,7 +80,11 @@ /* helper2.c */ int main_loop(void); @@ -194,7 +194,7 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/ia64_intrinsic.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/ia64_intrinsic.h 2006-08-04 10:42:25.402351178 +0100 ++++ ioemu/ia64_intrinsic.h 2006-08-04 10:57:27.495159560 +0100 @@ -0,0 +1,276 @@ +#ifndef IA64_INTRINSIC_H +#define IA64_INTRINSIC_H diff --git a/tools/ioemu/patches/vnc-fixes b/tools/ioemu/patches/vnc-fixes index b001ed2d11..ba21cb25a4 100644 --- a/tools/ioemu/patches/vnc-fixes +++ b/tools/ioemu/patches/vnc-fixes @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:53:04.142549012 +0100 -+++ ioemu/vl.c 2006-08-04 10:53:04.206541619 +0100 -@@ -6024,8 +6024,10 @@ +--- ioemu.orig/vl.c 2006-08-04 10:57:29.116972627 +0100 ++++ ioemu/vl.c 2006-08-04 10:57:29.186964560 +0100 +@@ -6026,8 +6026,10 @@ kernel_filename, kernel_cmdline, initrd_filename, timeoffset); @@ -17,8 +17,8 @@ Index: ioemu/vl.c if (use_gdbstub) { Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:53:04.139549358 +0100 -+++ ioemu/vnc.c 2006-08-04 10:53:04.207541503 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:57:29.114972858 +0100 ++++ ioemu/vnc.c 2006-08-04 10:57:29.187964445 +0100 @@ -3,6 +3,7 @@ * * Copyright (C) 2006 Anthony Liguori @@ -493,8 +493,8 @@ Index: ioemu/vnc.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:53:03.950571191 +0100 -+++ ioemu/vl.h 2006-08-04 10:53:04.207541503 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:57:28.925994639 +0100 ++++ ioemu/vl.h 2006-08-04 10:57:29.187964445 +0100 @@ -302,6 +302,7 @@ int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds); diff --git a/tools/ioemu/patches/vnc-start-vncviewer b/tools/ioemu/patches/vnc-start-vncviewer index 3305167117..e0ecff1fe0 100644 --- a/tools/ioemu/patches/vnc-start-vncviewer +++ b/tools/ioemu/patches/vnc-start-vncviewer @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:53:04.207541503 +0100 -+++ ioemu/vnc.c 2006-08-04 10:53:04.370522674 +0100 +--- ioemu.orig/vnc.c 2006-08-04 10:57:29.187964445 +0100 ++++ ioemu/vnc.c 2006-08-04 10:57:29.351945544 +0100 @@ -1002,3 +1002,25 @@ vnc_dpy_resize(vs->ds, 640, 400); @@ -30,8 +30,8 @@ Index: ioemu/vnc.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:53:04.206541619 +0100 -+++ ioemu/vl.c 2006-08-04 10:53:04.373522328 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:57:29.186964560 +0100 ++++ ioemu/vl.c 2006-08-04 10:57:29.354945198 +0100 @@ -121,6 +121,7 @@ int bios_size; static DisplayState display_state; @@ -82,7 +82,7 @@ Index: ioemu/vl.c case QEMU_OPTION_domainname: strncat(domain_name, optarg, sizeof(domain_name) - 20); break; -@@ -5931,6 +5939,8 @@ +@@ -5933,6 +5941,8 @@ dumb_display_init(ds); } else if (vnc_display != -1) { vnc_display_init(ds, vnc_display); @@ -93,8 +93,8 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:53:04.207541503 +0100 -+++ ioemu/vl.h 2006-08-04 10:53:04.374522212 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:57:29.187964445 +0100 ++++ ioemu/vl.h 2006-08-04 10:57:29.355945083 +0100 @@ -734,6 +734,7 @@ /* vnc.c */ diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config index ad51023183..93cc5651a0 100644 --- a/tools/ioemu/patches/xenstore-block-device-config +++ b/tools/ioemu/patches/xenstore-block-device-config @@ -1,7 +1,7 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-04 10:53:03.944571884 +0100 -+++ ioemu/Makefile.target 2006-08-04 10:53:04.659489290 +0100 +--- ioemu.orig/Makefile.target 2006-08-04 10:57:28.920995216 +0100 ++++ ioemu/Makefile.target 2006-08-04 10:57:29.641912123 +0100 @@ -336,6 +336,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o @@ -13,7 +13,7 @@ Index: ioemu/Makefile.target Index: ioemu/xenstore.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/xenstore.c 2006-08-04 10:53:04.660489174 +0100 ++++ ioemu/xenstore.c 2006-08-04 10:57:29.641912123 +0100 @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms and conditions of the GNU General @@ -204,8 +204,8 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:53:04.373522328 +0100 -+++ ioemu/vl.c 2006-08-04 10:53:04.663488828 +0100 +--- ioemu.orig/vl.c 2006-08-04 10:57:29.354945198 +0100 ++++ ioemu/vl.c 2006-08-04 10:57:29.644911777 +0100 @@ -4711,9 +4711,11 @@ "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" @@ -359,7 +359,7 @@ Index: ioemu/vl.c #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ -@@ -5868,6 +5899,7 @@ +@@ -5870,6 +5901,7 @@ #endif /* !CONFIG_DM */ @@ -367,7 +367,7 @@ Index: ioemu/vl.c /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { -@@ -5894,6 +5926,7 @@ +@@ -5896,6 +5928,7 @@ } } } @@ -375,7 +375,7 @@ Index: ioemu/vl.c /* we always create at least one floppy disk */ fd_table[0] = bdrv_new("fda"); -@@ -6029,6 +6062,8 @@ +@@ -6031,6 +6064,8 @@ #endif init_timers(); @@ -386,8 +386,8 @@ Index: ioemu/vl.c kernel_filename, kernel_cmdline, initrd_filename, Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-08-04 10:53:03.222655287 +0100 -+++ ioemu/monitor.c 2006-08-04 10:53:04.664488712 +0100 +--- ioemu.orig/monitor.c 2006-08-04 10:57:28.195078886 +0100 ++++ ioemu/monitor.c 2006-08-04 10:57:29.645911662 +0100 @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" @@ -416,8 +416,8 @@ Index: ioemu/monitor.c int i; Index: ioemu/block.c =================================================================== ---- ioemu.orig/block.c 2006-08-04 10:52:55.582537986 +0100 -+++ ioemu/block.c 2006-08-04 10:53:04.664488712 +0100 +--- ioemu.orig/block.c 2006-08-04 10:57:21.718825369 +0100 ++++ ioemu/block.c 2006-08-04 10:57:29.646911546 +0100 @@ -750,6 +750,7 @@ static void raw_close(BlockDriverState *bs) { @@ -428,8 +428,8 @@ Index: ioemu/block.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:53:04.374522212 +0100 -+++ ioemu/vl.h 2006-08-04 10:53:04.665488597 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:57:29.355945083 +0100 ++++ ioemu/vl.h 2006-08-04 10:57:29.647911431 +0100 @@ -1093,6 +1093,8 @@ void term_print_help(void); void monitor_readline(const char *prompt, int is_password, @@ -455,8 +455,8 @@ Index: ioemu/vl.h extern char domain_name[]; Index: ioemu/hw/ide.c =================================================================== ---- ioemu.orig/hw/ide.c 2006-08-04 10:53:03.636607463 +0100 -+++ ioemu/hw/ide.c 2006-08-04 10:53:04.666488481 +0100 +--- ioemu.orig/hw/ide.c 2006-08-04 10:57:28.612030827 +0100 ++++ ioemu/hw/ide.c 2006-08-04 10:57:29.648911316 +0100 @@ -1279,6 +1279,7 @@ } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port index 189430d425..fe326cffb1 100644 --- a/tools/ioemu/patches/xenstore-write-vnc-port +++ b/tools/ioemu/patches/xenstore-write-vnc-port @@ -1,7 +1,7 @@ Index: ioemu/xenstore.c =================================================================== ---- ioemu.orig/xenstore.c 2006-08-04 10:53:04.660489174 +0100 -+++ ioemu/xenstore.c 2006-08-04 10:53:04.865465494 +0100 +--- ioemu.orig/xenstore.c 2006-08-04 10:57:29.641912123 +0100 ++++ ioemu/xenstore.c 2006-08-04 10:57:30.244842629 +0100 @@ -185,3 +185,31 @@ free(image); free(vec); @@ -36,9 +36,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:53:04.663488828 +0100 -+++ ioemu/vl.c 2006-08-04 10:53:04.868465147 +0100 -@@ -5974,6 +5974,7 @@ +--- ioemu.orig/vl.c 2006-08-04 10:57:29.644911777 +0100 ++++ ioemu/vl.c 2006-08-04 10:57:30.246842399 +0100 +@@ -5976,6 +5976,7 @@ vnc_display_init(ds, vnc_display); if (vncviewer) vnc_start_viewer(vnc_display); @@ -48,8 +48,8 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:53:04.665488597 +0100 -+++ ioemu/vl.h 2006-08-04 10:53:04.869465032 +0100 +--- ioemu.orig/vl.h 2006-08-04 10:57:29.647911431 +0100 ++++ ioemu/vl.h 2006-08-04 10:57:30.247842283 +0100 @@ -1112,6 +1112,7 @@ int xenstore_fd(void); void xenstore_process_event(void *opaque); From a5da231f56268702ba9d9e0c4f1ad7156446e77b Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 11:03:17 +0100 Subject: [PATCH 093/111] [hvm firmware] Update hvm acpi dsdt table. 1)Code style clean up 2)Mininor fix for pci bus 0, dev 4 apic IRQ number 3)Add support for HCT "unreported IO and Memory" test by reporting low 640 MB mem as motherboard resource Signed-off-by: Winston Wang --- tools/firmware/acpi/acpi_dsdt.asl | 217 ++++++------ tools/firmware/acpi/acpi_dsdt.c | 531 +++++++++++++++--------------- 2 files changed, 385 insertions(+), 363 deletions(-) diff --git a/tools/firmware/acpi/acpi_dsdt.asl b/tools/firmware/acpi/acpi_dsdt.asl index 139020f779..8a1bc47221 100644 --- a/tools/firmware/acpi/acpi_dsdt.asl +++ b/tools/firmware/acpi/acpi_dsdt.asl @@ -16,7 +16,7 @@ //* Place - Suite 330, Boston, MA 02111-1307 USA. //** -//** DSDT for Xen with Qemu device model +//** DSDT for Xen with Qemu device model //** //** @@ -50,21 +50,36 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) }) - Name(PICD, 0) + Name(PICD, 0) - Method(_PIC, 1) { + Method(_PIC, 1) { - Store(Arg0, PICD) - } + Store(Arg0, PICD) + } Scope (\_SB) { - Device (PCI0) + /* Fix HCT test for 0x400 pci memory - need to report low 640 MB mem as motherboard resource */ + + Device(MEM0) { + Name(_HID, EISAID("PNP0C02")) + Name(_CRS, ResourceTemplate() { + QWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, + 0x00000000, + 0x0009ffff, + 0x00000000, + 0x000a0000) + } + ) + } + + Device (PCI0) { - Name (_HID, EisaId ("PNP0A03")) - Name (_UID, 0x00) - Name (_ADR, 0x00) - Name (_BBN, 0x00) - OperationRegion (PIRP, PCI_Config, 0x3c, 0x10) + Name (_HID, EisaId ("PNP0A03")) + Name (_UID, 0x00) + Name (_ADR, 0x00) + Name (_BBN, 0x00) + OperationRegion (PIRP, PCI_Config, 0x3c, 0x10) Field(PIRP, ByteAcc, NoLock, Preserve){ IRQ3,3, IRQ5,5, @@ -79,7 +94,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) Name (PRT0, ResourceTemplate () { - /* bus number is from 0 - 255*/ + /* bus number is from 0 - 255*/ WordBusNumber (ResourceConsumer, MinFixed, MaxFixed, SubDecode, 0x0000, 0x0000, @@ -122,7 +137,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) 0x00000000, 0x00030000) - /* reserve what device model consumed for PCI VGA device */ + /* reserve what device model consumed for PCI VGA device */ DWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, 0x00000000, @@ -146,9 +161,9 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) }) Return (PRT0) } - Name(BUFA, ResourceTemplate() { + Name(BUFA, ResourceTemplate() { IRQ(Level, ActiveLow, Shared) { - 3,4,5,6,7,10,11,12,14,15} + 3,4,5,6,7,10,11,12,14,15} }) Name(BUFB, Buffer(){ @@ -156,7 +171,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) 0x79, 0}) CreateWordField(BUFB, 0x01, IRQV) - + Name(BUFC, Buffer(){ 5, 7, 10, 11 }) @@ -165,17 +180,17 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) CreateByteField(BUFC, 0x01, PIQB) CreateByteField(BUFC, 0x01, PIQC) CreateByteField(BUFC, 0x01, PIQD) - - Device(LNKA) { - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + + Device(LNKA) { + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link Name(_UID, 1) Method(_STA, 0) { And(PIRA, 0x80, Local0) If(LEqual(Local0, 0x80)) { - Return(0x09) + Return(0x09) } Else { - Return(0x0B) + Return(0x0B) } } @@ -189,34 +204,34 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) } Method(_CRS) { - And(PIRB, 0x0f, Local0) - ShiftLeft(0x1, Local0, IRQV) - Return(BUFB) + And(PIRB, 0x0f, Local0) + ShiftLeft(0x1, Local0, IRQV) + Return(BUFB) } Method(_SRS, 1) { - CreateWordField(ARG0, 0x01, IRQ1) - FindSetRightBit(IRQ1, Local0) - Decrement(Local0) - Store(Local0, PIRA) + CreateWordField(ARG0, 0x01, IRQ1) + FindSetRightBit(IRQ1, Local0) + Decrement(Local0) + Store(Local0, PIRA) } // Method(_SRS) } - Device(LNKB) { - Name(_HID, EISAID("PNP0C0F")) + Device(LNKB){ + Name(_HID, EISAID("PNP0C0F")) Name(_UID, 2) Method(_STA, 0) { And(PIRB, 0x80, Local0) If(LEqual(Local0, 0x80)) { - Return(0x09) + Return(0x09) } Else { - Return(0x0B) + Return(0x0B) } } Method(_PRS) { - Return(BUFA) + Return(BUFA) } // Method(_PRS) Method(_DIS) { @@ -225,35 +240,35 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) } Method(_CRS) { - And(PIRB, 0x0f, Local0) - ShiftLeft(0x1, Local0, IRQV) - Return(BUFB) + And(PIRB, 0x0f, Local0) + ShiftLeft(0x1, Local0, IRQV) + Return(BUFB) } // Method(_CRS) Method(_SRS, 1) { - CreateWordField(ARG0, 0x01, IRQ1) - FindSetRightBit(IRQ1, Local0) - Decrement(Local0) - Store(Local0, PIRB) + CreateWordField(ARG0, 0x01, IRQ1) + FindSetRightBit(IRQ1, Local0) + Decrement(Local0) + Store(Local0, PIRB) } // Method(_SRS) } - Device(LNKC) { - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Device(LNKC){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link Name(_UID, 3) Method(_STA, 0) { - And(PIRC, 0x80, Local0) + And(PIRC, 0x80, Local0) If(LEqual(Local0, 0x80)) { - Return(0x09) + Return(0x09) } Else { - Return(0x0B) + Return(0x0B) } } - Method(_PRS) { - Return(BUFA) - } // Method(_PRS) + Method(_PRS) { + Return(BUFA) + } // Method(_PRS) Method(_DIS) { @@ -261,91 +276,89 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) } Method(_CRS) { - And(PIRC, 0x0f, Local0) - ShiftLeft(0x1, Local0, IRQV) - Return(BUFB) + And(PIRC, 0x0f, Local0) + ShiftLeft(0x1, Local0, IRQV) + Return(BUFB) } // Method(_CRS) Method(_SRS, 1) { - CreateWordField(ARG0, 0x01, IRQ1) - FindSetRightBit(IRQ1, Local0) - Decrement(Local0) - Store(Local0, PIRC) + CreateWordField(ARG0, 0x01, IRQ1) + FindSetRightBit(IRQ1, Local0) + Decrement(Local0) + Store(Local0, PIRC) } // Method(_SRS) } - Device(LNKD) { - Name(_HID, EISAID("PNP0C0F")) + Device(LNKD) { + Name(_HID, EISAID("PNP0C0F")) Name(_UID, 4) Method(_STA, 0) { And(PIRD, 0x80, Local0) If(LEqual(Local0, 0x80)) { - Return(0x09) + Return(0x09) } Else { - Return(0x0B) + Return(0x0B) } } - Method(_PRS) { - Return(BUFA) - } // Method(_PRS) + Method(_PRS) { + Return(BUFA) + } // Method(_PRS) Method(_DIS) { Or(PIRD, 0x80, PIRD) } Method(_CRS) { - And(PIRD, 0x0f, Local0) - ShiftLeft(0x1, Local0, IRQV) - Return(BUFB) + And(PIRD, 0x0f, Local0) + ShiftLeft(0x1, Local0, IRQV) + Return(BUFB) } // Method(_CRS) Method(_SRS, 1) { - CreateWordField(ARG0, 0x01, IRQ1) - FindSetRightBit(IRQ1, Local0) - Decrement(Local0) - Store(Local0, PIRD) + CreateWordField(ARG0, 0x01, IRQ1) + FindSetRightBit(IRQ1, Local0) + Decrement(Local0) + Store(Local0, PIRD) } // Method(_SRS) } Method(_PRT,0) { - If(PICD) {Return(PRTA)} - Return (PRTP) - } // end _PRT - - - Name(PRTP, Package(){ - Package(){0x0000ffff, 0, \_SB.PCI0.LNKA, 0}, // Slot 1, INTA - Package(){0x0000ffff, 1, \_SB.PCI0.LNKB, 0}, // Slot 1, INTB - Package(){0x0000ffff, 2, \_SB.PCI0.LNKC, 0}, // Slot 1, INTC - Package(){0x0000ffff, 3, \_SB.PCI0.LNKD, 0}, // Slot 1, INTD + If(PICD) {Return(PRTA)} + Return (PRTP) + } // end _PRT - Package(){0x0001ffff, 0, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB - Package(){0x0001ffff, 1, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC - Package(){0x0001ffff, 2, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD - Package(){0x0001ffff, 3, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA + Name(PRTP, Package(){ + Package(){0x0000ffff, 0, \_SB.PCI0.LNKA, 0}, // Slot 1, INTA + Package(){0x0000ffff, 1, \_SB.PCI0.LNKB, 0}, // Slot 1, INTB + Package(){0x0000ffff, 2, \_SB.PCI0.LNKC, 0}, // Slot 1, INTC + Package(){0x0000ffff, 3, \_SB.PCI0.LNKD, 0}, // Slot 1, INTD + + Package(){0x0001ffff, 0, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB + Package(){0x0001ffff, 1, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC + Package(){0x0001ffff, 2, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD + Package(){0x0001ffff, 3, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA - Package(){0x0002ffff, 0, \_SB.PCI0.LNKC, 0}, // Slot 3, INTC - Package(){0x0002ffff, 1, \_SB.PCI0.LNKD, 0}, // Slot 3, INTD - Package(){0x0002ffff, 2, \_SB.PCI0.LNKA, 0}, // Slot 3, INTA - Package(){0x0002ffff, 3, \_SB.PCI0.LNKB, 0}, // Slot 3, INTB + Package(){0x0002ffff, 0, \_SB.PCI0.LNKC, 0}, // Slot 3, INTC + Package(){0x0002ffff, 1, \_SB.PCI0.LNKD, 0}, // Slot 3, INTD + Package(){0x0002ffff, 2, \_SB.PCI0.LNKA, 0}, // Slot 3, INTA + Package(){0x0002ffff, 3, \_SB.PCI0.LNKB, 0}, // Slot 3, INTB - Package(){0x0003ffff, 0, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD - Package(){0x0003ffff, 1, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA - Package(){0x0003ffff, 2, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB - Package(){0x0003ffff, 3, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC + Package(){0x0003ffff, 0, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD + Package(){0x0003ffff, 1, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA + Package(){0x0003ffff, 2, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB + Package(){0x0003ffff, 3, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC } ) - Name(PRTA, Package(){ - Package(){0x0001ffff, 0, 0, 5}, // Device 1, INTA + Name(PRTA, Package(){ + Package(){0x0001ffff, 0, 0, 5}, // Device 1, INTA - Package(){0x0002ffff, 0, 0, 7}, // Device 2, INTA + Package(){0x0002ffff, 0, 0, 7}, // Device 2, INTA - Package(){0x0003ffff, 0, 0, 10}, // Device 3, INTA + Package(){0x0003ffff, 0, 0, 10}, // Device 3, INTA - Package(){0x0003ffff, 0, 0, 11}, // Device 4, INTA - + Package(){0x0004ffff, 0, 0, 11}, // Device 4, INTA } ) @@ -354,22 +367,22 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) { Name (_ADR, 0x00000000) /* device id, PCI bus num, ... */ - OperationRegion(PIRQ, PCI_Config, 0x60, 0x4) + OperationRegion(PIRQ, PCI_Config, 0x60, 0x4) Scope(\) { - Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) { + Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) { PIRA, 8, PIRB, 8, PIRC, 8, PIRD, 8 } - } + } Device (SYSR) { Name (_HID, EisaId ("PNP0C02")) Name (_UID, 0x01) Name (CRS, ResourceTemplate () { - /* TODO: list hidden resources */ + /* TODO: list hidden resources */ IO (Decode16, 0x0010, 0x0010, 0x00, 0x10) IO (Decode16, 0x0022, 0x0022, 0x00, 0x0C) IO (Decode16, 0x0030, 0x0030, 0x00, 0x10) @@ -417,7 +430,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006) IO (Decode16, 0x0089, 0x0089, 0x00, 0x03) IO (Decode16, 0x008F, 0x008F, 0x00, 0x01) IO (Decode16, 0x00C0, 0x00C0, 0x00, 0x20) - IO (Decode16, 0x0480, 0x0480, 0x00, 0x10) + IO (Decode16, 0x0480, 0x0480, 0x00, 0x10) }) } diff --git a/tools/firmware/acpi/acpi_dsdt.c b/tools/firmware/acpi/acpi_dsdt.c index d9255166d1..fb9dcdcc3f 100644 --- a/tools/firmware/acpi/acpi_dsdt.c +++ b/tools/firmware/acpi/acpi_dsdt.c @@ -5,15 +5,15 @@ * Copyright (C) 2000 - 2005 Intel Corporation * Supports ACPI Specification Revision 3.0 * - * Compilation of "acpi_dsdt.asl" - Mon Jun 12 22:33:41 2006 + * Compilation of "acpi_dsdt.asl" - Thu Aug 3 11:05:15 2006 * * C source code output * */ unsigned char AmlCode[] = { - 0x44,0x53,0x44,0x54,0xC3,0x08,0x00,0x00, /* 00000000 "DSDT...." */ - 0x01,0x0C,0x49,0x4E,0x54,0x45,0x4C,0x00, /* 00000008 "..INTEL." */ + 0x44,0x53,0x44,0x54,0x0E,0x09,0x00,0x00, /* 00000000 "DSDT...." */ + 0x01,0x03,0x49,0x4E,0x54,0x45,0x4C,0x00, /* 00000008 "..INTEL." */ 0x69,0x6E,0x74,0x2D,0x78,0x65,0x6E,0x00, /* 00000010 "int-xen." */ 0xD6,0x07,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ 0x13,0x05,0x05,0x20,0x08,0x50,0x4D,0x42, /* 00000020 "... .PMB" */ @@ -34,264 +34,273 @@ unsigned char AmlCode[] = 0x12,0x08,0x04,0x0A,0x07,0x0A,0x07,0x00, /* 00000098 "........" */ 0x00,0x08,0x50,0x49,0x43,0x44,0x00,0x14, /* 000000A0 "..PICD.." */ 0x0C,0x5F,0x50,0x49,0x43,0x01,0x70,0x68, /* 000000A8 "._PIC.ph" */ - 0x50,0x49,0x43,0x44,0x10,0x4E,0x80,0x5F, /* 000000B0 "PICD.N._" */ - 0x53,0x42,0x5F,0x5B,0x82,0x46,0x80,0x50, /* 000000B8 "SB_[.F.P" */ - 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 000000C0 "CI0._HID" */ - 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x55, /* 000000C8 ".A...._U" */ - 0x49,0x44,0x00,0x08,0x5F,0x41,0x44,0x52, /* 000000D0 "ID.._ADR" */ - 0x00,0x08,0x5F,0x42,0x42,0x4E,0x00,0x5B, /* 000000D8 ".._BBN.[" */ - 0x80,0x50,0x49,0x52,0x50,0x02,0x0A,0x3C, /* 000000E0 ".PIRP..<" */ - 0x0A,0x10,0x5B,0x81,0x24,0x50,0x49,0x52, /* 000000E8 "..[.$PIR" */ - 0x50,0x01,0x49,0x52,0x51,0x33,0x03,0x49, /* 000000F0 "P.IRQ3.I" */ - 0x52,0x51,0x35,0x05,0x49,0x52,0x51,0x37, /* 000000F8 "RQ5.IRQ7" */ - 0x07,0x49,0x52,0x51,0x39,0x09,0x49,0x52, /* 00000100 ".IRQ9.IR" */ - 0x51,0x41,0x0A,0x49,0x52,0x51,0x42,0x0B, /* 00000108 "QA.IRQB." */ - 0x14,0x48,0x0D,0x5F,0x43,0x52,0x53,0x00, /* 00000110 ".H._CRS." */ - 0x08,0x50,0x52,0x54,0x30,0x11,0x46,0x0C, /* 00000118 ".PRT0.F." */ - 0x0A,0xC2,0x88,0x0D,0x00,0x02,0x0F,0x00, /* 00000120 "........" */ - 0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, /* 00000128 "........" */ - 0x00,0x01,0x47,0x01,0xF8,0x0C,0xF8,0x0C, /* 00000130 "..G....." */ - 0x01,0x08,0x88,0x0D,0x00,0x01,0x0C,0x03, /* 00000138 "........" */ - 0x00,0x00,0x00,0x00,0xF7,0x0C,0x00,0x00, /* 00000140 "........" */ - 0xF8,0x0C,0x88,0x0D,0x00,0x01,0x0C,0x03, /* 00000148 "........" */ - 0x00,0x00,0x00,0x0D,0xFF,0x0F,0x00,0x00, /* 00000150 "........" */ - 0x00,0x03,0x88,0x0D,0x00,0x01,0x0D,0x03, /* 00000158 "........" */ - 0x00,0x00,0x00,0xC0,0x1F,0xC0,0x00,0x00, /* 00000160 "........" */ - 0x20,0x00,0x88,0x0D,0x00,0x01,0x0D,0x03, /* 00000168 " ......." */ - 0x00,0x00,0x20,0xC0,0x3F,0xC0,0x00,0x00, /* 00000170 ".. .?..." */ - 0x10,0x00,0x87,0x17,0x00,0x00,0x0C,0x02, /* 00000178 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00, /* 00000180 "........" */ - 0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00, /* 00000188 "........" */ - 0x00,0x00,0x03,0x00,0x87,0x17,0x00,0x00, /* 00000190 "........" */ - 0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000198 "........" */ - 0x00,0xF0,0xFF,0xFF,0xFF,0xF1,0x00,0x00, /* 000001A0 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x02,0x87,0x17, /* 000001A8 "........" */ - 0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 000001B0 "........" */ - 0x00,0x00,0x00,0xF2,0xFF,0x0F,0x00,0xF2, /* 000001B8 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00, /* 000001C0 "........" */ - 0x87,0x17,0x00,0x00,0x0D,0x03,0x00,0x00, /* 000001C8 "........" */ - 0x00,0x00,0x00,0x10,0x00,0xF2,0x1F,0x10, /* 000001D0 "........" */ - 0x00,0xF2,0x00,0x00,0x00,0x00,0x20,0x00, /* 000001D8 "...... ." */ - 0x00,0x00,0x79,0x00,0xA4,0x50,0x52,0x54, /* 000001E0 "..y..PRT" */ - 0x30,0x08,0x42,0x55,0x46,0x41,0x11,0x09, /* 000001E8 "0.BUFA.." */ - 0x0A,0x06,0x23,0xF8,0xDC,0x18,0x79,0x00, /* 000001F0 "..#...y." */ - 0x08,0x42,0x55,0x46,0x42,0x11,0x09,0x0A, /* 000001F8 ".BUFB..." */ - 0x06,0x23,0x00,0x00,0x18,0x79,0x00,0x8B, /* 00000200 ".#...y.." */ - 0x42,0x55,0x46,0x42,0x01,0x49,0x52,0x51, /* 00000208 "BUFB.IRQ" */ - 0x56,0x08,0x42,0x55,0x46,0x43,0x11,0x07, /* 00000210 "V.BUFC.." */ - 0x0A,0x04,0x05,0x07,0x0A,0x0B,0x8C,0x42, /* 00000218 ".......B" */ - 0x55,0x46,0x43,0x01,0x50,0x49,0x51,0x41, /* 00000220 "UFC.PIQA" */ - 0x8C,0x42,0x55,0x46,0x43,0x01,0x50,0x49, /* 00000228 ".BUFC.PI" */ - 0x51,0x42,0x8C,0x42,0x55,0x46,0x43,0x01, /* 00000230 "QB.BUFC." */ - 0x50,0x49,0x51,0x43,0x8C,0x42,0x55,0x46, /* 00000238 "PIQC.BUF" */ - 0x43,0x01,0x50,0x49,0x51,0x44,0x5B,0x82, /* 00000240 "C.PIQD[." */ - 0x48,0x08,0x4C,0x4E,0x4B,0x41,0x08,0x5F, /* 00000248 "H.LNKA._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 00000250 "HID.A..." */ - 0x08,0x5F,0x55,0x49,0x44,0x01,0x14,0x1C, /* 00000258 "._UID..." */ - 0x5F,0x53,0x54,0x41,0x00,0x7B,0x50,0x49, /* 00000260 "_STA.{PI" */ - 0x52,0x41,0x0A,0x80,0x60,0xA0,0x08,0x93, /* 00000268 "RA..`..." */ - 0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04, /* 00000270 "`......." */ - 0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52, /* 00000278 "....._PR" */ - 0x53,0x00,0xA4,0x42,0x55,0x46,0x41,0x14, /* 00000280 "S..BUFA." */ - 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000288 "._DIS.}P" */ - 0x49,0x52,0x41,0x0A,0x80,0x50,0x49,0x52, /* 00000290 "IRA..PIR" */ - 0x41,0x14,0x1A,0x5F,0x43,0x52,0x53,0x00, /* 00000298 "A.._CRS." */ - 0x7B,0x50,0x49,0x52,0x42,0x0A,0x0F,0x60, /* 000002A0 "{PIRB..`" */ - 0x79,0x01,0x60,0x49,0x52,0x51,0x56,0xA4, /* 000002A8 "y.`IRQV." */ - 0x42,0x55,0x46,0x42,0x14,0x1B,0x5F,0x53, /* 000002B0 "BUFB.._S" */ - 0x52,0x53,0x01,0x8B,0x68,0x01,0x49,0x52, /* 000002B8 "RS..h.IR" */ - 0x51,0x31,0x82,0x49,0x52,0x51,0x31,0x60, /* 000002C0 "Q1.IRQ1`" */ - 0x76,0x60,0x70,0x60,0x50,0x49,0x52,0x41, /* 000002C8 "v`p`PIRA" */ - 0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B,0x42, /* 000002D0 "[.I.LNKB" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000002D8 "._HID.A." */ - 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000002E0 "..._UID." */ - 0x02,0x14,0x1C,0x5F,0x53,0x54,0x41,0x00, /* 000002E8 "..._STA." */ - 0x7B,0x50,0x49,0x52,0x42,0x0A,0x80,0x60, /* 000002F0 "{PIRB..`" */ - 0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A, /* 000002F8 "...`...." */ - 0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B, /* 00000300 "........" */ - 0x5F,0x50,0x52,0x53,0x00,0xA4,0x42,0x55, /* 00000308 "_PRS..BU" */ - 0x46,0x41,0x14,0x11,0x5F,0x44,0x49,0x53, /* 00000310 "FA.._DIS" */ - 0x00,0x7D,0x50,0x49,0x52,0x42,0x0A,0x80, /* 00000318 ".}PIRB.." */ - 0x50,0x49,0x52,0x42,0x14,0x1A,0x5F,0x43, /* 00000320 "PIRB.._C" */ - 0x52,0x53,0x00,0x7B,0x50,0x49,0x52,0x42, /* 00000328 "RS.{PIRB" */ - 0x0A,0x0F,0x60,0x79,0x01,0x60,0x49,0x52, /* 00000330 "..`y.`IR" */ - 0x51,0x56,0xA4,0x42,0x55,0x46,0x42,0x14, /* 00000338 "QV.BUFB." */ - 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 00000340 "._SRS..h" */ - 0x01,0x49,0x52,0x51,0x31,0x82,0x49,0x52, /* 00000348 ".IRQ1.IR" */ - 0x51,0x31,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000350 "Q1`v`p`P" */ - 0x49,0x52,0x42,0x5B,0x82,0x49,0x08,0x4C, /* 00000358 "IRB[.I.L" */ - 0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49,0x44, /* 00000360 "NKC._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000368 ".A...._U" */ - 0x49,0x44,0x0A,0x03,0x14,0x1C,0x5F,0x53, /* 00000370 "ID...._S" */ - 0x54,0x41,0x00,0x7B,0x50,0x49,0x52,0x43, /* 00000378 "TA.{PIRC" */ - 0x0A,0x80,0x60,0xA0,0x08,0x93,0x60,0x0A, /* 00000380 "..`...`." */ - 0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A, /* 00000388 "........" */ - 0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53,0x00, /* 00000390 "..._PRS." */ - 0xA4,0x42,0x55,0x46,0x41,0x14,0x11,0x5F, /* 00000398 ".BUFA.._" */ - 0x44,0x49,0x53,0x00,0x7D,0x50,0x49,0x52, /* 000003A0 "DIS.}PIR" */ - 0x43,0x0A,0x80,0x50,0x49,0x52,0x43,0x14, /* 000003A8 "C..PIRC." */ - 0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B,0x50, /* 000003B0 "._CRS.{P" */ - 0x49,0x52,0x43,0x0A,0x0F,0x60,0x79,0x01, /* 000003B8 "IRC..`y." */ - 0x60,0x49,0x52,0x51,0x56,0xA4,0x42,0x55, /* 000003C0 "`IRQV.BU" */ - 0x46,0x42,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 000003C8 "FB.._SRS" */ - 0x01,0x8B,0x68,0x01,0x49,0x52,0x51,0x31, /* 000003D0 "..h.IRQ1" */ - 0x82,0x49,0x52,0x51,0x31,0x60,0x76,0x60, /* 000003D8 ".IRQ1`v`" */ - 0x70,0x60,0x50,0x49,0x52,0x43,0x5B,0x82, /* 000003E0 "p`PIRC[." */ - 0x49,0x08,0x4C,0x4E,0x4B,0x44,0x08,0x5F, /* 000003E8 "I.LNKD._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000003F0 "HID.A..." */ - 0x08,0x5F,0x55,0x49,0x44,0x0A,0x04,0x14, /* 000003F8 "._UID..." */ - 0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B,0x50, /* 00000400 "._STA.{P" */ - 0x49,0x52,0x44,0x0A,0x80,0x60,0xA0,0x08, /* 00000408 "IRD..`.." */ - 0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1, /* 00000410 ".`......" */ - 0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50, /* 00000418 "......_P" */ - 0x52,0x53,0x00,0xA4,0x42,0x55,0x46,0x41, /* 00000420 "RS..BUFA" */ - 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00000428 ".._DIS.}" */ - 0x50,0x49,0x52,0x44,0x0A,0x80,0x50,0x49, /* 00000430 "PIRD..PI" */ - 0x52,0x44,0x14,0x1A,0x5F,0x43,0x52,0x53, /* 00000438 "RD.._CRS" */ - 0x00,0x7B,0x50,0x49,0x52,0x44,0x0A,0x0F, /* 00000440 ".{PIRD.." */ - 0x60,0x79,0x01,0x60,0x49,0x52,0x51,0x56, /* 00000448 "`y.`IRQV" */ - 0xA4,0x42,0x55,0x46,0x42,0x14,0x1B,0x5F, /* 00000450 ".BUFB.._" */ - 0x53,0x52,0x53,0x01,0x8B,0x68,0x01,0x49, /* 00000458 "SRS..h.I" */ - 0x52,0x51,0x31,0x82,0x49,0x52,0x51,0x31, /* 00000460 "RQ1.IRQ1" */ - 0x60,0x76,0x60,0x70,0x60,0x50,0x49,0x52, /* 00000468 "`v`p`PIR" */ - 0x44,0x14,0x16,0x5F,0x50,0x52,0x54,0x00, /* 00000470 "D.._PRT." */ - 0xA0,0x0A,0x50,0x49,0x43,0x44,0xA4,0x50, /* 00000478 "..PICD.P" */ - 0x52,0x54,0x41,0xA4,0x50,0x52,0x54,0x50, /* 00000480 "RTA.PRTP" */ - 0x08,0x50,0x52,0x54,0x50,0x12,0x43,0x0E, /* 00000488 ".PRTP.C." */ - 0x10,0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x00, /* 00000490 "........" */ - 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0B,0x04, /* 00000498 "LNKA...." */ - 0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B,0x42, /* 000004A0 "....LNKB" */ - 0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A, /* 000004A8 "........" */ - 0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0C, /* 000004B0 ".LNKC..." */ - 0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C,0x4E, /* 000004B8 "......LN" */ - 0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000004C0 "KD......" */ - 0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B,0x42, /* 000004C8 "....LNKB" */ - 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01, /* 000004D0 "........" */ - 0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000004D8 "..LNKC.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 000004E0 "........" */ - 0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000004E8 ".LNKD..." */ - 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03, /* 000004F0 "........" */ - 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04, /* 000004F8 "LNKA...." */ - 0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C,0x4E, /* 00000500 "......LN" */ - 0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 00000508 "KC......" */ - 0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B,0x44, /* 00000510 "....LNKD" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000518 "........" */ - 0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00, /* 00000520 "...LNKA." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000528 "........" */ - 0x0A,0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000530 "..LNKB.." */ - 0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00,0x00, /* 00000538 "........" */ - 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04, /* 00000540 "LNKD...." */ - 0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C,0x4E, /* 00000548 "......LN" */ - 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000550 "KA......" */ - 0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E,0x4B, /* 00000558 ".....LNK" */ - 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000560 "B......." */ - 0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43, /* 00000568 "....LNKC" */ - 0x00,0x08,0x50,0x52,0x54,0x41,0x12,0x32, /* 00000570 "..PRTA.2" */ - 0x04,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x01, /* 00000578 "........" */ - 0x00,0x00,0x00,0x0A,0x05,0x12,0x0B,0x04, /* 00000580 "........" */ - 0x0C,0xFF,0xFF,0x02,0x00,0x00,0x00,0x0A, /* 00000588 "........" */ - 0x07,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x03, /* 00000590 "........" */ - 0x00,0x00,0x00,0x0A,0x0A,0x12,0x0B,0x04, /* 00000598 "........" */ - 0x0C,0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A, /* 000005A0 "........" */ - 0x0B,0x5B,0x82,0x48,0x31,0x49,0x53,0x41, /* 000005A8 ".[.H1ISA" */ - 0x5F,0x08,0x5F,0x41,0x44,0x52,0x00,0x5B, /* 000005B0 "_._ADR.[" */ - 0x80,0x50,0x49,0x52,0x51,0x02,0x0A,0x60, /* 000005B8 ".PIRQ..`" */ - 0x0A,0x04,0x10,0x2E,0x5C,0x00,0x5B,0x81, /* 000005C0 "....\.[." */ - 0x29,0x5C,0x2F,0x04,0x5F,0x53,0x42,0x5F, /* 000005C8 ")\/._SB_" */ - 0x50,0x43,0x49,0x30,0x49,0x53,0x41,0x5F, /* 000005D0 "PCI0ISA_" */ - 0x50,0x49,0x52,0x51,0x01,0x50,0x49,0x52, /* 000005D8 "PIRQ.PIR" */ - 0x41,0x08,0x50,0x49,0x52,0x42,0x08,0x50, /* 000005E0 "A.PIRB.P" */ - 0x49,0x52,0x43,0x08,0x50,0x49,0x52,0x44, /* 000005E8 "IRC.PIRD" */ - 0x08,0x5B,0x82,0x46,0x0B,0x53,0x59,0x53, /* 000005F0 ".[.F.SYS" */ - 0x52,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 000005F8 "R._HID.A" */ - 0xD0,0x0C,0x02,0x08,0x5F,0x55,0x49,0x44, /* 00000600 "...._UID" */ - 0x01,0x08,0x43,0x52,0x53,0x5F,0x11,0x4E, /* 00000608 "..CRS_.N" */ - 0x08,0x0A,0x8A,0x47,0x01,0x10,0x00,0x10, /* 00000610 "...G...." */ - 0x00,0x00,0x10,0x47,0x01,0x22,0x00,0x22, /* 00000618 "...G."."" */ - 0x00,0x00,0x0C,0x47,0x01,0x30,0x00,0x30, /* 00000620 "...G.0.0" */ - 0x00,0x00,0x10,0x47,0x01,0x44,0x00,0x44, /* 00000628 "...G.D.D" */ - 0x00,0x00,0x1C,0x47,0x01,0x62,0x00,0x62, /* 00000630 "...G.b.b" */ - 0x00,0x00,0x02,0x47,0x01,0x65,0x00,0x65, /* 00000638 "...G.e.e" */ - 0x00,0x00,0x0B,0x47,0x01,0x72,0x00,0x72, /* 00000640 "...G.r.r" */ - 0x00,0x00,0x0E,0x47,0x01,0x80,0x00,0x80, /* 00000648 "...G...." */ - 0x00,0x00,0x01,0x47,0x01,0x84,0x00,0x84, /* 00000650 "...G...." */ - 0x00,0x00,0x03,0x47,0x01,0x88,0x00,0x88, /* 00000658 "...G...." */ - 0x00,0x00,0x01,0x47,0x01,0x8C,0x00,0x8C, /* 00000660 "...G...." */ - 0x00,0x00,0x03,0x47,0x01,0x90,0x00,0x90, /* 00000668 "...G...." */ - 0x00,0x00,0x10,0x47,0x01,0xA2,0x00,0xA2, /* 00000670 "...G...." */ - 0x00,0x00,0x1C,0x47,0x01,0xE0,0x00,0xE0, /* 00000678 "...G...." */ - 0x00,0x00,0x10,0x47,0x01,0xA0,0x08,0xA0, /* 00000680 "...G...." */ - 0x08,0x00,0x04,0x47,0x01,0xC0,0x0C,0xC0, /* 00000688 "...G...." */ - 0x0C,0x00,0x10,0x47,0x01,0xD0,0x04,0xD0, /* 00000690 "...G...." */ - 0x04,0x00,0x02,0x79,0x00,0x14,0x0B,0x5F, /* 00000698 "...y..._" */ - 0x43,0x52,0x53,0x00,0xA4,0x43,0x52,0x53, /* 000006A0 "CRS..CRS" */ - 0x5F,0x5B,0x82,0x2B,0x50,0x49,0x43,0x5F, /* 000006A8 "_[.+PIC_" */ - 0x08,0x5F,0x48,0x49,0x44,0x0B,0x41,0xD0, /* 000006B0 "._HID.A." */ - 0x08,0x5F,0x43,0x52,0x53,0x11,0x18,0x0A, /* 000006B8 "._CRS..." */ - 0x15,0x47,0x01,0x20,0x00,0x20,0x00,0x01, /* 000006C0 ".G. . .." */ - 0x02,0x47,0x01,0xA0,0x00,0xA0,0x00,0x01, /* 000006C8 ".G......" */ - 0x02,0x22,0x04,0x00,0x79,0x00,0x5B,0x82, /* 000006D0 "."..y.[." */ - 0x47,0x05,0x44,0x4D,0x41,0x30,0x08,0x5F, /* 000006D8 "G.DMA0._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x02,0x00, /* 000006E0 "HID.A..." */ - 0x08,0x5F,0x43,0x52,0x53,0x11,0x41,0x04, /* 000006E8 "._CRS.A." */ - 0x0A,0x3D,0x2A,0x10,0x04,0x47,0x01,0x00, /* 000006F0 ".=*..G.." */ - 0x00,0x00,0x00,0x00,0x10,0x47,0x01,0x81, /* 000006F8 ".....G.." */ - 0x00,0x81,0x00,0x00,0x03,0x47,0x01,0x87, /* 00000700 ".....G.." */ - 0x00,0x87,0x00,0x00,0x01,0x47,0x01,0x89, /* 00000708 ".....G.." */ - 0x00,0x89,0x00,0x00,0x03,0x47,0x01,0x8F, /* 00000710 ".....G.." */ - 0x00,0x8F,0x00,0x00,0x01,0x47,0x01,0xC0, /* 00000718 ".....G.." */ - 0x00,0xC0,0x00,0x00,0x20,0x47,0x01,0x80, /* 00000720 ".... G.." */ - 0x04,0x80,0x04,0x00,0x10,0x79,0x00,0x5B, /* 00000728 ".....y.[" */ - 0x82,0x25,0x54,0x4D,0x52,0x5F,0x08,0x5F, /* 00000730 ".%TMR_._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x01,0x00, /* 00000738 "HID.A..." */ - 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 00000740 "._CRS..." */ - 0x0D,0x47,0x01,0x40,0x00,0x40,0x00,0x00, /* 00000748 ".G.@.@.." */ - 0x04,0x22,0x01,0x00,0x79,0x00,0x5B,0x82, /* 00000750 "."..y.[." */ - 0x25,0x52,0x54,0x43,0x5F,0x08,0x5F,0x48, /* 00000758 "%RTC_._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x0B,0x00,0x08, /* 00000760 "ID.A...." */ - 0x5F,0x43,0x52,0x53,0x11,0x10,0x0A,0x0D, /* 00000768 "_CRS...." */ - 0x47,0x01,0x70,0x00,0x70,0x00,0x00,0x02, /* 00000770 "G.p.p..." */ - 0x22,0x00,0x01,0x79,0x00,0x5B,0x82,0x22, /* 00000778 ""..y.[."" */ - 0x53,0x50,0x4B,0x52,0x08,0x5F,0x48,0x49, /* 00000780 "SPKR._HI" */ - 0x44,0x0C,0x41,0xD0,0x08,0x00,0x08,0x5F, /* 00000788 "D.A...._" */ - 0x43,0x52,0x53,0x11,0x0D,0x0A,0x0A,0x47, /* 00000790 "CRS....G" */ - 0x01,0x61,0x00,0x61,0x00,0x00,0x01,0x79, /* 00000798 ".a.a...y" */ - 0x00,0x5B,0x82,0x31,0x50,0x53,0x32,0x4D, /* 000007A0 ".[.1PS2M" */ + 0x50,0x49,0x43,0x44,0x10,0x49,0x85,0x5F, /* 000000B0 "PICD.I._" */ + 0x53,0x42,0x5F,0x5B,0x82,0x49,0x04,0x4D, /* 000000B8 "SB_[.I.M" */ + 0x45,0x4D,0x30,0x08,0x5F,0x48,0x49,0x44, /* 000000C0 "EM0._HID" */ + 0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F,0x43, /* 000000C8 ".A...._C" */ + 0x52,0x53,0x11,0x33,0x0A,0x30,0x8A,0x2B, /* 000000D0 "RS.3.0.+" */ + 0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 000000D8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x09,0x00, /* 000000E8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00, /* 000000F8 "........" */ + 0x00,0x00,0x00,0x00,0x79,0x00,0x5B,0x82, /* 00000100 "....y.[." */ + 0x46,0x80,0x50,0x43,0x49,0x30,0x08,0x5F, /* 00000108 "F.PCI0._" */ + 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03, /* 00000110 "HID.A..." */ + 0x08,0x5F,0x55,0x49,0x44,0x00,0x08,0x5F, /* 00000118 "._UID.._" */ + 0x41,0x44,0x52,0x00,0x08,0x5F,0x42,0x42, /* 00000120 "ADR.._BB" */ + 0x4E,0x00,0x5B,0x80,0x50,0x49,0x52,0x50, /* 00000128 "N.[.PIRP" */ + 0x02,0x0A,0x3C,0x0A,0x10,0x5B,0x81,0x24, /* 00000130 "..<..[.$" */ + 0x50,0x49,0x52,0x50,0x01,0x49,0x52,0x51, /* 00000138 "PIRP.IRQ" */ + 0x33,0x03,0x49,0x52,0x51,0x35,0x05,0x49, /* 00000140 "3.IRQ5.I" */ + 0x52,0x51,0x37,0x07,0x49,0x52,0x51,0x39, /* 00000148 "RQ7.IRQ9" */ + 0x09,0x49,0x52,0x51,0x41,0x0A,0x49,0x52, /* 00000150 ".IRQA.IR" */ + 0x51,0x42,0x0B,0x14,0x48,0x0D,0x5F,0x43, /* 00000158 "QB..H._C" */ + 0x52,0x53,0x00,0x08,0x50,0x52,0x54,0x30, /* 00000160 "RS..PRT0" */ + 0x11,0x46,0x0C,0x0A,0xC2,0x88,0x0D,0x00, /* 00000168 ".F......" */ + 0x02,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF, /* 00000170 "........" */ + 0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8, /* 00000178 ".....G.." */ + 0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00, /* 00000180 "........" */ + 0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7, /* 00000188 "........" */ + 0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00, /* 00000190 "........" */ + 0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF, /* 00000198 "........" */ + 0x0F,0x00,0x00,0x00,0x03,0x88,0x0D,0x00, /* 000001A0 "........" */ + 0x01,0x0D,0x03,0x00,0x00,0x00,0xC0,0x1F, /* 000001A8 "........" */ + 0xC0,0x00,0x00,0x20,0x00,0x88,0x0D,0x00, /* 000001B0 "... ...." */ + 0x01,0x0D,0x03,0x00,0x00,0x20,0xC0,0x3F, /* 000001B8 "..... .?" */ + 0xC0,0x00,0x00,0x10,0x00,0x87,0x17,0x00, /* 000001C0 "........" */ + 0x00,0x0C,0x02,0x00,0x00,0x00,0x00,0x00, /* 000001C8 "........" */ + 0x00,0x0C,0x00,0xFF,0xFF,0x0F,0x00,0x00, /* 000001D0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x87, /* 000001D8 "........" */ + 0x17,0x00,0x00,0x0D,0x03,0x00,0x00,0x00, /* 000001E0 "........" */ + 0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF, /* 000001E8 "........" */ + 0xF1,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000001F0 "........" */ + 0x02,0x87,0x17,0x00,0x00,0x0D,0x03,0x00, /* 000001F8 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0xF2,0xFF, /* 00000200 "........" */ + 0x0F,0x00,0xF2,0x00,0x00,0x00,0x00,0x00, /* 00000208 "........" */ + 0x10,0x00,0x00,0x87,0x17,0x00,0x00,0x0D, /* 00000210 "........" */ + 0x03,0x00,0x00,0x00,0x00,0x00,0x10,0x00, /* 00000218 "........" */ + 0xF2,0x1F,0x10,0x00,0xF2,0x00,0x00,0x00, /* 00000220 "........" */ + 0x00,0x20,0x00,0x00,0x00,0x79,0x00,0xA4, /* 00000228 ". ...y.." */ + 0x50,0x52,0x54,0x30,0x08,0x42,0x55,0x46, /* 00000230 "PRT0.BUF" */ + 0x41,0x11,0x09,0x0A,0x06,0x23,0xF8,0xDC, /* 00000238 "A....#.." */ + 0x18,0x79,0x00,0x08,0x42,0x55,0x46,0x42, /* 00000240 ".y..BUFB" */ + 0x11,0x09,0x0A,0x06,0x23,0x00,0x00,0x18, /* 00000248 "....#..." */ + 0x79,0x00,0x8B,0x42,0x55,0x46,0x42,0x01, /* 00000250 "y..BUFB." */ + 0x49,0x52,0x51,0x56,0x08,0x42,0x55,0x46, /* 00000258 "IRQV.BUF" */ + 0x43,0x11,0x07,0x0A,0x04,0x05,0x07,0x0A, /* 00000260 "C......." */ + 0x0B,0x8C,0x42,0x55,0x46,0x43,0x01,0x50, /* 00000268 "..BUFC.P" */ + 0x49,0x51,0x41,0x8C,0x42,0x55,0x46,0x43, /* 00000270 "IQA.BUFC" */ + 0x01,0x50,0x49,0x51,0x42,0x8C,0x42,0x55, /* 00000278 ".PIQB.BU" */ + 0x46,0x43,0x01,0x50,0x49,0x51,0x43,0x8C, /* 00000280 "FC.PIQC." */ + 0x42,0x55,0x46,0x43,0x01,0x50,0x49,0x51, /* 00000288 "BUFC.PIQ" */ + 0x44,0x5B,0x82,0x48,0x08,0x4C,0x4E,0x4B, /* 00000290 "D[.H.LNK" */ + 0x41,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000298 "A._HID.A" */ + 0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 000002A0 "...._UID" */ + 0x01,0x14,0x1C,0x5F,0x53,0x54,0x41,0x00, /* 000002A8 "..._STA." */ + 0x7B,0x50,0x49,0x52,0x41,0x0A,0x80,0x60, /* 000002B0 "{PIRA..`" */ + 0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A, /* 000002B8 "...`...." */ + 0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B, /* 000002C0 "........" */ + 0x5F,0x50,0x52,0x53,0x00,0xA4,0x42,0x55, /* 000002C8 "_PRS..BU" */ + 0x46,0x41,0x14,0x11,0x5F,0x44,0x49,0x53, /* 000002D0 "FA.._DIS" */ + 0x00,0x7D,0x50,0x49,0x52,0x41,0x0A,0x80, /* 000002D8 ".}PIRA.." */ + 0x50,0x49,0x52,0x41,0x14,0x1A,0x5F,0x43, /* 000002E0 "PIRA.._C" */ + 0x52,0x53,0x00,0x7B,0x50,0x49,0x52,0x42, /* 000002E8 "RS.{PIRB" */ + 0x0A,0x0F,0x60,0x79,0x01,0x60,0x49,0x52, /* 000002F0 "..`y.`IR" */ + 0x51,0x56,0xA4,0x42,0x55,0x46,0x42,0x14, /* 000002F8 "QV.BUFB." */ + 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 00000300 "._SRS..h" */ + 0x01,0x49,0x52,0x51,0x31,0x82,0x49,0x52, /* 00000308 ".IRQ1.IR" */ + 0x51,0x31,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000310 "Q1`v`p`P" */ + 0x49,0x52,0x41,0x5B,0x82,0x49,0x08,0x4C, /* 00000318 "IRA[.I.L" */ + 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000320 "NKB._HID" */ + 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000328 ".A...._U" */ + 0x49,0x44,0x0A,0x02,0x14,0x1C,0x5F,0x53, /* 00000330 "ID...._S" */ + 0x54,0x41,0x00,0x7B,0x50,0x49,0x52,0x42, /* 00000338 "TA.{PIRB" */ + 0x0A,0x80,0x60,0xA0,0x08,0x93,0x60,0x0A, /* 00000340 "..`...`." */ + 0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A, /* 00000348 "........" */ + 0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53,0x00, /* 00000350 "..._PRS." */ + 0xA4,0x42,0x55,0x46,0x41,0x14,0x11,0x5F, /* 00000358 ".BUFA.._" */ + 0x44,0x49,0x53,0x00,0x7D,0x50,0x49,0x52, /* 00000360 "DIS.}PIR" */ + 0x42,0x0A,0x80,0x50,0x49,0x52,0x42,0x14, /* 00000368 "B..PIRB." */ + 0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B,0x50, /* 00000370 "._CRS.{P" */ + 0x49,0x52,0x42,0x0A,0x0F,0x60,0x79,0x01, /* 00000378 "IRB..`y." */ + 0x60,0x49,0x52,0x51,0x56,0xA4,0x42,0x55, /* 00000380 "`IRQV.BU" */ + 0x46,0x42,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000388 "FB.._SRS" */ + 0x01,0x8B,0x68,0x01,0x49,0x52,0x51,0x31, /* 00000390 "..h.IRQ1" */ + 0x82,0x49,0x52,0x51,0x31,0x60,0x76,0x60, /* 00000398 ".IRQ1`v`" */ + 0x70,0x60,0x50,0x49,0x52,0x42,0x5B,0x82, /* 000003A0 "p`PIRB[." */ + 0x49,0x08,0x4C,0x4E,0x4B,0x43,0x08,0x5F, /* 000003A8 "I.LNKC._" */ + 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000003B0 "HID.A..." */ + 0x08,0x5F,0x55,0x49,0x44,0x0A,0x03,0x14, /* 000003B8 "._UID..." */ + 0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B,0x50, /* 000003C0 "._STA.{P" */ + 0x49,0x52,0x43,0x0A,0x80,0x60,0xA0,0x08, /* 000003C8 "IRC..`.." */ + 0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1, /* 000003D0 ".`......" */ + 0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50, /* 000003D8 "......_P" */ + 0x52,0x53,0x00,0xA4,0x42,0x55,0x46,0x41, /* 000003E0 "RS..BUFA" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000003E8 ".._DIS.}" */ + 0x50,0x49,0x52,0x43,0x0A,0x80,0x50,0x49, /* 000003F0 "PIRC..PI" */ + 0x52,0x43,0x14,0x1A,0x5F,0x43,0x52,0x53, /* 000003F8 "RC.._CRS" */ + 0x00,0x7B,0x50,0x49,0x52,0x43,0x0A,0x0F, /* 00000400 ".{PIRC.." */ + 0x60,0x79,0x01,0x60,0x49,0x52,0x51,0x56, /* 00000408 "`y.`IRQV" */ + 0xA4,0x42,0x55,0x46,0x42,0x14,0x1B,0x5F, /* 00000410 ".BUFB.._" */ + 0x53,0x52,0x53,0x01,0x8B,0x68,0x01,0x49, /* 00000418 "SRS..h.I" */ + 0x52,0x51,0x31,0x82,0x49,0x52,0x51,0x31, /* 00000420 "RQ1.IRQ1" */ + 0x60,0x76,0x60,0x70,0x60,0x50,0x49,0x52, /* 00000428 "`v`p`PIR" */ + 0x43,0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B, /* 00000430 "C[.I.LNK" */ + 0x44,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000438 "D._HID.A" */ + 0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 00000440 "...._UID" */ + 0x0A,0x04,0x14,0x1C,0x5F,0x53,0x54,0x41, /* 00000448 "...._STA" */ + 0x00,0x7B,0x50,0x49,0x52,0x44,0x0A,0x80, /* 00000450 ".{PIRD.." */ + 0x60,0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4, /* 00000458 "`...`..." */ + 0x0A,0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14, /* 00000460 "........" */ + 0x0B,0x5F,0x50,0x52,0x53,0x00,0xA4,0x42, /* 00000468 "._PRS..B" */ + 0x55,0x46,0x41,0x14,0x11,0x5F,0x44,0x49, /* 00000470 "UFA.._DI" */ + 0x53,0x00,0x7D,0x50,0x49,0x52,0x44,0x0A, /* 00000478 "S.}PIRD." */ + 0x80,0x50,0x49,0x52,0x44,0x14,0x1A,0x5F, /* 00000480 ".PIRD.._" */ + 0x43,0x52,0x53,0x00,0x7B,0x50,0x49,0x52, /* 00000488 "CRS.{PIR" */ + 0x44,0x0A,0x0F,0x60,0x79,0x01,0x60,0x49, /* 00000490 "D..`y.`I" */ + 0x52,0x51,0x56,0xA4,0x42,0x55,0x46,0x42, /* 00000498 "RQV.BUFB" */ + 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000004A0 ".._SRS.." */ + 0x68,0x01,0x49,0x52,0x51,0x31,0x82,0x49, /* 000004A8 "h.IRQ1.I" */ + 0x52,0x51,0x31,0x60,0x76,0x60,0x70,0x60, /* 000004B0 "RQ1`v`p`" */ + 0x50,0x49,0x52,0x44,0x14,0x16,0x5F,0x50, /* 000004B8 "PIRD.._P" */ + 0x52,0x54,0x00,0xA0,0x0A,0x50,0x49,0x43, /* 000004C0 "RT...PIC" */ + 0x44,0xA4,0x50,0x52,0x54,0x41,0xA4,0x50, /* 000004C8 "D.PRTA.P" */ + 0x52,0x54,0x50,0x08,0x50,0x52,0x54,0x50, /* 000004D0 "RTP.PRTP" */ + 0x12,0x43,0x0E,0x10,0x12,0x0B,0x04,0x0B, /* 000004D8 ".C......" */ + 0xFF,0xFF,0x00,0x4C,0x4E,0x4B,0x41,0x00, /* 000004E0 "...LNKA." */ + 0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x01,0x4C, /* 000004E8 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0C,0x04,0x0B, /* 000004F0 "NKB....." */ + 0xFF,0xFF,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000004F8 "....LNKC" */ + 0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A, /* 00000500 "........" */ + 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000508 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x00,0x4C, /* 00000510 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000518 "NKB....." */ + 0xFF,0xFF,0x01,0x00,0x01,0x4C,0x4E,0x4B, /* 00000520 ".....LNK" */ + 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000528 "C......." */ + 0x01,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000530 "....LNKD" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01, /* 00000538 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000540 "...LNKA." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000548 "........" */ + 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000550 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x4C, /* 00000558 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000560 "NKD....." */ + 0xFF,0xFF,0x02,0x00,0x0A,0x02,0x4C,0x4E, /* 00000568 "......LN" */ + 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000570 "KA......" */ + 0xFF,0x02,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000578 ".....LNK" */ + 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000580 "B......." */ + 0x03,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000588 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000590 "........" */ + 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000598 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02, /* 000005A0 "........" */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000005A8 "LNKB...." */ + 0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x03,0x4C, /* 000005B0 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x08,0x50,0x52,0x54, /* 000005B8 "NKC..PRT" */ + 0x41,0x12,0x32,0x04,0x12,0x0B,0x04,0x0C, /* 000005C0 "A.2....." */ + 0xFF,0xFF,0x01,0x00,0x00,0x00,0x0A,0x05, /* 000005C8 "........" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 000005D0 "........" */ + 0x00,0x00,0x0A,0x07,0x12,0x0B,0x04,0x0C, /* 000005D8 "........" */ + 0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A,0x0A, /* 000005E0 "........" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 000005E8 "........" */ + 0x00,0x00,0x0A,0x0B,0x5B,0x82,0x48,0x31, /* 000005F0 "....[.H1" */ + 0x49,0x53,0x41,0x5F,0x08,0x5F,0x41,0x44, /* 000005F8 "ISA_._AD" */ + 0x52,0x00,0x5B,0x80,0x50,0x49,0x52,0x51, /* 00000600 "R.[.PIRQ" */ + 0x02,0x0A,0x60,0x0A,0x04,0x10,0x2E,0x5C, /* 00000608 "..`....\" */ + 0x00,0x5B,0x81,0x29,0x5C,0x2F,0x04,0x5F, /* 00000610 ".[.)\/._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x49, /* 00000618 "SB_PCI0I" */ + 0x53,0x41,0x5F,0x50,0x49,0x52,0x51,0x01, /* 00000620 "SA_PIRQ." */ + 0x50,0x49,0x52,0x41,0x08,0x50,0x49,0x52, /* 00000628 "PIRA.PIR" */ + 0x42,0x08,0x50,0x49,0x52,0x43,0x08,0x50, /* 00000630 "B.PIRC.P" */ + 0x49,0x52,0x44,0x08,0x5B,0x82,0x46,0x0B, /* 00000638 "IRD.[.F." */ + 0x53,0x59,0x53,0x52,0x08,0x5F,0x48,0x49, /* 00000640 "SYSR._HI" */ + 0x44,0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F, /* 00000648 "D.A...._" */ + 0x55,0x49,0x44,0x01,0x08,0x43,0x52,0x53, /* 00000650 "UID..CRS" */ + 0x5F,0x11,0x4E,0x08,0x0A,0x8A,0x47,0x01, /* 00000658 "_.N...G." */ + 0x10,0x00,0x10,0x00,0x00,0x10,0x47,0x01, /* 00000660 "......G." */ + 0x22,0x00,0x22,0x00,0x00,0x0C,0x47,0x01, /* 00000668 ""."...G." */ + 0x30,0x00,0x30,0x00,0x00,0x10,0x47,0x01, /* 00000670 "0.0...G." */ + 0x44,0x00,0x44,0x00,0x00,0x1C,0x47,0x01, /* 00000678 "D.D...G." */ + 0x62,0x00,0x62,0x00,0x00,0x02,0x47,0x01, /* 00000680 "b.b...G." */ + 0x65,0x00,0x65,0x00,0x00,0x0B,0x47,0x01, /* 00000688 "e.e...G." */ + 0x72,0x00,0x72,0x00,0x00,0x0E,0x47,0x01, /* 00000690 "r.r...G." */ + 0x80,0x00,0x80,0x00,0x00,0x01,0x47,0x01, /* 00000698 "......G." */ + 0x84,0x00,0x84,0x00,0x00,0x03,0x47,0x01, /* 000006A0 "......G." */ + 0x88,0x00,0x88,0x00,0x00,0x01,0x47,0x01, /* 000006A8 "......G." */ + 0x8C,0x00,0x8C,0x00,0x00,0x03,0x47,0x01, /* 000006B0 "......G." */ + 0x90,0x00,0x90,0x00,0x00,0x10,0x47,0x01, /* 000006B8 "......G." */ + 0xA2,0x00,0xA2,0x00,0x00,0x1C,0x47,0x01, /* 000006C0 "......G." */ + 0xE0,0x00,0xE0,0x00,0x00,0x10,0x47,0x01, /* 000006C8 "......G." */ + 0xA0,0x08,0xA0,0x08,0x00,0x04,0x47,0x01, /* 000006D0 "......G." */ + 0xC0,0x0C,0xC0,0x0C,0x00,0x10,0x47,0x01, /* 000006D8 "......G." */ + 0xD0,0x04,0xD0,0x04,0x00,0x02,0x79,0x00, /* 000006E0 "......y." */ + 0x14,0x0B,0x5F,0x43,0x52,0x53,0x00,0xA4, /* 000006E8 ".._CRS.." */ + 0x43,0x52,0x53,0x5F,0x5B,0x82,0x2B,0x50, /* 000006F0 "CRS_[.+P" */ + 0x49,0x43,0x5F,0x08,0x5F,0x48,0x49,0x44, /* 000006F8 "IC_._HID" */ + 0x0B,0x41,0xD0,0x08,0x5F,0x43,0x52,0x53, /* 00000700 ".A.._CRS" */ + 0x11,0x18,0x0A,0x15,0x47,0x01,0x20,0x00, /* 00000708 "....G. ." */ + 0x20,0x00,0x01,0x02,0x47,0x01,0xA0,0x00, /* 00000710 " ...G..." */ + 0xA0,0x00,0x01,0x02,0x22,0x04,0x00,0x79, /* 00000718 "...."..y" */ + 0x00,0x5B,0x82,0x47,0x05,0x44,0x4D,0x41, /* 00000720 ".[.G.DMA" */ + 0x30,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000728 "0._HID.A" */ + 0xD0,0x02,0x00,0x08,0x5F,0x43,0x52,0x53, /* 00000730 "...._CRS" */ + 0x11,0x41,0x04,0x0A,0x3D,0x2A,0x10,0x04, /* 00000738 ".A..=*.." */ + 0x47,0x01,0x00,0x00,0x00,0x00,0x00,0x10, /* 00000740 "G......." */ + 0x47,0x01,0x81,0x00,0x81,0x00,0x00,0x03, /* 00000748 "G......." */ + 0x47,0x01,0x87,0x00,0x87,0x00,0x00,0x01, /* 00000750 "G......." */ + 0x47,0x01,0x89,0x00,0x89,0x00,0x00,0x03, /* 00000758 "G......." */ + 0x47,0x01,0x8F,0x00,0x8F,0x00,0x00,0x01, /* 00000760 "G......." */ + 0x47,0x01,0xC0,0x00,0xC0,0x00,0x00,0x20, /* 00000768 "G...... " */ + 0x47,0x01,0x80,0x04,0x80,0x04,0x00,0x10, /* 00000770 "G......." */ + 0x79,0x00,0x5B,0x82,0x25,0x54,0x4D,0x52, /* 00000778 "y.[.%TMR" */ + 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000780 "_._HID.A" */ + 0xD0,0x01,0x00,0x08,0x5F,0x43,0x52,0x53, /* 00000788 "...._CRS" */ + 0x11,0x10,0x0A,0x0D,0x47,0x01,0x40,0x00, /* 00000790 "....G.@." */ + 0x40,0x00,0x00,0x04,0x22,0x01,0x00,0x79, /* 00000798 "@..."..y" */ + 0x00,0x5B,0x82,0x25,0x52,0x54,0x43,0x5F, /* 000007A0 ".[.%RTC_" */ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000007A8 "._HID.A." */ - 0x0F,0x13,0x08,0x5F,0x43,0x49,0x44,0x0C, /* 000007B0 "..._CID." */ - 0x41,0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53, /* 000007B8 "A....._S" */ - 0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F, /* 000007C0 "TA....._" */ - 0x43,0x52,0x53,0x11,0x08,0x0A,0x05,0x22, /* 000007C8 "CRS...."" */ - 0x00,0x10,0x79,0x00,0x5B,0x82,0x42,0x04, /* 000007D0 "..y.[.B." */ - 0x50,0x53,0x32,0x4B,0x08,0x5F,0x48,0x49, /* 000007D8 "PS2K._HI" */ - 0x44,0x0C,0x41,0xD0,0x03,0x03,0x08,0x5F, /* 000007E0 "D.A...._" */ - 0x43,0x49,0x44,0x0C,0x41,0xD0,0x03,0x0B, /* 000007E8 "CID.A..." */ - 0x14,0x09,0x5F,0x53,0x54,0x41,0x00,0xA4, /* 000007F0 ".._STA.." */ - 0x0A,0x0F,0x08,0x5F,0x43,0x52,0x53,0x11, /* 000007F8 "..._CRS." */ - 0x18,0x0A,0x15,0x47,0x01,0x60,0x00,0x60, /* 00000800 "...G.`.`" */ - 0x00,0x00,0x01,0x47,0x01,0x64,0x00,0x64, /* 00000808 "...G.d.d" */ - 0x00,0x00,0x01,0x22,0x02,0x00,0x79,0x00, /* 00000810 "..."..y." */ - 0x5B,0x82,0x3A,0x46,0x44,0x43,0x30,0x08, /* 00000818 "[.:FDC0." */ - 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000820 "_HID.A.." */ - 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000828 "..._STA." */ - 0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52,0x53, /* 00000830 "...._CRS" */ - 0x11,0x1B,0x0A,0x18,0x47,0x01,0xF0,0x03, /* 00000838 "....G..." */ - 0xF0,0x03,0x01,0x06,0x47,0x01,0xF7,0x03, /* 00000840 "....G..." */ - 0xF7,0x03,0x01,0x01,0x22,0x40,0x00,0x2A, /* 00000848 "...."@.*" */ - 0x04,0x00,0x79,0x00,0x5B,0x82,0x35,0x55, /* 00000850 "..y.[.5U" */ - 0x41,0x52,0x31,0x08,0x5F,0x48,0x49,0x44, /* 00000858 "AR1._HID" */ - 0x0C,0x41,0xD0,0x05,0x01,0x08,0x5F,0x55, /* 00000860 ".A...._U" */ - 0x49,0x44,0x01,0x14,0x09,0x5F,0x53,0x54, /* 00000868 "ID..._ST" */ - 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000870 "A....._C" */ - 0x52,0x53,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000878 "RS....G." */ - 0xF8,0x03,0xF8,0x03,0x01,0x08,0x22,0x10, /* 00000880 "......"." */ - 0x00,0x79,0x00,0x5B,0x82,0x36,0x55,0x41, /* 00000888 ".y.[.6UA" */ - 0x52,0x32,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000890 "R2._HID." */ - 0x41,0xD0,0x05,0x01,0x08,0x5F,0x55,0x49, /* 00000898 "A...._UI" */ - 0x44,0x0A,0x02,0x14,0x09,0x5F,0x53,0x54, /* 000008A0 "D...._ST" */ - 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 000008A8 "A....._C" */ - 0x52,0x53,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 000008B0 "RS....G." */ - 0xF8,0x02,0xF8,0x02,0x01,0x08,0x22,0x08, /* 000008B8 "......"." */ - 0x00,0x79,0x00, + 0x0B,0x00,0x08,0x5F,0x43,0x52,0x53,0x11, /* 000007B0 "..._CRS." */ + 0x10,0x0A,0x0D,0x47,0x01,0x70,0x00,0x70, /* 000007B8 "...G.p.p" */ + 0x00,0x00,0x02,0x22,0x00,0x01,0x79,0x00, /* 000007C0 "..."..y." */ + 0x5B,0x82,0x22,0x53,0x50,0x4B,0x52,0x08, /* 000007C8 "[."SPKR." */ + 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x08, /* 000007D0 "_HID.A.." */ + 0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x0D, /* 000007D8 ".._CRS.." */ + 0x0A,0x0A,0x47,0x01,0x61,0x00,0x61,0x00, /* 000007E0 "..G.a.a." */ + 0x00,0x01,0x79,0x00,0x5B,0x82,0x31,0x50, /* 000007E8 "..y.[.1P" */ + 0x53,0x32,0x4D,0x08,0x5F,0x48,0x49,0x44, /* 000007F0 "S2M._HID" */ + 0x0C,0x41,0xD0,0x0F,0x13,0x08,0x5F,0x43, /* 000007F8 ".A...._C" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0F,0x13,0x14, /* 00000800 "ID.A...." */ + 0x09,0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A, /* 00000808 "._STA..." */ + 0x0F,0x08,0x5F,0x43,0x52,0x53,0x11,0x08, /* 00000810 ".._CRS.." */ + 0x0A,0x05,0x22,0x00,0x10,0x79,0x00,0x5B, /* 00000818 ".."..y.[" */ + 0x82,0x42,0x04,0x50,0x53,0x32,0x4B,0x08, /* 00000820 ".B.PS2K." */ + 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x03, /* 00000828 "_HID.A.." */ + 0x03,0x08,0x5F,0x43,0x49,0x44,0x0C,0x41, /* 00000830 ".._CID.A" */ + 0xD0,0x03,0x0B,0x14,0x09,0x5F,0x53,0x54, /* 00000838 "....._ST" */ + 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000840 "A....._C" */ + 0x52,0x53,0x11,0x18,0x0A,0x15,0x47,0x01, /* 00000848 "RS....G." */ + 0x60,0x00,0x60,0x00,0x00,0x01,0x47,0x01, /* 00000850 "`.`...G." */ + 0x64,0x00,0x64,0x00,0x00,0x01,0x22,0x02, /* 00000858 "d.d..."." */ + 0x00,0x79,0x00,0x5B,0x82,0x3A,0x46,0x44, /* 00000860 ".y.[.:FD" */ + 0x43,0x30,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000868 "C0._HID." */ + 0x41,0xD0,0x07,0x00,0x14,0x09,0x5F,0x53, /* 00000870 "A....._S" */ + 0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F, /* 00000878 "TA....._" */ + 0x43,0x52,0x53,0x11,0x1B,0x0A,0x18,0x47, /* 00000880 "CRS....G" */ + 0x01,0xF0,0x03,0xF0,0x03,0x01,0x06,0x47, /* 00000888 ".......G" */ + 0x01,0xF7,0x03,0xF7,0x03,0x01,0x01,0x22, /* 00000890 "......."" */ + 0x40,0x00,0x2A,0x04,0x00,0x79,0x00,0x5B, /* 00000898 "@.*..y.[" */ + 0x82,0x35,0x55,0x41,0x52,0x31,0x08,0x5F, /* 000008A0 ".5UAR1._" */ + 0x48,0x49,0x44,0x0C,0x41,0xD0,0x05,0x01, /* 000008A8 "HID.A..." */ + 0x08,0x5F,0x55,0x49,0x44,0x01,0x14,0x09, /* 000008B0 "._UID..." */ + 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 000008B8 "_STA...." */ + 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 000008C0 "._CRS..." */ + 0x0D,0x47,0x01,0xF8,0x03,0xF8,0x03,0x01, /* 000008C8 ".G......" */ + 0x08,0x22,0x10,0x00,0x79,0x00,0x5B,0x82, /* 000008D0 "."..y.[." */ + 0x36,0x55,0x41,0x52,0x32,0x08,0x5F,0x48, /* 000008D8 "6UAR2._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 000008E0 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x09, /* 000008E8 "_UID...." */ + 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 000008F0 "_STA...." */ + 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 000008F8 "._CRS..." */ + 0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02,0x01, /* 00000900 ".G......" */ + 0x08,0x22,0x08,0x00,0x79,0x00, }; int DsdtLen=sizeof(AmlCode); From c4a18a04353ffcdb93818217c662ab47f1455536 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 11:33:41 +0100 Subject: [PATCH 094/111] [qemu] Update acpi timer to not use a qemu timer. Compute the acpi timer's value when it is accessed instead of using a qemu timer to keep it uptodate. From: Wang, Winston L Signed-off-by: Christian Limpach --- tools/ioemu/hw/piix4acpi.c | 145 +++++++++---------------------------- 1 file changed, 33 insertions(+), 112 deletions(-) diff --git a/tools/ioemu/hw/piix4acpi.c b/tools/ioemu/hw/piix4acpi.c index 530ce2c531..e82dc83fae 100644 --- a/tools/ioemu/hw/piix4acpi.c +++ b/tools/ioemu/hw/piix4acpi.c @@ -24,26 +24,26 @@ */ #include "vl.h" -#define FREQUENCE_PMTIMER 3753425 +#define FREQUENCE_PMTIMER 3579545 /* acpi register bit define here */ -/* PM1_STS */ -#define TMROF_STS (1 << 0) -#define BM_STS (1 << 4) -#define GBL_STS (1 << 5) -#define PWRBTN_STS (1 << 8) -#define RTC_STS (1 << 10) +/* PM1_STS */ +#define TMROF_STS (1 << 0) +#define BM_STS (1 << 4) +#define GBL_STS (1 << 5) +#define PWRBTN_STS (1 << 8) +#define RTC_STS (1 << 10) #define PRBTNOR_STS (1 << 11) -#define WAK_STS (1 << 15) -/* PM1_EN */ +#define WAK_STS (1 << 15) +/* PM1_EN */ #define TMROF_EN (1 << 0) #define GBL_EN (1 << 5) #define PWRBTN_EN (1 << 8) -#define RTC_EN (1 << 10) -/* PM1_CNT */ +#define RTC_EN (1 << 10) +/* PM1_CNT */ #define SCI_EN (1 << 0) #define GBL_RLS (1 << 2) -#define SLP_EN (1 << 13) +#define SLP_EN (1 << 13) /* Bits of PM1a register define here */ #define SLP_TYP_MASK 0x1C00 @@ -52,14 +52,6 @@ typedef struct AcpiDeviceState AcpiDeviceState; AcpiDeviceState *acpi_device_table; -/* Bits of PM1a register define here */ -typedef struct PMTState { - uint32_t count; - int irq; - uint64_t next_pm_time; - QEMUTimer *pm_timer; -}PMTState; - typedef struct PM1Event_BLK { uint16_t pm1_status; /* pm1a_EVT_BLK */ uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */ @@ -72,84 +64,11 @@ typedef struct PCIAcpiState { uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */ uint16_t pm1_control; /* pm1a_ECNT_BLK */ uint32_t pm1_timer; /* pmtmr_BLK */ + uint64_t old_vmck_ticks /* using vm_clock counter */ } PCIAcpiState; -static PMTState *pmtimer_state; static PCIAcpiState *acpi_state; -static void pmtimer_save(QEMUFile *f, void *opaque) -{ - PMTState *s = opaque; - - qemu_put_be32s(f, &s->count); - qemu_put_be32s(f, &s->irq); - qemu_put_be64s(f, &s->next_pm_time); - qemu_put_timer(f, s->pm_timer); -} - -static int pmtimer_load(QEMUFile *f, void *opaque, int version_id) -{ - PMTState *s = opaque; - - if (version_id != 1) - return -EINVAL; - qemu_get_be32s(f, &s->count); - qemu_get_be32s(f, &s->irq); - qemu_get_be64s(f, &s->next_pm_time); - qemu_get_timer(f, s->pm_timer); - return 0; -} - -static inline void acpi_set_irq(PCIAcpiState *s) -{ -/* no real SCI event need for now, so comment the following line out */ -/* pic_set_irq(s->irq, 1); */ - printf("acpi_set_irq: s->irq %x \n",s->irq); -} - -static void pm_timer_update(void *opaque) -{ - PMTState *s = opaque; - s->next_pm_time = qemu_get_clock(vm_clock) + - muldiv64(1, ticks_per_sec,FREQUENCE_PMTIMER); - qemu_mod_timer(s->pm_timer, s->next_pm_time); - acpi_state->pm1_timer ++; - - /* If pm timer is zero then reset it to zero. */ - if (acpi_state->pm1_timer >= 0x1000000) { -/* printf("pm_timerupdate: timer overflow: %x \n", acpi_state->pm1_timer); */ - - acpi_state->pm1_timer = 0; - acpi_state->pm1_status = acpi_state->pm1_status | TMROF_STS; - /* If TMROF_EN is set then send the irq. */ - if ((acpi_state->pm1_enable & TMROF_EN) == TMROF_EN) { - acpi_set_irq(acpi_state); - acpi_state->pm1_enable = 0x00; /* only need one time...*/ - } - } - s->count = acpi_state->pm1_timer; -} - -static PMTState *pmtimer_init(void) -{ - PMTState *s; - - s = qemu_mallocz(sizeof(PMTState)); - if (!s) - return NULL; - - /* s->irq = irq; */ - - s->pm_timer = qemu_new_timer(vm_clock, pm_timer_update, s); - - s->count = 0; - s->next_pm_time = qemu_get_clock(vm_clock) + muldiv64(1, ticks_per_sec,FREQUENCE_PMTIMER) + 1; - qemu_mod_timer(s->pm_timer, s->next_pm_time); - - register_savevm("pm timer", 1, 1, pmtimer_save, pmtimer_load, s); - return s; -} - static void acpi_reset(PCIAcpiState *s) { uint8_t *pci_conf; @@ -162,6 +81,7 @@ static void acpi_reset(PCIAcpiState *s) s->pm1_enable = 0x00; /* TMROF_EN should cleared */ s->pm1_control = SCI_EN; /* SCI_EN */ s->pm1_timer = 0; + s->old_vmck_ticks = qemu_get_clock(vm_clock); } /*byte access */ @@ -173,8 +93,8 @@ static void acpiPm1Status_writeb(void *opaque, uint32_t addr, uint32_t val) s->pm1_status = s->pm1_status&!TMROF_STS; if ((val&GBL_STS)==GBL_STS) - s->pm1_status = s->pm1_status&!GBL_STS; - + s->pm1_status = s->pm1_status&!GBL_STS; + /* printf("acpiPm1Status_writeb \n addr %x val:%x pm1_status:%x \n", addr, val,s->pm1_status); */ } @@ -193,7 +113,7 @@ static void acpiPm1StatusP1_writeb(void *opaque, uint32_t addr, uint32_t val) { PCIAcpiState *s = opaque; - s->pm1_status = (val<<8)||(s->pm1_status); + s->pm1_status = (val<<8)||(s->pm1_status); /* printf("acpiPm1StatusP1_writeb \n addr %x val:%x\n", addr, val); */ } @@ -305,7 +225,7 @@ static void acpiPm1Status_writew(void *opaque, uint32_t addr, uint32_t val) s->pm1_status = s->pm1_status&!TMROF_STS; if ((val&GBL_STS)==GBL_STS) - s->pm1_status = s->pm1_status&!GBL_STS; + s->pm1_status = s->pm1_status&!GBL_STS; /* printf("acpiPm1Status_writew \n addr %x val:%x pm1_status:%x \n", addr, val,s->pm1_status); */ } @@ -384,7 +304,7 @@ static uint32_t acpiPm1Event_readl(void *opaque, uint32_t addr) { PCIAcpiState *s = opaque; uint32_t val; - + val = s->pm1_status|(s->pm1_enable<<16); /* printf("acpiPm1Event_readl \n addr %x val:%x\n", addr, val); */ @@ -396,17 +316,21 @@ static void acpiPm1Timer_writel(void *opaque, uint32_t addr, uint32_t val) PCIAcpiState *s = opaque; s->pm1_timer = val; -/* printf("acpiPm1Timer_writel \n addr %x val:%x\n", addr, val); */ + s->old_vmck_ticks = qemu_get_clock(vm_clock) + + muldiv64(val, FREQUENCE_PMTIMER, ticks_per_sec); } static uint32_t acpiPm1Timer_readl(void *opaque, uint32_t addr) { PCIAcpiState *s = opaque; - uint32_t val; + int64_t current_vmck_ticks = qemu_get_clock(vm_clock); + int64_t vmck_ticks_delta = current_vmck_ticks - s->old_vmck_ticks; - val = s->pm1_timer; -/* printf("acpiPm1Timer_readl \n addr %x val:%x\n", addr, val); */ - return val; + if (s->old_vmck_ticks) + s->pm1_timer += muldiv64(vmck_ticks_delta, FREQUENCE_PMTIMER, + ticks_per_sec); + s->old_vmck_ticks = current_vmck_ticks; + return s->pm1_timer; } static void acpi_map(PCIDevice *pci_dev, int region_num, @@ -414,7 +338,7 @@ static void acpi_map(PCIDevice *pci_dev, int region_num, { PCIAcpiState *d = (PCIAcpiState *)pci_dev; - printf("register acpi io \n"); + printf("register acpi io\n"); /* Byte access */ register_ioport_write(addr, 1, 1, acpiPm1Status_writeb, d); @@ -430,14 +354,14 @@ static void acpi_map(PCIDevice *pci_dev, int region_num, register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d); register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d); register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d); - register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); + register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); /* Word access */ register_ioport_write(addr, 2, 2, acpiPm1Status_writew, d); register_ioport_read(addr, 2, 2, acpiPm1Status_readw, d); register_ioport_write(addr + 2, 2, 2, acpiPm1Enable_writew, d); - register_ioport_read(addr + 2, 2, 2, acpiPm1Enable_readw, d); + register_ioport_read(addr + 2, 2, 2, acpiPm1Enable_readw, d); register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d); register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d); @@ -445,11 +369,10 @@ static void acpi_map(PCIDevice *pci_dev, int region_num, /* DWord access */ register_ioport_write(addr, 4, 4, acpiPm1Event_writel, d); register_ioport_read(addr, 4, 4, acpiPm1Event_readl, d); - + register_ioport_write(addr + 8, 4, 4, acpiPm1Timer_writel, d); register_ioport_read(addr + 8, 4, 4, acpiPm1Timer_readl, d); } - /* PIIX4 acpi pci configuration space, func 3 */ void pci_piix4_acpi_init(PCIBus *bus) @@ -478,7 +401,5 @@ void pci_piix4_acpi_init(PCIBus *bus) pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, acpi_map); - pmtimer_state = pmtimer_init(); - - acpi_reset (d); + acpi_reset(d); } From 41df99f54ecbe88ff62c9d75654c7dbd371ceac5 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 11:34:01 +0100 Subject: [PATCH 095/111] [qemu patches] Update patches for changeset 10943:1de1bb6a51c5. Signed-off-by: Christian Limpach --- tools/ioemu/patches/acpi-timer-support | 265 ++++++++++++++++--------- 1 file changed, 166 insertions(+), 99 deletions(-) diff --git a/tools/ioemu/patches/acpi-timer-support b/tools/ioemu/patches/acpi-timer-support index b97dcd06b9..0060109ab6 100644 --- a/tools/ioemu/patches/acpi-timer-support +++ b/tools/ioemu/patches/acpi-timer-support @@ -1,116 +1,118 @@ -diff -r 45c8b171d210 hw/piix4acpi.c ---- a/hw/piix4acpi.c Wed Jun 28 20:33:30 2006 +0100 -+++ b/hw/piix4acpi.c Thu Jun 29 09:34:35 2006 +0100 -@@ -49,6 +49,13 @@ AcpiDeviceState *acpi_device_table; +Index: ioemu/hw/piix4acpi.c +=================================================================== +--- ioemu.orig/hw/piix4acpi.c 2006-08-04 10:57:28.922994985 +0100 ++++ ioemu/hw/piix4acpi.c 2006-08-04 11:23:48.127374982 +0100 +@@ -24,31 +24,30 @@ + */ + + #include "vl.h" +-#define FREQUENCE_PMTIMER 3753425 ++#define FREQUENCE_PMTIMER 3579545 + /* acpi register bit define here */ + +-/* PM1_STS */ +-#define TMROF_STS (1 << 0) +-#define BM_STS (1 << 4) +-#define GBL_STS (1 << 5) +-#define PWRBTN_STS (1 << 8) +-#define RTC_STS (1 << 10) ++/* PM1_STS */ ++#define TMROF_STS (1 << 0) ++#define BM_STS (1 << 4) ++#define GBL_STS (1 << 5) ++#define PWRBTN_STS (1 << 8) ++#define RTC_STS (1 << 10) + #define PRBTNOR_STS (1 << 11) +-#define WAK_STS (1 << 15) +-/* PM1_EN */ ++#define WAK_STS (1 << 15) ++/* PM1_EN */ + #define TMROF_EN (1 << 0) + #define GBL_EN (1 << 5) + #define PWRBTN_EN (1 << 8) +-#define RTC_EN (1 << 10) +-/* PM1_CNT */ ++#define RTC_EN (1 << 10) ++/* PM1_CNT */ + #define SCI_EN (1 << 0) + #define GBL_RLS (1 << 2) +-#define SLP_EN (1 << 13) ++#define SLP_EN (1 << 13) + + typedef struct AcpiDeviceState AcpiDeviceState; AcpiDeviceState *acpi_device_table; - /* Bits of PM1a register define here */ -+typedef struct PMTState { -+ uint32_t count; -+ int irq; -+ uint64_t next_pm_time; -+ QEMUTimer *pm_timer; -+}PMTState; -+ +-/* Bits of PM1a register define here */ typedef struct PM1Event_BLK { uint16_t pm1_status; /* pm1a_EVT_BLK */ uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */ -@@ -63,13 +70,80 @@ typedef struct PCIAcpiState { +@@ -61,17 +60,11 @@ + uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */ + uint16_t pm1_control; /* pm1a_ECNT_BLK */ uint32_t pm1_timer; /* pmtmr_BLK */ ++ uint64_t old_vmck_ticks /* using vm_clock counter */ } PCIAcpiState; -+static PMTState *pmtimer_state; static PCIAcpiState *acpi_state; -+ -+static void pmtimer_save(QEMUFile *f, void *opaque) -+{ -+ PMTState *s = opaque; -+ -+ qemu_put_be32s(f, &s->count); -+ qemu_put_be32s(f, &s->irq); -+ qemu_put_be64s(f, &s->next_pm_time); -+ qemu_put_timer(f, s->pm_timer); -+} -+ -+static int pmtimer_load(QEMUFile *f, void *opaque, int version_id) -+{ -+ PMTState *s = opaque; -+ -+ if (version_id != 1) -+ return -EINVAL; -+ qemu_get_be32s(f, &s->count); -+ qemu_get_be32s(f, &s->irq); -+ qemu_get_be64s(f, &s->next_pm_time); -+ qemu_get_timer(f, s->pm_timer); -+ return 0; -+} - static inline void acpi_set_irq(PCIAcpiState *s) +-static inline void acpi_set_irq(PCIAcpiState *s) +-{ +-/* no real SCI event need for now, so comment the following line out */ +-/* pic_set_irq(s->irq, 1); */ +- printf("acpi_set_irq: s->irq %x \n",s->irq); +-} +- + static void acpi_reset(PCIAcpiState *s) { - /* no real SCI event need for now, so comment the following line out */ - /* pic_set_irq(s->irq, 1); */ - printf("acpi_set_irq: s->irq %x \n",s->irq); -+} -+ -+static void pm_timer_update(void *opaque) -+{ -+ PMTState *s = opaque; -+ s->next_pm_time = qemu_get_clock(vm_clock) + -+ muldiv64(1, ticks_per_sec,FREQUENCE_PMTIMER); -+ qemu_mod_timer(s->pm_timer, s->next_pm_time); -+ acpi_state->pm1_timer ++; -+ -+ /* If pm timer is zero then reset it to zero. */ -+ if (acpi_state->pm1_timer >= 0x1000000) { -+/* printf("pm_timerupdate: timer overflow: %x \n", acpi_state->pm1_timer); */ -+ -+ acpi_state->pm1_timer = 0; -+ acpi_state->pm1_status = acpi_state->pm1_status | TMROF_STS; -+ /* If TMROF_EN is set then send the irq. */ -+ if ((acpi_state->pm1_enable & TMROF_EN) == TMROF_EN) { -+ acpi_set_irq(acpi_state); -+ acpi_state->pm1_enable = 0x00; /* only need one time...*/ -+ } -+ } -+ s->count = acpi_state->pm1_timer; -+} -+ -+static PMTState *pmtimer_init(void) -+{ -+ PMTState *s; -+ -+ s = qemu_mallocz(sizeof(PMTState)); -+ if (!s) -+ return NULL; -+ -+ /* s->irq = irq; */ -+ -+ s->pm_timer = qemu_new_timer(vm_clock, pm_timer_update, s); -+ -+ s->count = 0; -+ s->next_pm_time = qemu_get_clock(vm_clock) + muldiv64(1, ticks_per_sec,FREQUENCE_PMTIMER) + 1; -+ qemu_mod_timer(s->pm_timer, s->next_pm_time); -+ -+ register_savevm("pm timer", 1, 1, pmtimer_save, pmtimer_load, s); -+ return s; + uint8_t *pci_conf; +@@ -84,6 +77,7 @@ + s->pm1_enable = 0x00; /* TMROF_EN should cleared */ + s->pm1_control = SCI_EN; /* SCI_EN */ + s->pm1_timer = 0; ++ s->old_vmck_ticks = qemu_get_clock(vm_clock); } - static void acpi_reset(PCIAcpiState *s) -@@ -288,13 +362,15 @@ static void acpiPm1Event_writel(void *op + /*byte access */ +@@ -95,8 +89,8 @@ + s->pm1_status = s->pm1_status&!TMROF_STS; + + if ((val&GBL_STS)==GBL_STS) +- s->pm1_status = s->pm1_status&!GBL_STS; +- ++ s->pm1_status = s->pm1_status&!GBL_STS; ++ + /* printf("acpiPm1Status_writeb \n addr %x val:%x pm1_status:%x \n", addr, val,s->pm1_status); */ + } + +@@ -115,7 +109,7 @@ + { + PCIAcpiState *s = opaque; + +- s->pm1_status = (val<<8)||(s->pm1_status); ++ s->pm1_status = (val<<8)||(s->pm1_status); + /* printf("acpiPm1StatusP1_writeb \n addr %x val:%x\n", addr, val); */ + } + +@@ -220,7 +214,7 @@ + s->pm1_status = s->pm1_status&!TMROF_STS; + + if ((val&GBL_STS)==GBL_STS) +- s->pm1_status = s->pm1_status&!GBL_STS; ++ s->pm1_status = s->pm1_status&!GBL_STS; + + /* printf("acpiPm1Status_writew \n addr %x val:%x pm1_status:%x \n", addr, val,s->pm1_status); */ + } +@@ -288,13 +282,15 @@ } -static void acpiPm1Event_readl(void *opaque, uint32_t addr) --{ -- PCIAcpiState *s = opaque; -- uint32_t val; -- -- val=s->pm1_status|(s->pm1_enable<<16); +static uint32_t acpiPm1Event_readl(void *opaque, uint32_t addr) -+{ -+ PCIAcpiState *s = opaque; -+ uint32_t val; -+ + { + PCIAcpiState *s = opaque; + uint32_t val; + +- val=s->pm1_status|(s->pm1_enable<<16); + val = s->pm1_status|(s->pm1_enable<<16); /* printf("acpiPm1Event_readl \n addr %x val:%x\n", addr, val); */ + @@ -118,11 +120,76 @@ diff -r 45c8b171d210 hw/piix4acpi.c } static void acpiPm1Timer_writel(void *opaque, uint32_t addr, uint32_t val) -@@ -384,5 +460,7 @@ void pci_piix4_acpi_init(PCIBus *bus) +@@ -302,17 +298,21 @@ + PCIAcpiState *s = opaque; + + s->pm1_timer = val; +-/* printf("acpiPm1Timer_writel \n addr %x val:%x\n", addr, val); */ ++ s->old_vmck_ticks = qemu_get_clock(vm_clock) + ++ muldiv64(val, FREQUENCE_PMTIMER, ticks_per_sec); + } + + static uint32_t acpiPm1Timer_readl(void *opaque, uint32_t addr) + { + PCIAcpiState *s = opaque; +- uint32_t val; ++ int64_t current_vmck_ticks = qemu_get_clock(vm_clock); ++ int64_t vmck_ticks_delta = current_vmck_ticks - s->old_vmck_ticks; + +- val = s->pm1_timer; +-/* printf("acpiPm1Timer_readl \n addr %x val:%x\n", addr, val); */ +- return val; ++ if (s->old_vmck_ticks) ++ s->pm1_timer += muldiv64(vmck_ticks_delta, FREQUENCE_PMTIMER, ++ ticks_per_sec); ++ s->old_vmck_ticks = current_vmck_ticks; ++ return s->pm1_timer; + } + + static void acpi_map(PCIDevice *pci_dev, int region_num, +@@ -320,7 +320,7 @@ + { + PCIAcpiState *d = (PCIAcpiState *)pci_dev; + +- printf("register acpi io \n"); ++ printf("register acpi io\n"); + + /* Byte access */ + register_ioport_write(addr, 1, 1, acpiPm1Status_writeb, d); +@@ -336,14 +336,14 @@ + register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d); + register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d); + register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d); +- register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); ++ register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); + + /* Word access */ + register_ioport_write(addr, 2, 2, acpiPm1Status_writew, d); + register_ioport_read(addr, 2, 2, acpiPm1Status_readw, d); + + register_ioport_write(addr + 2, 2, 2, acpiPm1Enable_writew, d); +- register_ioport_read(addr + 2, 2, 2, acpiPm1Enable_readw, d); ++ register_ioport_read(addr + 2, 2, 2, acpiPm1Enable_readw, d); + + register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d); + register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d); +@@ -351,11 +351,10 @@ + /* DWord access */ + register_ioport_write(addr, 4, 4, acpiPm1Event_writel, d); + register_ioport_read(addr, 4, 4, acpiPm1Event_readl, d); +- ++ + register_ioport_write(addr + 8, 4, 4, acpiPm1Timer_writel, d); + register_ioport_read(addr + 8, 4, 4, acpiPm1Timer_readl, d); + } +- + + /* PIIX4 acpi pci configuration space, func 3 */ + void pci_piix4_acpi_init(PCIBus *bus) +@@ -384,5 +383,5 @@ pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, acpi_map); -+ pmtimer_state = pmtimer_init(); -+ - acpi_reset (d); +- acpi_reset (d); ++ acpi_reset(d); } From 1f401924d598220ee233595c41b7dbf5fdf51f32 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 11:35:51 +0100 Subject: [PATCH 096/111] [qemu] Add missing semicolon. Signed-off-by: Christian Limpach --- tools/ioemu/hw/piix4acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ioemu/hw/piix4acpi.c b/tools/ioemu/hw/piix4acpi.c index e82dc83fae..1e272dbff0 100644 --- a/tools/ioemu/hw/piix4acpi.c +++ b/tools/ioemu/hw/piix4acpi.c @@ -64,7 +64,7 @@ typedef struct PCIAcpiState { uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */ uint16_t pm1_control; /* pm1a_ECNT_BLK */ uint32_t pm1_timer; /* pmtmr_BLK */ - uint64_t old_vmck_ticks /* using vm_clock counter */ + uint64_t old_vmck_ticks; /* using vm_clock counter */ } PCIAcpiState; static PCIAcpiState *acpi_state; From 47b577e71c33acdebeacb0d51c7312ec84b96f94 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Fri, 4 Aug 2006 11:36:07 +0100 Subject: [PATCH 097/111] [qemu patches] Update patches for changeset 10945:baa6d08e62a0. Signed-off-by: Christian Limpach --- tools/ioemu/patches/acpi-timer-support | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/patches/acpi-timer-support b/tools/ioemu/patches/acpi-timer-support index 0060109ab6..dabe65a276 100644 --- a/tools/ioemu/patches/acpi-timer-support +++ b/tools/ioemu/patches/acpi-timer-support @@ -1,7 +1,7 @@ Index: ioemu/hw/piix4acpi.c =================================================================== --- ioemu.orig/hw/piix4acpi.c 2006-08-04 10:57:28.922994985 +0100 -+++ ioemu/hw/piix4acpi.c 2006-08-04 11:23:48.127374982 +0100 ++++ ioemu/hw/piix4acpi.c 2006-08-04 11:35:15.177574467 +0100 @@ -24,31 +24,30 @@ */ @@ -50,7 +50,7 @@ Index: ioemu/hw/piix4acpi.c uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */ uint16_t pm1_control; /* pm1a_ECNT_BLK */ uint32_t pm1_timer; /* pmtmr_BLK */ -+ uint64_t old_vmck_ticks /* using vm_clock counter */ ++ uint64_t old_vmck_ticks; /* using vm_clock counter */ } PCIAcpiState; static PCIAcpiState *acpi_state; From 092b64b838ed9b5dc0f7daea671d500501a419ae Mon Sep 17 00:00:00 2001 From: "ack@localhost.localdomain" Date: Fri, 4 Aug 2006 16:07:58 +0100 Subject: [PATCH 098/111] [NET] front: Check for received packets in network_open0 Because the backend brings up the interface long before the frontend has booted up, it is possible that by the time we get here we already have packets queued up for processing. If we don't process them here, we may delay them more than what is necessary. Worse yet, it is possible to miss the notification interrupt from the backend in such a way that we never get another one until we bring the interface down and up. Signed-off-by: Herbert Xu --- linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 7644b09b86..6bad0c4909 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -497,6 +497,9 @@ static int network_open(struct net_device *dev) network_alloc_rx_buffers(dev); np->rx.sring->rsp_event = np->rx.rsp_cons + 1; + if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) + netif_rx_schedule(dev); + netif_start_queue(dev); return 0; From 5eeca68ffd007f81ac202eafdc96d44e5bb69bfb Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 4 Aug 2006 20:30:12 +0100 Subject: [PATCH 099/111] [HVMLOADER] HVM loader initialises hypercall shim and uses it to interrogate Xen version information. Also add support for HVM hypercall execution on 64-bit host. Signed-off-by: Steven Smith Signed-off-by: Keir Fraser --- tools/firmware/Makefile | 2 +- tools/firmware/hvmloader/Makefile | 9 +- tools/firmware/hvmloader/acpi_madt.c | 4 +- tools/firmware/hvmloader/hvmloader.c | 117 ++++++++-------- tools/firmware/hvmloader/hypercall.h | 180 +++++++++++++++++++++++++ tools/firmware/hvmloader/mp_tables.c | 3 +- tools/firmware/hvmloader/util.c | 96 +++++++++++++ tools/firmware/hvmloader/util.h | 19 +++ xen/arch/x86/hvm/hvm.c | 126 ++++++++++++++--- xen/arch/x86/hvm/platform.c | 14 ++ xen/common/kernel.c | 7 + xen/include/asm-x86/guest_access.h | 5 +- xen/include/asm-x86/hvm/guest_access.h | 3 + xen/include/public/version.h | 3 + 14 files changed, 505 insertions(+), 83 deletions(-) create mode 100644 tools/firmware/hvmloader/hypercall.h create mode 100644 tools/firmware/hvmloader/util.c create mode 100644 tools/firmware/hvmloader/util.h diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile index 63ccb7b17e..85902319e8 100644 --- a/tools/firmware/Makefile +++ b/tools/firmware/Makefile @@ -30,7 +30,7 @@ all: .PHONY: install install: all [ -d $(INSTALL_DIR) ] || install -d -m0755 $(INSTALL_DIR) - [ ! -e $(TARGET) ] || install -m0644 $(TARGET) $(INSTALL_DIR) + install -m0644 $(TARGET) $(INSTALL_DIR) .PHONY: clean clean: diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index ecf1110ebe..66e149599a 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -42,12 +42,15 @@ OBJCOPY = objcopy CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR) +SRCS = hvmloader.c acpi_madt.c mp_tables.c util.c +OBJS = $(patsubst %.c,%.o,$(SRCS)) + .PHONY: all all: hvmloader -hvmloader: roms.h hvmloader.c acpi_madt.c mp_tables.c - $(CC) $(CFLAGS) -c hvmloader.c acpi_madt.c mp_tables.c - $(CC) $(LDFLAGS) -o hvmloader.tmp hvmloader.o acpi_madt.o mp_tables.o +hvmloader: roms.h $(SRCS) + $(CC) $(CFLAGS) -c $(SRCS) + $(CC) $(LDFLAGS) -o hvmloader.tmp $(OBJS) $(OBJCOPY) hvmloader.tmp hvmloader rm -f hvmloader.tmp diff --git a/tools/firmware/hvmloader/acpi_madt.c b/tools/firmware/hvmloader/acpi_madt.c index f977d3ee4f..5a9c3063ae 100644 --- a/tools/firmware/hvmloader/acpi_madt.c +++ b/tools/firmware/hvmloader/acpi_madt.c @@ -20,13 +20,11 @@ #include "../acpi/acpi2_0.h" #include "../acpi/acpi_madt.h" - +#include "util.h" #include #define NULL ((void*)0) -extern int puts(const char *s); - static struct hvm_info_table *table = NULL; static int validate_hvm_info(struct hvm_info_table *t) diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index 4c4637dc58..ec38f5737e 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -23,9 +23,13 @@ */ #include "roms.h" #include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */ +#include "hypercall.h" +#include "util.h" +#include #include /* memory map */ +#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000 #define VGABIOS_PHYSICAL_ADDRESS 0x000C0000 #define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000 #define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000 @@ -75,65 +79,14 @@ extern int acpi_madt_update(unsigned char* acpi_start); extern void create_mp_tables(void); struct hvm_info_table *get_hvm_info_table(void); -static inline void -outw(unsigned short addr, unsigned short val) -{ - __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val)); -} - -static inline void -outb(unsigned short addr, unsigned char val) -{ - __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val)); -} - -static inline unsigned char -inb(unsigned short addr) -{ - unsigned char val; - - __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr)); - return val; -} - -void * -memcpy(void *dest, const void *src, unsigned n) -{ - int t0, t1, t2; - - __asm__ __volatile__( - "cld\n" - "rep; movsl\n" - "testb $2,%b4\n" - "je 1f\n" - "movsw\n" - "1: testb $1,%b4\n" - "je 2f\n" - "movsb\n" - "2:" - : "=&c" (t0), "=&D" (t1), "=&S" (t2) - : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src) - : "memory" - ); - return dest; -} - -int -puts(const char *s) -{ - while (*s) - outb(0xE9, *s++); - return 0; -} - -int +static int cirrus_check(void) { outw(0x3C4, 0x9206); return inb(0x3C5) == 0x12; } -int +static int vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx) { int eax; @@ -147,7 +100,7 @@ vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx) return eax; } -int +static int check_amd(void) { char id[12]; @@ -162,6 +115,60 @@ check_amd(void) return __builtin_memcmp(id, "AuthenticAMD", 12) == 0; } +static void +cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) +{ + __asm__ __volatile__( + "cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (idx) ); +} + +static void +wrmsr(uint32_t idx, uint64_t v) +{ + __asm__ __volatile__( + "wrmsr" + : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) ); +} + +static void +init_hypercalls(void) +{ + uint32_t eax, ebx, ecx, edx; + unsigned long i; + char signature[13], number[13]; + xen_extraversion_t extraversion; + + cpuid(0x40000000, &eax, &ebx, &ecx, &edx); + + *(uint32_t *)(signature + 0) = ebx; + *(uint32_t *)(signature + 4) = ecx; + *(uint32_t *)(signature + 8) = edx; + signature[12] = '\0'; + + if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) { + puts("FATAL: Xen hypervisor not detected\n"); + __asm__ __volatile__( "ud2" ); + } + + cpuid(0x40000001, &eax, &ebx, &ecx, &edx); + + puts("Detected Xen v"); + puts(itoa(number, eax >> 16)); + puts("."); + puts(itoa(number, eax & 0xffff)); + + cpuid(0x40000002, &eax, &ebx, &ecx, &edx); + + for (i = 0; i < eax; i++) + wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i); + + hypercall_xen_version(XENVER_extraversion, extraversion); + puts(extraversion); + puts("\n"); +} + int main(void) { @@ -169,6 +176,8 @@ main(void) puts("HVM Loader\n"); + init_hypercalls(); + puts("Loading ROMBIOS ...\n"); memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios)); if (t->apic_enabled) diff --git a/tools/firmware/hvmloader/hypercall.h b/tools/firmware/hvmloader/hypercall.h new file mode 100644 index 0000000000..5648abf003 --- /dev/null +++ b/tools/firmware/hvmloader/hypercall.h @@ -0,0 +1,180 @@ +/****************************************************************************** + * hypercall.h + * + * Copyright (c) 2002-2006, K A Fraser + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __HVMLOADER_HYPERCALL_H__ +#define __HVMLOADER_HYPERCALL_H__ + +/* + * NB. Hypercall address needs to be relative to a linkage symbol for + * some version of ld to relocate the relative calls properly. + * Keep this in sync with HYPERCALL_PHYSICAL_ADDRESS in hvmloader.c! + */ +#define hypercall_pa "_start - 0x80000" + +#define __STR(x) #x +#define STR(x) __STR(x) + +#define _hypercall0(type, name) \ +({ \ + long __res; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res) \ + : \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall1(type, name, a1) \ +({ \ + long __res, __ign1; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1) \ + : "1" ((long)(a1)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall2(type, name, a1, a2) \ +({ \ + long __res, __ign1, __ign2; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ + : "1" ((long)(a1)), "2" ((long)(a2)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall3(type, name, a1, a2, a3) \ +({ \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall4(type, name, a1, a2, a3, a4) \ +({ \ + long __res, __ign1, __ign2, __ign3, __ign4; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +({ \ + long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)), \ + "5" ((long)(a5)) \ + : "memory" ); \ + (type)__res; \ +}) + +static inline int +hypercall_sched_op( + int cmd, void *arg) +{ + return _hypercall2(int, sched_op, cmd, arg); +} + +static inline int +hypercall_memory_op( + unsigned int cmd, void *arg) +{ + return _hypercall2(int, memory_op, cmd, arg); +} + +static inline int +hypercall_multicall( + void *call_list, int nr_calls) +{ + return _hypercall2(int, multicall, call_list, nr_calls); +} + +static inline int +hypercall_event_channel_op( + int cmd, void *arg) +{ + return _hypercall2(int, event_channel_op, cmd, arg); +} + +static inline int +hypercall_xen_version( + int cmd, void *arg) +{ + return _hypercall2(int, xen_version, cmd, arg); +} + +static inline int +hypercall_console_io( + int cmd, int count, char *str) +{ + return _hypercall3(int, console_io, cmd, count, str); +} + +static inline int +hypercall_vm_assist( + unsigned int cmd, unsigned int type) +{ + return _hypercall2(int, vm_assist, cmd, type); +} + +static inline int +hypercall_vcpu_op( + int cmd, int vcpuid, void *extra_args) +{ + return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); +} + +static inline int +hypercall_hvm_op( + int cmd, void *arg) +{ + return _hypercall2(int, hvm_op, cmd, arg); +} + +#endif /* __HVMLOADER_HYPERCALL_H__ */ diff --git a/tools/firmware/hvmloader/mp_tables.c b/tools/firmware/hvmloader/mp_tables.c index 160cdcfc9a..d836832662 100644 --- a/tools/firmware/hvmloader/mp_tables.c +++ b/tools/firmware/hvmloader/mp_tables.c @@ -93,7 +93,8 @@ typedef signed long int64_t; #define INTR_MAX_NR 16 -extern int puts(const char *); /* for printing */ +#include "util.h" + extern int get_vcpu_nr(void); /* for the guest's VCPU count */ /* diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c new file mode 100644 index 0000000000..b1a38fd036 --- /dev/null +++ b/tools/firmware/hvmloader/util.c @@ -0,0 +1,96 @@ +/* + * util.c: Helper library functions for HVMLoader. + * + * Leendert van Doorn, leendert@watson.ibm.com + * Copyright (c) 2005, International Business Machines Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */ +#include "util.h" + +void outw(uint16_t addr, uint16_t val) +{ + __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val)); +} + +void outb(uint16_t addr, uint8_t val) +{ + __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val)); +} + +uint8_t inb(uint16_t addr) +{ + uint8_t val; + __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr)); + return val; +} + +char *itoa(char *a, unsigned int i) +{ + unsigned int _i = i, x = 0; + + do { + x++; + _i /= 10; + } while (_i != 0); + + a += x; + *a-- = '\0'; + + do { + *a-- = (i % 10) + '0'; + i /= 10; + } while (i != 0); + + return a + 1; +} + +int strcmp(const char *cs, const char *ct) +{ + signed char res; + + while (((res = *cs - *ct++) == 0) && (*cs++ != '\0')) + continue; + + return res; +} + +void *memcpy(void *dest, const void *src, unsigned n) +{ + int t0, t1, t2; + + __asm__ __volatile__( + "cld\n" + "rep; movsl\n" + "testb $2,%b4\n" + "je 1f\n" + "movsw\n" + "1: testb $1,%b4\n" + "je 2f\n" + "movsb\n" + "2:" + : "=&c" (t0), "=&D" (t1), "=&S" (t2) + : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src) + : "memory" + ); + return dest; +} + +void puts(const char *s) +{ + while (*s) + outb(0xE9, *s++); +} diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h new file mode 100644 index 0000000000..57aab64998 --- /dev/null +++ b/tools/firmware/hvmloader/util.h @@ -0,0 +1,19 @@ +#ifndef __HVMLOADER_UTIL_H__ +#define __HVMLOADER_UTIL_H__ + +/* I/O output */ +void outw(uint16_t addr, uint16_t val); +void outb(uint16_t addr, uint8_t val); + +/* I/O input */ +uint8_t inb(uint16_t addr); + +/* String and memory functions */ +int strcmp(const char *cs, const char *ct); +void *memcpy(void *dest, const void *src, unsigned n); +char *itoa(char *a, unsigned int i); + +/* Debug output */ +void puts(const char *s); + +#endif /* __HVMLOADER_UTIL_H__ */ diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 7b348e32dd..cbc2a5bd4a 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,8 @@ #include #include #include -#include +#include +#include int hvm_enabled = 0; @@ -305,55 +307,139 @@ void hvm_print_line(struct vcpu *v, const char c) pbuf[(*index)++] = c; } -#if defined(__i386__) - typedef unsigned long hvm_hypercall_t( unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); -#define HYPERCALL(x) [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x + +#define HYPERCALL(x) \ + [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x +#define HYPERCALL_COMPAT32(x) \ + [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x ## _compat32 + +#if defined(__i386__) + static hvm_hypercall_t *hvm_hypercall_table[] = { - HYPERCALL(mmu_update), HYPERCALL(memory_op), HYPERCALL(multicall), - HYPERCALL(update_va_mapping), - HYPERCALL(event_channel_op_compat), HYPERCALL(xen_version), - HYPERCALL(grant_table_op), HYPERCALL(event_channel_op), HYPERCALL(hvm_op) }; -#undef HYPERCALL void hvm_do_hypercall(struct cpu_user_regs *pregs) { - if ( ring_3(pregs) ) + if ( unlikely(ring_3(pregs)) ) { pregs->eax = -EPERM; return; } - if ( pregs->eax > ARRAY_SIZE(hvm_hypercall_table) || - !hvm_hypercall_table[pregs->eax] ) + if ( (pregs->eax >= NR_hypercalls) || !hvm_hypercall_table[pregs->eax] ) { DPRINTK("HVM vcpu %d:%d did a bad hypercall %d.\n", current->domain->domain_id, current->vcpu_id, pregs->eax); pregs->eax = -ENOSYS; + return; } - else - { - pregs->eax = hvm_hypercall_table[pregs->eax]( - pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi); - } + + pregs->eax = hvm_hypercall_table[pregs->eax]( + pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi); } -#else /* __x86_64__ */ +#else /* defined(__x86_64__) */ + +static long do_memory_op_compat32(int cmd, XEN_GUEST_HANDLE(void) arg) +{ + extern long do_add_to_physmap(struct xen_add_to_physmap *xatp); + long rc; + + switch ( cmd ) + { + case XENMEM_add_to_physmap: + { + struct { + domid_t domid; + uint32_t space; + uint32_t idx; + uint32_t gpfn; + } u; + struct xen_add_to_physmap h; + + if ( copy_from_guest(&u, arg, 1) ) + return -EFAULT; + + h.domid = u.domid; + h.space = u.space; + h.idx = u.idx; + h.gpfn = u.gpfn; + + this_cpu(guest_handles_in_xen_space) = 1; + rc = do_memory_op(cmd, guest_handle_from_ptr(&h, void)); + this_cpu(guest_handles_in_xen_space) = 0; + + break; + } + + default: + DPRINTK("memory_op %d.\n", cmd); + rc = -ENOSYS; + break; + } + + return rc; +} + +static hvm_hypercall_t *hvm_hypercall64_table[NR_hypercalls] = { + HYPERCALL(memory_op), + HYPERCALL(xen_version), + HYPERCALL(hvm_op), + HYPERCALL(event_channel_op) +}; + +static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = { + HYPERCALL_COMPAT32(memory_op), + HYPERCALL(xen_version), + HYPERCALL(hvm_op), + HYPERCALL(event_channel_op) +}; void hvm_do_hypercall(struct cpu_user_regs *pregs) { - printk("not supported yet!\n"); + if ( unlikely(ring_3(pregs)) ) + { + pregs->rax = -EPERM; + return; + } + + pregs->rax = (uint32_t)pregs->eax; /* mask in case compat32 caller */ + if ( (pregs->rax >= NR_hypercalls) || !hvm_hypercall64_table[pregs->rax] ) + { + DPRINTK("HVM vcpu %d:%d did a bad hypercall %ld.\n", + current->domain->domain_id, current->vcpu_id, + pregs->rax); + pregs->rax = -ENOSYS; + return; + } + + if ( current->domain->arch.ops->guest_paging_levels == PAGING_L4 ) + { + pregs->rax = hvm_hypercall64_table[pregs->rax](pregs->rdi, + pregs->rsi, + pregs->rdx, + pregs->r10, + pregs->r8); + } + else + { + pregs->eax = hvm_hypercall32_table[pregs->eax]((uint32_t)pregs->ebx, + (uint32_t)pregs->ecx, + (uint32_t)pregs->edx, + (uint32_t)pregs->esi, + (uint32_t)pregs->edi); + } } -#endif +#endif /* defined(__x86_64__) */ /* Initialise a hypercall transfer page for a VMX domain using paravirtualised drivers. */ diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index efe443a8a0..af8b55d661 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -1034,17 +1034,31 @@ void handle_mmio(unsigned long va, unsigned long gpa) } } +DEFINE_PER_CPU(int, guest_handles_in_xen_space); + /* Note that copy_{to,from}_user_hvm don't set the A and D bits on PTEs, and require the PTE to be writable even when they're only trying to read from it. The guest is expected to deal with this. */ unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len) { + if ( this_cpu(guest_handles_in_xen_space) ) + { + memcpy(to, from, len); + return 0; + } + return !hvm_copy((void *)from, (unsigned long)to, len, HVM_COPY_OUT); } unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len) { + if ( this_cpu(guest_handles_in_xen_space) ) + { + memcpy(to, from, len); + return 0; + } + return !hvm_copy(to, (unsigned long)from, len, HVM_COPY_IN); } diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 5c3069bb62..0f14494c20 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -217,6 +217,13 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE(void) arg) return (!guest_handle_is_null(arg) ? -EINVAL : PAGE_SIZE); } + case XENVER_guest_handle: + { + if ( copy_to_guest(arg, (char *)current->domain->handle, + sizeof(current->domain->handle)) ) + return -EFAULT; + return 0; + } } return -ENOSYS; diff --git a/xen/include/asm-x86/guest_access.h b/xen/include/asm-x86/guest_access.h index 7b88aad86b..caad3525b0 100644 --- a/xen/include/asm-x86/guest_access.h +++ b/xen/include/asm-x86/guest_access.h @@ -20,9 +20,12 @@ /* Cast a guest handle to the specified type of handle. */ #define guest_handle_cast(hnd, type) ({ \ type *_x = (hnd).p; \ - (XEN_GUEST_HANDLE(type)) { _x }; \ + (XEN_GUEST_HANDLE(type)) { _x }; \ }) +#define guest_handle_from_ptr(ptr, type) \ + ((XEN_GUEST_HANDLE(type)) { (type *)ptr }) + /* * Copy an array of objects to guest context via a guest handle, * specifying an offset into the guest array. diff --git a/xen/include/asm-x86/hvm/guest_access.h b/xen/include/asm-x86/hvm/guest_access.h index 7a89e81536..25ea341e5b 100644 --- a/xen/include/asm-x86/hvm/guest_access.h +++ b/xen/include/asm-x86/hvm/guest_access.h @@ -1,6 +1,9 @@ #ifndef __ASM_X86_HVM_GUEST_ACCESS_H__ #define __ASM_X86_HVM_GUEST_ACCESS_H__ +#include +DECLARE_PER_CPU(int, guest_handles_in_xen_space); + unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len); unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len); diff --git a/xen/include/public/version.h b/xen/include/public/version.h index 8976130c59..dbe18c9e08 100644 --- a/xen/include/public/version.h +++ b/xen/include/public/version.h @@ -57,6 +57,9 @@ typedef struct xen_feature_info xen_feature_info_t; /* arg == NULL; returns host memory page size. */ #define XENVER_pagesize 7 +/* arg == xen_domain_handle_t. */ +#define XENVER_guest_handle 8 + #endif /* __XEN_PUBLIC_VERSION_H__ */ /* From 76338bfaaa51f16b2c4ee5602985e510a92c51ed Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 4 Aug 2006 20:34:44 +0100 Subject: [PATCH 100/111] [XEN] Add Xen-attached event channels, which will be used by HVM for the ioreq_packet port. Signed-off-by: Keir Fraser --- xen/common/event_channel.c | 108 ++++++++++++++++++++++++++++++++++++- xen/include/xen/event.h | 37 ++++++++++--- xen/include/xen/sched.h | 8 ++- 3 files changed, 143 insertions(+), 10 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 305b3b81a2..e333144cf2 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -333,6 +333,14 @@ static long __evtchn_close(struct domain *d1, int port1) } chn1 = evtchn_from_port(d1, port1); + + /* Guest cannot close a Xen-attached event channel. */ + if ( unlikely(chn1->consumer_is_xen) ) + { + rc = -EINVAL; + goto out; + } + switch ( chn1->state ) { case ECS_FREE: @@ -441,6 +449,7 @@ long evtchn_send(unsigned int lport) { struct evtchn *lchn, *rchn; struct domain *ld = current->domain, *rd; + struct vcpu *rvcpu; int rport, ret = 0; spin_lock(&ld->evtchn_lock); @@ -452,13 +461,32 @@ long evtchn_send(unsigned int lport) } lchn = evtchn_from_port(ld, lport); + + /* Guest cannot send via a Xen-attached event channel. */ + if ( unlikely(lchn->consumer_is_xen) ) + { + spin_unlock(&ld->evtchn_lock); + return -EINVAL; + } + switch ( lchn->state ) { case ECS_INTERDOMAIN: rd = lchn->u.interdomain.remote_dom; rport = lchn->u.interdomain.remote_port; rchn = evtchn_from_port(rd, rport); - evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport); + rvcpu = rd->vcpu[rchn->notify_vcpu_id]; + if ( rchn->consumer_is_xen ) + { + /* Xen consumers need notification only if they are blocked. */ + if ( test_and_clear_bit(_VCPUF_blocked_in_xen, + &rvcpu->vcpu_flags) ) + vcpu_wake(rvcpu); + } + else + { + evtchn_set_pending(rvcpu, rport); + } break; case ECS_IPI: evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); @@ -638,6 +666,14 @@ long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id) } chn = evtchn_from_port(d, port); + + /* Guest cannot re-bind a Xen-attached event channel. */ + if ( unlikely(chn->consumer_is_xen) ) + { + rc = -EINVAL; + goto out; + } + switch ( chn->state ) { case ECS_VIRQ: @@ -804,6 +840,71 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE(void) arg) } +int alloc_unbound_xen_event_channel( + struct vcpu *local_vcpu, domid_t remote_domid) +{ + struct evtchn *chn; + struct domain *d = local_vcpu->domain; + int port; + + spin_lock(&d->evtchn_lock); + + if ( (port = get_free_port(d)) < 0 ) + goto out; + chn = evtchn_from_port(d, port); + + chn->state = ECS_UNBOUND; + chn->consumer_is_xen = 1; + chn->notify_vcpu_id = local_vcpu->vcpu_id; + chn->u.unbound.remote_domid = remote_domid; + + out: + spin_unlock(&d->evtchn_lock); + + return port; +} + + +void free_xen_event_channel( + struct vcpu *local_vcpu, int port) +{ + struct evtchn *chn; + struct domain *d = local_vcpu->domain; + + spin_lock(&d->evtchn_lock); + chn = evtchn_from_port(d, port); + BUG_ON(!chn->consumer_is_xen); + chn->consumer_is_xen = 0; + spin_unlock(&d->evtchn_lock); + + (void)__evtchn_close(d, port); +} + + +void notify_via_xen_event_channel(int lport) +{ + struct evtchn *lchn, *rchn; + struct domain *ld = current->domain, *rd; + int rport; + + spin_lock(&ld->evtchn_lock); + + ASSERT(port_is_valid(ld, lport)); + lchn = evtchn_from_port(ld, lport); + ASSERT(lchn->consumer_is_xen); + + if ( likely(lchn->state == ECS_INTERDOMAIN) ) + { + rd = lchn->u.interdomain.remote_dom; + rport = lchn->u.interdomain.remote_port; + rchn = evtchn_from_port(rd, rport); + evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport); + } + + spin_unlock(&ld->evtchn_lock); +} + + int evtchn_init(struct domain *d) { spin_lock_init(&d->evtchn_lock); @@ -819,7 +920,10 @@ void evtchn_destroy(struct domain *d) int i; for ( i = 0; port_is_valid(d, i); i++ ) - (void)__evtchn_close(d, i); + { + evtchn_from_port(d, i)->consumer_is_xen = 0; + (void)__evtchn_close(d, i); + } for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ ) xfree(d->evtchn[i]); diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 7b0d428b67..304466a945 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -15,33 +15,58 @@ #include #include -extern void evtchn_set_pending(struct vcpu *v, int port); +void evtchn_set_pending(struct vcpu *v, int port); /* * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ. * @v: VCPU to which virtual IRQ should be sent * @virq: Virtual IRQ number (VIRQ_*) */ -extern void send_guest_vcpu_virq(struct vcpu *v, int virq); +void send_guest_vcpu_virq(struct vcpu *v, int virq); /* * send_guest_global_virq: Notify guest via a global VIRQ. * @d: Domain to which virtual IRQ should be sent * @virq: Virtual IRQ number (VIRQ_*) */ -extern void send_guest_global_virq(struct domain *d, int virq); +void send_guest_global_virq(struct domain *d, int virq); /* * send_guest_pirq: * @d: Domain to which physical IRQ should be sent * @pirq: Physical IRQ number */ -extern void send_guest_pirq(struct domain *d, int pirq); +void send_guest_pirq(struct domain *d, int pirq); /* Send a notification from a local event-channel port. */ -extern long evtchn_send(unsigned int lport); +long evtchn_send(unsigned int lport); /* Bind a local event-channel port to the specified VCPU. */ -extern long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); +long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); + +/* Allocate/free a Xen-attached event channel port. */ +int alloc_unbound_xen_event_channel( + struct vcpu *local_vcpu, domid_t remote_domid); +void free_xen_event_channel( + struct vcpu *local_vcpu, int port); + +/* Notify remote end of a Xen-attached event channel.*/ +void notify_via_xen_event_channel(int lport); + +/* Wait on a Xen-attached event channel. */ +#define wait_on_xen_event_channel(port, condition) \ + do { \ + if ( condition ) \ + break; \ + set_bit(_VCPUF_blocked_in_xen, ¤t->vcpu_flags); \ + mb(); /* set blocked status /then/ re-evaluate condition */ \ + if ( condition ) \ + { \ + clear_bit(_VCPUF_blocked_in_xen, ¤t->vcpu_flags); \ + break; \ + } \ + raise_softirq(SCHEDULE_SOFTIRQ); \ + do_softirq(); \ + } while ( 0 ) #endif /* __XEN_EVENT_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index fe89e57dab..c37e60f23a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -36,7 +36,8 @@ struct evtchn #define ECS_PIRQ 4 /* Channel is bound to a physical IRQ line. */ #define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */ #define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */ - u16 state; /* ECS_* */ + u8 state; /* ECS_* */ + u8 consumer_is_xen; /* Consumed by Xen or by guest? */ u16 notify_vcpu_id; /* VCPU for local delivery notification */ union { struct { @@ -375,6 +376,9 @@ extern struct domain *domain_list; /* VCPU is paused by the hypervisor? */ #define _VCPUF_paused 11 #define VCPUF_paused (1UL<<_VCPUF_paused) + /* VCPU is blocked awaiting an event to be consumed by Xen. */ +#define _VCPUF_blocked_in_xen 12 +#define VCPUF_blocked_in_xen (1UL<<_VCPUF_blocked_in_xen) /* * Per-domain flags (domain_flags). @@ -404,7 +408,7 @@ extern struct domain *domain_list; static inline int vcpu_runnable(struct vcpu *v) { return ( !(v->vcpu_flags & - (VCPUF_blocked|VCPUF_down|VCPUF_paused)) && + (VCPUF_blocked|VCPUF_down|VCPUF_paused|VCPUF_blocked_in_xen)) && !(v->domain->domain_flags & (DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) ); } From 3923c6638e50c51781fb5f6f29729c71336eb95a Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Mon, 7 Aug 2006 11:59:31 +0100 Subject: [PATCH 101/111] [xend] Fix reboot for hvm domains with cdrom devices. The device-type was not added to the device details which caused cdrom devices to appear as harddisks after a reboot. From: Alex Brett Signed-off-by: Christian Limpach --- tools/python/xen/xend/server/DevController.py | 2 ++ tools/python/xen/xend/server/blkif.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index 42adfd987a..80d7e85dd2 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -341,6 +341,8 @@ class DevController: else: raise VmError("Device %s not connected" % devid) + def readFrontend(self, devid, *args): + return xstransact.Read(self.frontendPath(devid), *args) def deviceIDs(self, transaction = None): """@return The IDs of each of the devices currently configured for diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index d131ea7843..0039900eaa 100644 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -86,6 +86,9 @@ class BlkifController(DevController): 'mode') if dev: + (dev_type) = self.readFrontend(devid, 'device-type') + if dev_type: + dev += ":" + dev_type result.append(['dev', dev]) if typ and params: result.append(['uname', typ + ":" + params]) From 9ee1bd77bfc225d638c8df106238f875025b5e8f Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 7 Aug 2006 15:35:06 +0100 Subject: [PATCH 102/111] [XEN] Clean up shutdown handling and ignore opt_noreboot if dom0 shuts down cleanly. The option is intended only to retain information on the local console in case of a crash. Based on a patch from Muli Ben-Yehuda Signed-off-by: Keir Fraser --- xen/arch/ia64/linux-xen/setup.c | 2 +- xen/arch/powerpc/domain.c | 2 +- xen/arch/x86/genapic/es7000plat.c | 1 - xen/arch/x86/shutdown.c | 17 ++------ xen/arch/x86/traps.c | 2 +- xen/arch/x86/x86_32/traps.c | 2 +- xen/arch/x86/x86_64/traps.c | 2 +- xen/common/Makefile | 1 + xen/common/domain.c | 27 +------------ xen/common/keyhandler.c | 2 +- xen/common/shutdown.c | 66 +++++++++++++++++++++++++++++++ xen/drivers/char/console.c | 19 +++++++-- xen/drivers/char/serial.c | 1 - xen/include/xen/reboot.h | 8 ---- xen/include/xen/shutdown.h | 13 ++++++ 15 files changed, 107 insertions(+), 58 deletions(-) create mode 100644 xen/common/shutdown.c delete mode 100644 xen/include/xen/reboot.h create mode 100644 xen/include/xen/shutdown.h diff --git a/xen/arch/ia64/linux-xen/setup.c b/xen/arch/ia64/linux-xen/setup.c index cc8e197063..6d03910fc7 100644 --- a/xen/arch/ia64/linux-xen/setup.c +++ b/xen/arch/ia64/linux-xen/setup.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/xen/arch/powerpc/domain.c b/xen/arch/powerpc/domain.c index 8e4041982f..140b7ec8d2 100644 --- a/xen/arch/powerpc/domain.c +++ b/xen/arch/powerpc/domain.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/xen/arch/x86/genapic/es7000plat.c b/xen/arch/x86/genapic/es7000plat.c index 1d7d0d5776..56752061c7 100644 --- a/xen/arch/x86/genapic/es7000plat.c +++ b/xen/arch/x86/genapic/es7000plat.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/xen/arch/x86/shutdown.c b/xen/arch/x86/shutdown.c index 4f59b2c983..76dbcca5d2 100644 --- a/xen/arch/x86/shutdown.c +++ b/xen/arch/x86/shutdown.c @@ -11,19 +11,16 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include #include -#include -#include -#include - -/* opt_noreboot: If true, machine will need manual reset on error. */ -static int opt_noreboot = 0; -boolean_param("noreboot", opt_noreboot); /* reboot_str: comma-separated list of reboot options. */ static char __initdata reboot_str[10] = ""; @@ -204,12 +201,6 @@ void machine_restart(char * __unused) { int i; - if ( opt_noreboot ) - { - printk("Reboot disabled on cmdline: require manual reset\n"); - machine_halt(); - } - watchdog_disable(); console_start_sync(); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 45d73bc511..2ce1f00562 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index 3c6d81f21d..4e8c4b075d 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 6b674a5b53..f0fa99349b 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/xen/common/Makefile b/xen/common/Makefile index be3179afdc..4cfde1c83b 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -16,6 +16,7 @@ obj-y += sched_bvt.o obj-y += sched_credit.o obj-y += sched_sedf.o obj-y += schedule.o +obj-y += shutdown.o obj-y += softirq.o obj-y += string.o obj-y += symbols.o diff --git a/xen/common/domain.c b/xen/common/domain.c index c837a31c69..5908a23399 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -282,36 +283,12 @@ static __init int domain_shutdown_finaliser_init(void) } __initcall(domain_shutdown_finaliser_init); - void domain_shutdown(struct domain *d, u8 reason) { struct vcpu *v; if ( d->domain_id == 0 ) - { - extern void machine_restart(char *); - extern void machine_halt(void); - - debugger_trap_immediate(); - - if ( reason == SHUTDOWN_poweroff ) - { - printk("Domain 0 halted: halting machine.\n"); - machine_halt(); - } - else if ( reason == SHUTDOWN_crash ) - { - printk("Domain 0 crashed: rebooting machine in 5 seconds.\n"); - watchdog_disable(); - mdelay(5000); - machine_restart(0); - } - else - { - printk("Domain 0 shutdown: rebooting machine.\n"); - machine_restart(0); - } - } + dom0_shutdown(reason); /* Mark the domain as shutting down. */ d->shutdown_code = reason; diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index 3f286e3ae6..21e5862a08 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/xen/common/shutdown.c b/xen/common/shutdown.c new file mode 100644 index 0000000000..1baea16205 --- /dev/null +++ b/xen/common/shutdown.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* opt_noreboot: If true, machine will need manual reset on error. */ +int opt_noreboot; +boolean_param("noreboot", opt_noreboot); + +static void maybe_reboot(void) +{ + if ( opt_noreboot ) + { + printk("'noreboot' set - not rebooting.\n"); + machine_halt(); + } + else + { + printk("rebooting machine in 5 seconds.\n"); + watchdog_disable(); + mdelay(5000); + machine_restart(NULL); + } +} + +void dom0_shutdown(u8 reason) +{ + debugger_trap_immediate(); + + switch ( reason ) + { + case SHUTDOWN_poweroff: + { + printk("Domain 0 halted: halting machine.\n"); + machine_halt(); + break; /* not reached */ + } + + case SHUTDOWN_crash: + { + printk("Domain 0 crashed: "); + maybe_reboot(); + break; /* not reached */ + } + + case SHUTDOWN_reboot: + { + printk("Domain 0 shutdown: rebooting machine.\n"); + machine_restart(NULL); + break; /* not reached */ + } + + default: + { + printk("Domain 0 shutdown (unknown reason %u): ", reason); + maybe_reboot(); + break; /* not reached */ + } + } +} + diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index f5ca219f9c..1e7f107966 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -730,14 +731,24 @@ void panic(const char *fmt, ...) printk("Panic on CPU %d:\n", smp_processor_id()); printk(buf); printk("****************************************\n\n"); - printk("Reboot in five seconds...\n"); + if ( opt_noreboot ) + printk("Manual reset required ('noreboot' specified)\n"); + else + printk("Reboot in five seconds...\n"); spin_unlock_irqrestore(&lock, flags); debugger_trap_immediate(); - watchdog_disable(); - mdelay(5000); - machine_restart(0); + if ( opt_noreboot ) + { + machine_halt(); + } + else + { + watchdog_disable(); + mdelay(5000); + machine_restart(NULL); + } } void __bug(char *file, int line) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index 4ee5237804..93bb556204 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/xen/include/xen/reboot.h b/xen/include/xen/reboot.h deleted file mode 100644 index 8ef2d96cf8..0000000000 --- a/xen/include/xen/reboot.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _LINUX_REBOOT_H -#define _LINUX_REBOOT_H - -extern void machine_restart(char *cmd); -extern void machine_halt(void); -extern void machine_power_off(void); - -#endif /* _LINUX_REBOOT_H */ diff --git a/xen/include/xen/shutdown.h b/xen/include/xen/shutdown.h new file mode 100644 index 0000000000..cfe20002d8 --- /dev/null +++ b/xen/include/xen/shutdown.h @@ -0,0 +1,13 @@ +#ifndef __XEN_SHUTDOWN_H__ +#define __XEN_SHUTDOWN_H__ + +/* opt_noreboot: If true, machine will need manual reset on error. */ +extern int opt_noreboot; + +void dom0_shutdown(u8 reason); + +void machine_restart(char *cmd); +void machine_halt(void); +void machine_power_off(void); + +#endif /* __XEN_SHUTDOWN_H__ */ From ed79bfa130dbc949ec2d23cf7d6d538d9222691e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 7 Aug 2006 15:42:25 +0100 Subject: [PATCH 103/111] [XEN] Allow users to specify mce/nomce boot parameters. Signed-off-by: Arun Sharma --- xen/arch/x86/cpu/mcheck/mce.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c index bc95f1717f..68a8ff59ed 100644 --- a/xen/arch/x86/cpu/mcheck/mce.c +++ b/xen/arch/x86/cpu/mcheck/mce.c @@ -69,5 +69,5 @@ static int __init mcheck_enable(char *str) return 0; } -__setup("nomce", mcheck_disable); -__setup("mce", mcheck_enable); +custom_param("nomce", mcheck_disable); +custom_param("mce", mcheck_enable); From a6e8b7effa20241c47ecd5c5fad549ac64d903a5 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 7 Aug 2006 15:53:06 +0100 Subject: [PATCH 104/111] Change DOM0_PERFCCONTROL: remove array limit. Descriptors and values are passed by two distinct buffers. Signed-off-by: Tristan Gingold --- tools/libxc/xc_misc.c | 13 +++++++-- tools/libxc/xenctrl.h | 9 +++++-- tools/misc/xenperf.c | 50 +++++++++++++++++++++-------------- xen/common/perfc.c | 37 ++++++++++++++++---------- xen/include/public/dom0_ops.h | 7 +++-- 5 files changed, 76 insertions(+), 40 deletions(-) diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index 4c0cb24b90..5a63e9e719 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -68,7 +68,10 @@ int xc_sched_id(int xc_handle, int xc_perfc_control(int xc_handle, uint32_t opcode, - xc_perfc_desc_t *desc) + xc_perfc_desc_t *desc, + xc_perfc_val_t *val, + int *nbr_desc, + int *nbr_val) { int rc; DECLARE_DOM0_OP; @@ -76,10 +79,16 @@ int xc_perfc_control(int xc_handle, op.cmd = DOM0_PERFCCONTROL; op.u.perfccontrol.op = opcode; set_xen_guest_handle(op.u.perfccontrol.desc, desc); + set_xen_guest_handle(op.u.perfccontrol.val, val); rc = do_dom0_op(xc_handle, &op); - return (rc == 0) ? op.u.perfccontrol.nr_counters : rc; + if (nbr_desc) + *nbr_desc = op.u.perfccontrol.nr_counters; + if (nbr_val) + *nbr_val = op.u.perfccontrol.nr_vals; + + return rc; } long long xc_msr_read(int xc_handle, int cpu_mask, int msr) diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index a405171279..58bf7b2dcb 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -466,10 +466,15 @@ unsigned long xc_make_page_below_4G(int xc_handle, uint32_t domid, unsigned long mfn); typedef dom0_perfc_desc_t xc_perfc_desc_t; -/* IMPORTANT: The caller is responsible for mlock()'ing the @desc array. */ +typedef dom0_perfc_val_t xc_perfc_val_t; +/* IMPORTANT: The caller is responsible for mlock()'ing the @desc and @val + arrays. */ int xc_perfc_control(int xc_handle, uint32_t op, - xc_perfc_desc_t *desc); + xc_perfc_desc_t *desc, + xc_perfc_val_t *val, + int *nbr_desc, + int *nbr_val); /* read/write msr */ long long xc_msr_read(int xc_handle, int cpu_mask, int msr); diff --git a/tools/misc/xenperf.c b/tools/misc/xenperf.c index 1572780c3d..1054d022f7 100644 --- a/tools/misc/xenperf.c +++ b/tools/misc/xenperf.c @@ -22,7 +22,10 @@ int main(int argc, char *argv[]) { int i, j, xc_handle; xc_perfc_desc_t *pcd; - unsigned int num, sum, reset = 0, full = 0; + xc_perfc_val_t *pcv; + xc_perfc_val_t *val; + int num_desc, num_val; + unsigned int sum, reset = 0, full = 0; if ( argc > 1 ) { @@ -62,7 +65,7 @@ int main(int argc, char *argv[]) if ( reset ) { if ( xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_RESET, - NULL) < 0 ) + NULL, NULL, NULL, NULL) != 0 ) { fprintf(stderr, "Error reseting performance counters: %d (%s)\n", errno, strerror(errno)); @@ -72,47 +75,54 @@ int main(int argc, char *argv[]) return 0; } + if ( xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_QUERY, + NULL, NULL, &num_desc, &num_val) != 0 ) + { + fprintf(stderr, "Error getting number of perf counters: %d (%s)\n", + errno, strerror(errno)); + return 1; + } - if ( (num = xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_QUERY, - NULL)) < 0 ) + pcd = malloc(sizeof(*pcd) * num_desc); + pcv = malloc(sizeof(*pcv) * num_val); + + if ( pcd == NULL + || mlock(pcd, sizeof(*pcd) * num_desc) != 0 + || pcv == NULL + || mlock(pcd, sizeof(*pcv) * num_val) != 0) { - fprintf(stderr, "Error getting number of perf counters: %d (%s)\n", - errno, strerror(errno)); - return 1; - } - - pcd = malloc(sizeof(*pcd) * num); - - if ( mlock(pcd, sizeof(*pcd) * num) != 0 ) - { - fprintf(stderr, "Could not mlock descriptor buffer: %d (%s)\n", + fprintf(stderr, "Could not alloc or mlock buffers: %d (%s)\n", errno, strerror(errno)); exit(-1); } - if ( xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_QUERY, pcd) <= 0 ) + if ( xc_perfc_control(xc_handle, DOM0_PERFCCONTROL_OP_QUERY, + pcd, pcv, NULL, NULL) != 0 ) { - fprintf(stderr, "Error getting perf counter description: %d (%s)\n", + fprintf(stderr, "Error getting perf counter: %d (%s)\n", errno, strerror(errno)); return 1; } - munlock(pcd, sizeof(*pcd) * num); + munlock(pcd, sizeof(*pcd) * num_desc); + munlock(pcv, sizeof(*pcv) * num_val); - for ( i = 0; i < num; i++ ) + val = pcv; + for ( i = 0; i < num_desc; i++ ) { printf ("%-35s ", pcd[i].name); sum = 0; for ( j = 0; j < pcd[i].nr_vals; j++ ) - sum += pcd[i].vals[j]; + sum += val[j]; printf ("T=%10u ", (unsigned int)sum); if ( full || (pcd[i].nr_vals <= 4) ) for ( j = 0; j < pcd[i].nr_vals; j++ ) - printf(" %10u", (unsigned int)pcd[i].vals[j]); + printf(" %10u", (unsigned int)val[j]); printf("\n"); + val += pcd[i].nr_vals; } return 0; diff --git a/xen/common/perfc.c b/xen/common/perfc.c index 830e1876b5..e2ba33383e 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -136,10 +136,14 @@ void perfc_reset(unsigned char key) } static dom0_perfc_desc_t perfc_d[NR_PERFCTRS]; +static dom0_perfc_val_t *perfc_vals; +static int perfc_nbr_vals; static int perfc_init = 0; -static int perfc_copy_info(XEN_GUEST_HANDLE(dom0_perfc_desc_t) desc) +static int perfc_copy_info(XEN_GUEST_HANDLE(dom0_perfc_desc_t) desc, + XEN_GUEST_HANDLE(dom0_perfc_val_t) val) { unsigned int i, j; + unsigned int v = 0; atomic_t *counters = (atomic_t *)&perfcounters; if ( guest_handle_is_null(desc) ) @@ -169,13 +173,13 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(dom0_perfc_desc_t) desc) perfc_d[i].nr_vals = perfc_info[i].nr_elements; break; } - - if ( perfc_d[i].nr_vals > ARRAY_SIZE(perfc_d[i].vals) ) - perfc_d[i].nr_vals = ARRAY_SIZE(perfc_d[i].vals); + perfc_nbr_vals += perfc_d[i].nr_vals; } - + perfc_vals = xmalloc_array(dom0_perfc_val_t, perfc_nbr_vals); perfc_init = 1; } + if (perfc_vals == NULL) + return -ENOMEM; /* We gather the counts together every time. */ for ( i = 0; i < NR_PERFCTRS; i++ ) @@ -184,26 +188,30 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(dom0_perfc_desc_t) desc) { case TYPE_SINGLE: case TYPE_S_SINGLE: - perfc_d[i].vals[0] = atomic_read(&counters[0]); + perfc_vals[v++] = atomic_read(&counters[0]); counters += 1; break; case TYPE_CPU: case TYPE_S_CPU: for ( j = 0; j < perfc_d[i].nr_vals; j++ ) - perfc_d[i].vals[j] = atomic_read(&counters[j]); + perfc_vals[v++] = atomic_read(&counters[j]); counters += NR_CPUS; break; case TYPE_ARRAY: case TYPE_S_ARRAY: for ( j = 0; j < perfc_d[i].nr_vals; j++ ) - perfc_d[i].vals[j] = atomic_read(&counters[j]); + perfc_vals[v++] = atomic_read(&counters[j]); counters += perfc_info[i].nr_elements; break; } } + BUG_ON(v != perfc_nbr_vals); - return (copy_to_guest(desc, (dom0_perfc_desc_t *)perfc_d, NR_PERFCTRS) ? - -EFAULT : 0); + if (copy_to_guest(desc, (dom0_perfc_desc_t *)perfc_d, NR_PERFCTRS)) + return -EFAULT; + if (copy_to_guest(val, perfc_vals, perfc_nbr_vals)) + return -EFAULT; + return 0; } /* Dom0 control of perf counters */ @@ -213,20 +221,18 @@ int perfc_control(dom0_perfccontrol_t *pc) u32 op = pc->op; int rc; - pc->nr_counters = NR_PERFCTRS; - spin_lock(&lock); switch ( op ) { case DOM0_PERFCCONTROL_OP_RESET: - perfc_copy_info(pc->desc); + perfc_copy_info(pc->desc, pc->val); perfc_reset(0); rc = 0; break; case DOM0_PERFCCONTROL_OP_QUERY: - perfc_copy_info(pc->desc); + perfc_copy_info(pc->desc, pc->val); rc = 0; break; @@ -237,6 +243,9 @@ int perfc_control(dom0_perfccontrol_t *pc) spin_unlock(&lock); + pc->nr_counters = NR_PERFCTRS; + pc->nr_vals = perfc_nbr_vals; + return rc; } diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index afaf4d5c65..d211ca1624 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -361,17 +361,20 @@ DEFINE_XEN_GUEST_HANDLE(dom0_read_memtype_t); struct dom0_perfc_desc { char name[80]; /* name of perf counter */ uint32_t nr_vals; /* number of values for this counter */ - uint32_t vals[64]; /* array of values */ }; typedef struct dom0_perfc_desc dom0_perfc_desc_t; DEFINE_XEN_GUEST_HANDLE(dom0_perfc_desc_t); +typedef uint32_t dom0_perfc_val_t; +DEFINE_XEN_GUEST_HANDLE(dom0_perfc_val_t); struct dom0_perfccontrol { /* IN variables. */ uint32_t op; /* DOM0_PERFCCONTROL_OP_??? */ /* OUT variables. */ - uint32_t nr_counters; /* number of counters */ + uint32_t nr_counters; /* number of counters description */ + uint32_t nr_vals; /* number of values */ XEN_GUEST_HANDLE(dom0_perfc_desc_t) desc; /* counter information (or NULL) */ + XEN_GUEST_HANDLE(dom0_perfc_val_t) val; /* counter values (or NULL) */ }; typedef struct dom0_perfccontrol dom0_perfccontrol_t; DEFINE_XEN_GUEST_HANDLE(dom0_perfccontrol_t); From cea4bbec3f9ba683f94e0f25948f1dd1bbfa8454 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 7 Aug 2006 15:55:39 +0100 Subject: [PATCH 105/111] Provides hooks for perfc print/reset/gather. These arch-neutral hooks allow architectures to report hardware counters. Signed-off-by: Tristan Gingold --- xen/common/perfc.c | 12 ++++++------ xen/include/asm-ia64/perfc.h | 16 ++++++++++++++++ xen/include/asm-powerpc/perfc.h | 16 ++++++++++++++++ xen/include/asm-x86/perfc.h | 23 +++++++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 xen/include/asm-ia64/perfc.h create mode 100644 xen/include/asm-powerpc/perfc.h create mode 100644 xen/include/asm-x86/perfc.h diff --git a/xen/common/perfc.c b/xen/common/perfc.c index e2ba33383e..4eb696a594 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -8,6 +8,7 @@ #include #include #include +#include #undef PERFCOUNTER #undef PERFCOUNTER_CPU @@ -89,9 +90,7 @@ void perfc_printall(unsigned char key) printk("\n"); } -#ifdef PERF_ARRAYS - ptwr_eip_stat_print(); -#endif + arch_perfc_printall(); } void perfc_reset(unsigned char key) @@ -130,9 +129,7 @@ void perfc_reset(unsigned char key) } } -#ifdef PERF_ARRAYS - ptwr_eip_stat_reset(); -#endif + arch_perfc_reset (); } static dom0_perfc_desc_t perfc_d[NR_PERFCTRS]; @@ -181,6 +178,9 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(dom0_perfc_desc_t) desc, if (perfc_vals == NULL) return -ENOMEM; + /* Architecture may fill counters from hardware. */ + arch_perfc_gather(); + /* We gather the counts together every time. */ for ( i = 0; i < NR_PERFCTRS; i++ ) { diff --git a/xen/include/asm-ia64/perfc.h b/xen/include/asm-ia64/perfc.h new file mode 100644 index 0000000000..37a0ac3bc5 --- /dev/null +++ b/xen/include/asm-ia64/perfc.h @@ -0,0 +1,16 @@ +#ifndef __ASM_PERFC_H__ +#define __ASM_PERFC_H__ + +static inline void arch_perfc_printall (void) +{ +} + +static inline void arch_perfc_reset (void) +{ +} + +static inline void arch_perfc_gather (void) +{ +} + +#endif diff --git a/xen/include/asm-powerpc/perfc.h b/xen/include/asm-powerpc/perfc.h new file mode 100644 index 0000000000..37a0ac3bc5 --- /dev/null +++ b/xen/include/asm-powerpc/perfc.h @@ -0,0 +1,16 @@ +#ifndef __ASM_PERFC_H__ +#define __ASM_PERFC_H__ + +static inline void arch_perfc_printall (void) +{ +} + +static inline void arch_perfc_reset (void) +{ +} + +static inline void arch_perfc_gather (void) +{ +} + +#endif diff --git a/xen/include/asm-x86/perfc.h b/xen/include/asm-x86/perfc.h new file mode 100644 index 0000000000..1999bd0dbf --- /dev/null +++ b/xen/include/asm-x86/perfc.h @@ -0,0 +1,23 @@ +#ifndef __ASM_PERFC_H__ +#define __ASM_PERFC_H__ +#include + +static inline void arch_perfc_printall (void) +{ +#ifdef PERF_ARRAYS + ptwr_eip_stat_print(); +#endif +} + +static inline void arch_perfc_reset (void) +{ +#ifdef PERF_ARRAYS + ptwr_eip_stat_reset(); +#endif +} + +static inline void arch_perfc_gather (void) +{ +} + +#endif From 7e9fd035dac638bceeb68a20574ad19bda888a76 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 7 Aug 2006 16:07:20 +0100 Subject: [PATCH 106/111] [LINUX] Fix a couple of benign diffs against vanilla spinlock.h. From: Jan Beulich Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/include/asm-i386/spinlock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/include/asm-i386/spinlock.h b/linux-2.6-xen-sparse/include/asm-i386/spinlock.h index 99b96b85d6..65a211156e 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/spinlock.h +++ b/linux-2.6-xen-sparse/include/asm-i386/spinlock.h @@ -23,7 +23,7 @@ (*(volatile signed char *)(&(x)->slock) <= 0) #define __raw_spin_lock_string \ - "\n1:\n" \ + "\n1:\t" \ LOCK \ "decb %0\n\t" \ "jns 3f\n" \ @@ -35,7 +35,7 @@ "3:\n\t" #define __raw_spin_lock_string_flags \ - "\n1:\n" \ + "\n1:\t" \ LOCK \ "decb %0\n\t" \ "jns 4f\n\t" \ From acf531c5658bcea80b80f7bac16a77dc2ff4dfaf Mon Sep 17 00:00:00 2001 From: "jchesterfield@wicket.uk.xensource.com" Date: Mon, 7 Aug 2006 18:11:59 +0100 Subject: [PATCH 107/111] Limit blktap static link to just libaio. --- tools/blktap/drivers/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/blktap/drivers/Makefile b/tools/blktap/drivers/Makefile index a2bdd02259..7c7d4ab27c 100644 --- a/tools/blktap/drivers/Makefile +++ b/tools/blktap/drivers/Makefile @@ -33,9 +33,7 @@ LIBS += -lcrypto LIBS += -lz LIBS += -L$(XEN_XENSTORE) -lxenstore -AIOLIBS := -L $(LIBAIO_DIR) -AIOLIBS += -laio -AIOLIBS += -static +AIOLIBS := $(LIBAIO_DIR)/libaio.a BLK-OBJS := block-aio.o BLK-OBJS += block-sync.o From b5d8830efe36951a99ba5d2055dc28c797096274 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Mon, 7 Aug 2006 18:25:30 +0100 Subject: [PATCH 108/111] [qemu] Update ioemu to qemu 0.8.2. Signed-off-by: Christian Limpach --- tools/ioemu/Changelog | 19 + tools/ioemu/Makefile | 31 +- tools/ioemu/Makefile.target | 54 +- tools/ioemu/TODO | 10 +- tools/ioemu/VERSION | 2 +- tools/ioemu/audio/alsaaudio.c | 19 +- tools/ioemu/audio/audio.c | 444 ++++++- tools/ioemu/audio/audio.h | 46 +- tools/ioemu/audio/audio_int.h | 40 +- tools/ioemu/audio/audio_template.h | 33 +- tools/ioemu/audio/coreaudio.c | 12 +- tools/ioemu/audio/dsound_template.h | 18 +- tools/ioemu/audio/dsoundaudio.c | 8 +- tools/ioemu/audio/fmodaudio.c | 10 +- tools/ioemu/audio/noaudio.c | 40 +- tools/ioemu/audio/ossaudio.c | 40 +- tools/ioemu/audio/rate_template.h | 2 +- tools/ioemu/audio/sdlaudio.c | 8 +- tools/ioemu/audio/wavaudio.c | 4 +- tools/ioemu/audio/wavcapture.c | 164 +++ tools/ioemu/block-cow.c | 7 + tools/ioemu/block-qcow.c | 7 + tools/ioemu/block-vmdk.c | 7 + tools/ioemu/block-vpc.c | 2 +- tools/ioemu/block-vvfat.c | 1 + tools/ioemu/block.c | 61 + tools/ioemu/block_int.h | 1 + tools/ioemu/cocoa.m | 56 +- tools/ioemu/configure | 45 +- tools/ioemu/console.c | 170 ++- tools/ioemu/cpu-all.h | 102 +- tools/ioemu/cpu-defs.h | 2 +- tools/ioemu/cpu-exec.c | 47 +- tools/ioemu/disas.c | 4 +- tools/ioemu/dyngen-exec.h | 27 +- tools/ioemu/dyngen.c | 92 +- tools/ioemu/dyngen.h | 8 +- tools/ioemu/elf.h | 2 + tools/ioemu/exec-all.h | 2 +- tools/ioemu/exec.c | 33 +- tools/ioemu/fpu/softfloat-native.c | 13 +- tools/ioemu/gdbstub.c | 125 +- tools/ioemu/hw/acpi-dsdt.dsl | 559 +++++++++ tools/ioemu/hw/acpi-dsdt.hex | 278 +++++ tools/ioemu/hw/acpi.c | 615 +++++++++ tools/ioemu/hw/adlib.c | 4 +- tools/ioemu/hw/apb_pci.c | 232 ++++ tools/ioemu/hw/apic.c | 4 +- tools/ioemu/hw/cdrom.c | 156 +++ tools/ioemu/hw/cuda.c | 2 +- tools/ioemu/hw/es1370.c | 10 +- tools/ioemu/hw/esp.c | 516 +++----- tools/ioemu/hw/grackle_pci.c | 156 +++ tools/ioemu/hw/i8259.c | 2 +- tools/ioemu/hw/ide.c | 134 +- tools/ioemu/hw/lsi53c895a.c | 1571 +++++++++++++++++++++++ tools/ioemu/hw/m48t59.c | 10 +- tools/ioemu/hw/mips_r4k.c | 6 +- tools/ioemu/hw/ne2000.c | 2 +- tools/ioemu/hw/pc.c | 55 +- tools/ioemu/hw/pci.c | 1477 +--------------------- tools/ioemu/hw/pci_host.h | 93 ++ tools/ioemu/hw/pcnet.c | 1789 +++++++++++++++++++++++++++ tools/ioemu/hw/pcspk.c | 4 +- tools/ioemu/hw/pflash_cfi02.c | 624 ++++++++++ tools/ioemu/hw/piix4acpi.c | 4 +- tools/ioemu/hw/piix_pci.c | 435 +++++++ tools/ioemu/hw/pl050.c | 2 +- tools/ioemu/hw/ppc_chrp.c | 20 +- tools/ioemu/hw/ppc_prep.c | 4 + tools/ioemu/hw/prep_pci.c | 167 +++ tools/ioemu/hw/rtl8139.c | 1482 +++++++++++++++------- tools/ioemu/hw/sb16.c | 94 +- tools/ioemu/hw/scsi-disk.c | 478 +++++++ tools/ioemu/hw/sh7750.c | 2 +- tools/ioemu/hw/slavio_intctl.c | 2 +- tools/ioemu/hw/slavio_timer.c | 2 +- tools/ioemu/hw/sun4m.c | 14 +- tools/ioemu/hw/sun4u.c | 18 +- tools/ioemu/hw/unin_pci.c | 261 ++++ tools/ioemu/hw/usb-hid.c | 14 + tools/ioemu/hw/usb-hub.c | 26 +- tools/ioemu/hw/usb-msd.c | 402 ++++++ tools/ioemu/hw/usb-ohci.c | 1190 ++++++++++++++++++ tools/ioemu/hw/usb-uhci.c | 22 +- tools/ioemu/hw/usb.h | 18 +- tools/ioemu/hw/versatile_pci.c | 119 ++ tools/ioemu/hw/versatilepb.c | 216 +++- tools/ioemu/hw/vga.c | 129 +- tools/ioemu/hw/vga_int.h | 9 +- tools/ioemu/hw/vga_template.h | 232 ++-- tools/ioemu/kqemu.c | 11 +- tools/ioemu/loader.c | 2 +- tools/ioemu/monitor.c | 164 ++- tools/ioemu/osdep.c | 22 +- tools/ioemu/osdep.h | 2 + tools/ioemu/pc-bios/README | 9 +- tools/ioemu/pc-bios/bios.diff | 146 ++- tools/ioemu/pc-bios/vgabios.diff | 1661 +++++++++++++------------ tools/ioemu/pc-bios/video.x | Bin 0 -> 12192 bytes tools/ioemu/qemu-doc.texi | 240 +++- tools/ioemu/qemu-img.c | 33 +- tools/ioemu/sdl.c | 27 +- tools/ioemu/tap-win32.c | 8 + tools/ioemu/target-i386/exec.h | 3 + tools/ioemu/target-i386/helper.c | 39 +- tools/ioemu/target-i386/helper2.c | 33 +- tools/ioemu/target-i386/op.c | 15 +- tools/ioemu/target-i386/translate.c | 93 +- tools/ioemu/tests/Makefile | 3 +- tools/ioemu/tests/test-i386.c | 22 +- tools/ioemu/usb-linux.c | 42 +- tools/ioemu/vl.c | 1268 +++++++++++++------ tools/ioemu/vl.h | 135 +- tools/ioemu/vnc.c | 254 +++- tools/ioemu/vnchextile.h | 46 +- 116 files changed, 15400 insertions(+), 4357 deletions(-) create mode 100644 tools/ioemu/audio/wavcapture.c mode change 100644 => 100755 tools/ioemu/configure create mode 100644 tools/ioemu/hw/acpi-dsdt.dsl create mode 100644 tools/ioemu/hw/acpi-dsdt.hex create mode 100644 tools/ioemu/hw/acpi.c create mode 100644 tools/ioemu/hw/apb_pci.c create mode 100644 tools/ioemu/hw/cdrom.c create mode 100644 tools/ioemu/hw/grackle_pci.c create mode 100644 tools/ioemu/hw/lsi53c895a.c create mode 100644 tools/ioemu/hw/pci_host.h create mode 100644 tools/ioemu/hw/pcnet.c create mode 100644 tools/ioemu/hw/pflash_cfi02.c create mode 100644 tools/ioemu/hw/piix_pci.c create mode 100644 tools/ioemu/hw/prep_pci.c create mode 100644 tools/ioemu/hw/scsi-disk.c create mode 100644 tools/ioemu/hw/unin_pci.c create mode 100644 tools/ioemu/hw/usb-msd.c create mode 100644 tools/ioemu/hw/usb-ohci.c create mode 100644 tools/ioemu/hw/versatile_pci.c create mode 100644 tools/ioemu/pc-bios/video.x diff --git a/tools/ioemu/Changelog b/tools/ioemu/Changelog index 659b5017ba..58f3e5e743 100644 --- a/tools/ioemu/Changelog +++ b/tools/ioemu/Changelog @@ -1,3 +1,22 @@ +version 0.8.2: + + - ACPI support + - PC VGA BIOS fixes + - switch to OpenBios for SPARC targets (Blue Swirl) + - VNC server fixes + - MIPS FPU support (Marius Groeger) + - Solaris/SPARC host support (Ben Taylor) + - PPC breakpoints and single stepping (Jason Wessel) + - USB updates (Paul Brook) + - UDP/TCP/telnet character devices (Jason Wessel) + - Windows sparse file support (Frediano Ziglio) + - RTL8139 NIC TCP segmentation offloading (Igor Kovalenko) + - PCNET NIC support (Antony T Curtis) + - Support for variable frequency host CPUs + - Workaround for win32 SMP hosts + - Support for AMD Flash memories (Jocelyn Mayer) + - Audio capture to WAV files support (malc) + version 0.8.1: - USB tablet support (Brad Campbell, Anthony Liguori) diff --git a/tools/ioemu/Makefile b/tools/ioemu/Makefile index a8625a152e..1d8b61d3b2 100644 --- a/tools/ioemu/Makefile +++ b/tools/ioemu/Makefile @@ -1,12 +1,20 @@ +# Makefile for QEMU. + XEN_ROOT=../.. include $(XEN_ROOT)/tools/Rules.mk -include config-host.mak +.PHONY: all clean distclean dvi info install install-doc tar tarbin \ + speed test test2 html dvi info + CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif +ifeq ($(ARCH),sparc) +CFLAGS+=-mcpu=ultrasparc +endif LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE @@ -20,11 +28,15 @@ else DOCS= endif -all: $(DOCS) - for d in $(TARGET_DIRS); do \ - $(MAKE) -C $$d $@ || exit 1 ; \ - done +TOOLS= +all: $(TOOLS) $(DOCS) recurse-all + +subdir-%: + $(MAKE) -C $(subst subdir-,,$@) all + +recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) + qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) @@ -42,6 +54,7 @@ clean: distclean: clean rm -f config-host.mak config-host.h $(DOCS) + rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr} for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done @@ -63,7 +76,7 @@ install: all $(if $(BUILD_DOCS),install-doc) # $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" # mkdir -p "$(DESTDIR)$(datadir)" # for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -# video.x proll.elf linux_boot.bin; do \ +# video.x openbios-sparc32 linux_boot.bin; do \ # $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ # done ifndef CONFIG_WIN32 @@ -106,6 +119,12 @@ qemu-img.1: qemu-img.texi perl -w $(SRC_PATH)/texi2pod.pl $< qemu-img.pod pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ +info: qemu-doc.info qemu-tech.info + +dvi: qemu-doc.dvi qemu-tech.dvi + +html: qemu-doc.html qemu-tech.html + FILE=qemu-$(shell cat VERSION) # tar release (use 'make -k tar' on a checkouted tree) @@ -138,7 +157,7 @@ tarbin: $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ $(datadir)/video.x \ - $(datadir)/proll.elf \ + $(datadir)/openbios-sparc32 \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/tools/ioemu/Makefile.target b/tools/ioemu/Makefile.target index e08247310d..ac740cec47 100644 --- a/tools/ioemu/Makefile.target +++ b/tools/ioemu/Makefile.target @@ -40,6 +40,11 @@ ifeq ($(TARGET_ARCH),arm) TARGET_ARCH2=armeb endif endif +ifeq ($(TARGET_ARCH),sh4) + ifeq ($(TARGET_WORDS_BIGENDIAN),yes) + TARGET_ARCH2=sh4eb + endif +endif ifeq ($(TARGET_ARCH),mips) ifneq ($(TARGET_WORDS_BIGENDIAN),yes) TARGET_ARCH2=mipsel @@ -114,17 +119,24 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld endif ifeq ($(ARCH),sparc) -CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +ifeq ($(CONFIG_SOLARIS),yes) +CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 +LDFLAGS+=-m32 +OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 +else +CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 LDFLAGS+=-m32 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat # -static is used to avoid g1/g3 usage by the dynamic linker LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static endif +endif ifeq ($(ARCH),sparc64) -CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 LDFLAGS+=-m64 +LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 endif @@ -186,7 +198,12 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o +OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ + elfload.o linuxload.o +ifdef TARGET_HAS_BFLT +OBJS+= flatload.o +endif + ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o endif @@ -323,18 +340,23 @@ endif ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o endif +AUDIODRV+= wavcapture.o + +# SCSI layer +VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o # USB layer -VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o +VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o # PCI network cards -VL_OBJS+= ne2000.o rtl8139.o +VL_OBJS+= ne2000.o rtl8139.o pcnet.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o -VL_OBJS+= cirrus_vga.o mixeng.o parallel.o +VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o +VL_OBJS+= usb-uhci.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o DEFINES += -DHAS_AUDIO @@ -343,6 +365,7 @@ ifeq ($(TARGET_BASE_ARCH), ppc) VL_OBJS+= ppc.o ide.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 +VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) @@ -351,7 +374,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o +VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o else @@ -362,6 +385,7 @@ endif ifeq ($(TARGET_BASE_ARCH), arm) VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o +VL_OBJS+= versatile_pci.o endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o @@ -399,7 +423,7 @@ endif ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 ifndef CONFIG_SOLARIS -VL_LIBS=-lutil +VL_LIBS=-lutil -lrt endif endif endif @@ -412,6 +436,11 @@ ifeq ($(ARCH),ia64) VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld endif +ifeq ($(ARCH),sparc64) +VL_LDFLAGS+=-m64 +VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld +endif + ifdef CONFIG_WIN32 SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole endif @@ -491,6 +520,13 @@ endif loader.o: loader.c elf_ops.h +acpi.o: acpi.c acpi-dsdt.hex + +ifdef BUILD_ACPI_TABLES +$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl + iasl -tc -p $@ $< +endif + ifeq ($(TARGET_ARCH), sh4) op.o: op.c op_mem.c cpu.h op_helper.o: op_helper.c exec.h cpu.h @@ -501,6 +537,8 @@ sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h tc58128.o: tc58128.c endif +$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff --git a/tools/ioemu/TODO b/tools/ioemu/TODO index 8cc9aa55f0..516ea87bf4 100644 --- a/tools/ioemu/TODO +++ b/tools/ioemu/TODO @@ -1,24 +1,20 @@ short term: ---------- -- support variable tsc freq +- cycle counter for all archs - cpu_interrupt() win32/SMP fix +- support variable tsc freq - USB host async - IDE async - debug option in 'configure' script + disable -fomit-frame-pointer - Precise VGA timings for old games/demos (malc patch) - merge PIC spurious interrupt patch -- merge Solaris patch - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) - config file (at least for windows/Mac OS X) -- commit message if execution of code in IO memory - update doc: PCI infos. -- VNC patch + Synaptic patch. - basic VGA optimizations -- physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch (different exception handling + CS.limit support) - do not resize vga if invalid size. - avoid looping if only exceptions -- cycle counter for all archs - TLB code protection support for PPC - see openMosix Doc - disable SMC handling for ARM/SPARC/PPC (not finished) @@ -31,12 +27,10 @@ short term: - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). -- fix arm fpu rounding (at least for float->integer conversions) ppc specific: ------------ - TLB invalidate not needed if msr_pr changes -- SPR_ENCODE() not useful - enable shift optimizations ? linux-user specific: diff --git a/tools/ioemu/VERSION b/tools/ioemu/VERSION index c18d72be30..53a48a1e8c 100644 --- a/tools/ioemu/VERSION +++ b/tools/ioemu/VERSION @@ -1 +1 @@ -0.8.1 \ No newline at end of file +0.8.2 \ No newline at end of file diff --git a/tools/ioemu/audio/alsaaudio.c b/tools/ioemu/audio/alsaaudio.c index 30f1e5076f..71e5235664 100644 --- a/tools/ioemu/audio/alsaaudio.c +++ b/tools/ioemu/audio/alsaaudio.c @@ -61,8 +61,8 @@ static struct { .size_in_usec_in = 1, .size_in_usec_out = 1, #endif - .pcm_name_out = "hw:0,0", - .pcm_name_in = "hw:0,0", + .pcm_name_out = "default", + .pcm_name_in = "default", #ifdef HIGH_LATENCY .buffer_size_in = 400000, .period_size_in = 400000 / 4, @@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw) } } - mixeng_clear (src, written); rpos = (rpos + written) % hw->samples; samples -= written; len -= written; @@ -663,12 +662,9 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); @@ -752,12 +748,9 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); diff --git a/tools/ioemu/audio/audio.c b/tools/ioemu/audio/audio.c index 811b207c55..556e6fdbcb 100644 --- a/tools/ioemu/audio/audio.c +++ b/tools/ioemu/audio/audio.c @@ -29,6 +29,7 @@ /* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ +/* #define DEBUG_CAPTURE */ #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" @@ -137,7 +138,7 @@ int audio_bug (const char *funcname, int cond) if (cond) { static int shown; - AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname); + AUD_log (NULL, "A bug was just triggered in %s\n", funcname); if (!shown) { shown = 1; AUD_log (NULL, "Save all your work and restart without audio\n"); @@ -509,14 +510,28 @@ static void audio_print_settings (audsettings_t *as) AUD_log (NULL, "invalid(%d)", as->fmt); break; } + + AUD_log (NULL, " endianness="); + switch (as->endianness) { + case 0: + AUD_log (NULL, "little"); + break; + case 1: + AUD_log (NULL, "big"); + break; + default: + AUD_log (NULL, "invalid"); + break; + } AUD_log (NULL, "\n"); } -static int audio_validate_settigs (audsettings_t *as) +static int audio_validate_settings (audsettings_t *as) { int invalid; invalid = as->nchannels != 1 && as->nchannels != 2; + invalid |= as->endianness != 0 && as->endianness != 1; switch (as->fmt) { case AUD_FMT_S8: @@ -530,11 +545,7 @@ static int audio_validate_settigs (audsettings_t *as) } invalid |= as->freq <= 0; - - if (invalid) { - return -1; - } - return 0; + return invalid ? -1 : 0; } static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) @@ -556,14 +567,11 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) return info->freq == as->freq && info->nchannels == as->nchannels && info->sign == sign - && info->bits == bits; + && info->bits == bits + && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS); } -void audio_pcm_init_info ( - struct audio_pcm_info *info, - audsettings_t *as, - int swap_endian - ) +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) { int bits = 8, sign = 0; @@ -587,7 +595,7 @@ void audio_pcm_init_info ( info->shift = (as->nchannels == 2) + (bits == 16); info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; - info->swap_endian = swap_endian; + info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); } void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) @@ -609,7 +617,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) int shift = info->nchannels - 1; short s = INT16_MAX; - if (info->swap_endian) { + if (info->swap_endianness) { s = bswap16 (s); } @@ -620,6 +628,143 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) } } +/* + * Capture + */ +static void noop_conv (st_sample_t *dst, const void *src, + int samples, volume_t *vol) +{ + (void) src; + (void) dst; + (void) samples; + (void) vol; +} + +static CaptureVoiceOut *audio_pcm_capture_find_specific ( + AudioState *s, + audsettings_t *as + ) +{ + CaptureVoiceOut *cap; + + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + if (audio_pcm_info_eq (&cap->hw.info, as)) { + return cap; + } + } + return NULL; +} + +static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd) +{ + struct capture_callback *cb; + +#ifdef DEBUG_CAPTURE + dolog ("notification %d sent\n", cmd); +#endif + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.notify (cb->opaque, cmd); + } +} + +static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled) +{ + if (cap->hw.enabled != enabled) { + audcnotification_e cmd; + cap->hw.enabled = enabled; + cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE; + audio_notify_capture (cap, cmd); + } +} + +static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap) +{ + HWVoiceOut *hw = &cap->hw; + SWVoiceOut *sw; + int enabled = 0; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active) { + enabled = 1; + break; + } + } + audio_capture_maybe_changed (cap, enabled); +} + +static void audio_detach_capture (HWVoiceOut *hw) +{ + SWVoiceCap *sc = hw->cap_head.lh_first; + + while (sc) { + SWVoiceCap *sc1 = sc->entries.le_next; + SWVoiceOut *sw = &sc->sw; + CaptureVoiceOut *cap = sc->cap; + int was_active = sw->active; + + if (sw->rate) { + st_rate_stop (sw->rate); + sw->rate = NULL; + } + + LIST_REMOVE (sw, entries); + LIST_REMOVE (sc, entries); + qemu_free (sc); + if (was_active) { + /* We have removed soft voice from the capture: + this might have changed the overall status of the capture + since this might have been the only active voice */ + audio_recalc_and_notify_capture (cap); + } + sc = sc1; + } +} + +static int audio_attach_capture (AudioState *s, HWVoiceOut *hw) +{ + CaptureVoiceOut *cap; + + audio_detach_capture (hw); + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + SWVoiceCap *sc; + SWVoiceOut *sw; + HWVoiceOut *hw_cap = &cap->hw; + + sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc)); + if (!sc) { + dolog ("Could not allocate soft capture voice (%zu bytes)\n", + sizeof (*sc)); + return -1; + } + + sc->cap = cap; + sw = &sc->sw; + sw->hw = hw_cap; + sw->info = hw->info; + sw->empty = 1; + sw->active = hw->enabled; + sw->conv = noop_conv; + sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq; + sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq); + if (!sw->rate) { + dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw)); + qemu_free (sw); + return -1; + } + LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); + LIST_INSERT_HEAD (&hw->cap_head, sc, entries); +#ifdef DEBUG_CAPTURE + asprintf (&sw->name, "for %p %d,%d,%d", + hw, sw->info.freq, sw->info.bits, sw->info.nchannels); + dolog ("Added %s active = %d\n", sw->name, sw->active); +#endif + if (sw->active) { + audio_capture_maybe_changed (cap, 1); + } + } + return 0; +} + /* * Hard voice (capture) */ @@ -796,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) } if (live == hwsamples) { +#ifdef DEBUG_OUT + dolog ("%s is full %d\n", sw->name, live); +#endif return 0; } @@ -914,19 +1062,14 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) hw = sw->hw; if (sw->active != on) { SWVoiceOut *temp_sw; + SWVoiceCap *sc; if (on) { - int total; - hw->pending_disable = 0; if (!hw->enabled) { hw->enabled = 1; hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); } - - if (sw->empty) { - total = 0; - } } else { if (hw->enabled) { @@ -940,6 +1083,13 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) hw->pending_disable = nb_active == 1; } } + + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + sc->sw.active = hw->enabled; + if (hw->enabled) { + audio_capture_maybe_changed (sc->cap, 1); + } + } sw->active = on; } } @@ -997,7 +1147,7 @@ static int audio_get_avail (SWVoiceIn *sw) } ldebug ( - "%s: get_avail live %d ret %lld\n", + "%s: get_avail live %d ret %" PRId64 "\n", SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift ); @@ -1023,7 +1173,7 @@ static int audio_get_free (SWVoiceOut *sw) dead = sw->hw->samples - live; #ifdef DEBUG_OUT - dolog ("%s: get_free live %d dead %d ret %lld\n", + dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); #endif @@ -1031,6 +1181,43 @@ static int audio_get_free (SWVoiceOut *sw) return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; } +static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) +{ + int n; + + if (hw->enabled) { + SWVoiceCap *sc; + + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + SWVoiceOut *sw = &sc->sw; + int rpos2 = rpos; + + n = samples; + while (n) { + int till_end_of_hw = hw->samples - rpos2; + int to_write = audio_MIN (till_end_of_hw, n); + int bytes = to_write << hw->info.shift; + int written; + + sw->buf = hw->mix_buf + rpos2; + written = audio_pcm_sw_write (sw, NULL, bytes); + if (written - bytes) { + dolog ("Could not mix %d bytes into a capture " + "buffer, mixed %d\n", + bytes, written); + break; + } + n -= to_write; + rpos2 = (rpos2 + to_write) % hw->samples; + } + } + } + + n = audio_MIN (samples, hw->samples - rpos); + mixeng_clear (hw->mix_buf + rpos, n); + mixeng_clear (hw->mix_buf, samples - n); +} + static void audio_run_out (AudioState *s) { HWVoiceOut *hw = NULL; @@ -1038,7 +1225,7 @@ static void audio_run_out (AudioState *s) while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) { int played; - int live, free, nb_live, cleanup_required; + int live, free, nb_live, cleanup_required, prev_rpos; live = audio_pcm_hw_get_live_out2 (hw, &nb_live); if (!nb_live) { @@ -1051,12 +1238,17 @@ static void audio_run_out (AudioState *s) } if (hw->pending_disable && !nb_live) { + SWVoiceCap *sc; #ifdef DEBUG_OUT dolog ("Disabling voice\n"); #endif hw->enabled = 0; hw->pending_disable = 0; hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + sc->sw.active = 0; + audio_recalc_and_notify_capture (sc->cap); + } continue; } @@ -1072,6 +1264,7 @@ static void audio_run_out (AudioState *s) continue; } + prev_rpos = hw->rpos; played = hw->pcm_ops->run_out (hw); if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", @@ -1085,6 +1278,7 @@ static void audio_run_out (AudioState *s) if (played) { hw->ts_helper += played; + audio_capture_mix_and_clear (hw, prev_rpos, played); } cleanup_required = 0; @@ -1115,15 +1309,18 @@ static void audio_run_out (AudioState *s) } if (cleanup_required) { - restart: - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + SWVoiceOut *sw1; + + sw = hw->sw_head.lh_first; + while (sw) { + sw1 = sw->entries.le_next; if (!sw->active && !sw->callback.fn) { #ifdef DEBUG_PLIVE dolog ("Finishing with old voice\n"); #endif audio_close_out (s, sw); - goto restart; /* play it safe */ } + sw = sw1; } } } @@ -1158,12 +1355,60 @@ static void audio_run_in (AudioState *s) } } +static void audio_run_capture (AudioState *s) +{ + CaptureVoiceOut *cap; + + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + int live, rpos, captured; + HWVoiceOut *hw = &cap->hw; + SWVoiceOut *sw; + + captured = live = audio_pcm_hw_get_live_out (hw); + rpos = hw->rpos; + while (live) { + int left = hw->samples - rpos; + int to_capture = audio_MIN (live, left); + st_sample_t *src; + struct capture_callback *cb; + + src = hw->mix_buf + rpos; + hw->clip (cap->buf, src, to_capture); + mixeng_clear (src, to_capture); + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.capture (cb->opaque, cap->buf, + to_capture << hw->info.shift); + } + rpos = (rpos + to_capture) % hw->samples; + live -= to_capture; + } + hw->rpos = rpos; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (!sw->active && sw->empty) { + continue; + } + + if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) { + dolog ("captured=%d sw->total_hw_samples_mixed=%d\n", + captured, sw->total_hw_samples_mixed); + captured = sw->total_hw_samples_mixed; + } + + sw->total_hw_samples_mixed -= captured; + sw->empty = sw->total_hw_samples_mixed == 0; + } + } +} + static void audio_timer (void *opaque) { AudioState *s = opaque; audio_run_out (s); audio_run_in (s); + audio_run_capture (s); qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); } @@ -1327,8 +1572,19 @@ static void audio_atexit (void) HWVoiceIn *hwi = NULL; while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { + SWVoiceCap *sc; + hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); hwo->pcm_ops->fini_out (hwo); + + for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) { + CaptureVoiceOut *cap = sc->cap; + struct capture_callback *cb; + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.destroy (cb->opaque); + } + } } while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) { @@ -1383,6 +1639,7 @@ AudioState *AUD_init (void) LIST_INIT (&s->hw_head_out); LIST_INIT (&s->hw_head_in); + LIST_INIT (&s->cap_head); atexit (audio_atexit); s->ts = qemu_new_timer (vm_clock, audio_timer, s); @@ -1479,3 +1736,136 @@ AudioState *AUD_init (void) qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); return s; } + +CaptureVoiceOut *AUD_add_capture ( + AudioState *s, + audsettings_t *as, + struct audio_capture_ops *ops, + void *cb_opaque + ) +{ + CaptureVoiceOut *cap; + struct capture_callback *cb; + + if (!s) { + /* XXX suppress */ + s = &glob_audio_state; + } + + if (audio_validate_settings (as)) { + dolog ("Invalid settings were passed when trying to add capture\n"); + audio_print_settings (as); + goto err0; + } + + cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); + if (!cb) { + dolog ("Could not allocate capture callback information, size %zu\n", + sizeof (*cb)); + goto err0; + } + cb->ops = *ops; + cb->opaque = cb_opaque; + + cap = audio_pcm_capture_find_specific (s, as); + if (cap) { + LIST_INSERT_HEAD (&cap->cb_head, cb, entries); + return cap; + } + else { + HWVoiceOut *hw; + CaptureVoiceOut *cap; + + cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap)); + if (!cap) { + dolog ("Could not allocate capture voice, size %zu\n", + sizeof (*cap)); + goto err1; + } + + hw = &cap->hw; + LIST_INIT (&hw->sw_head); + LIST_INIT (&cap->cb_head); + + /* XXX find a more elegant way */ + hw->samples = 4096 * 4; + hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, + sizeof (st_sample_t)); + if (!hw->mix_buf) { + dolog ("Could not allocate capture mix buffer (%d samples)\n", + hw->samples); + goto err2; + } + + audio_pcm_init_info (&hw->info, as); + + cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!cap->buf) { + dolog ("Could not allocate capture buffer " + "(%d samples, each %d bytes)\n", + hw->samples, 1 << hw->info.shift); + goto err3; + } + + hw->clip = mixeng_clip + [hw->info.nchannels == 2] + [hw->info.sign] + [hw->info.swap_endianness] + [hw->info.bits == 16]; + + LIST_INSERT_HEAD (&s->cap_head, cap, entries); + LIST_INSERT_HEAD (&cap->cb_head, cb, entries); + + hw = NULL; + while ((hw = audio_pcm_hw_find_any_out (s, hw))) { + audio_attach_capture (s, hw); + } + return cap; + + err3: + qemu_free (cap->hw.mix_buf); + err2: + qemu_free (cap); + err1: + qemu_free (cb); + err0: + return NULL; + } +} + +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) +{ + struct capture_callback *cb; + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + if (cb->opaque == cb_opaque) { + cb->ops.destroy (cb_opaque); + LIST_REMOVE (cb, entries); + qemu_free (cb); + + if (!cap->cb_head.lh_first) { + SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1; + + while (sw) { + SWVoiceCap *sc = (SWVoiceCap *) sw; +#ifdef DEBUG_CAPTURE + dolog ("freeing %s\n", sw->name); +#endif + + sw1 = sw->entries.le_next; + if (sw->rate) { + st_rate_stop (sw->rate); + sw->rate = NULL; + } + LIST_REMOVE (sw, entries); + LIST_REMOVE (sc, entries); + qemu_free (sc); + sw = sw1; + } + LIST_REMOVE (cap, entries); + qemu_free (cap); + } + return; + } + } +} diff --git a/tools/ioemu/audio/audio.h b/tools/ioemu/audio/audio.h index 169b5f636a..c097f391bb 100644 --- a/tools/ioemu/audio/audio.h +++ b/tools/ioemu/audio/audio.h @@ -24,6 +24,7 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H +#include "config.h" #include "sys-queue.h" typedef void (*audio_callback_fn_t) (void *opaque, int avail); @@ -35,14 +36,44 @@ typedef enum { AUD_FMT_S16 } audfmt_e; +#ifdef WORDS_BIGENDIAN +#define AUDIO_HOST_ENDIANNESS 1 +#else +#define AUDIO_HOST_ENDIANNESS 0 +#endif + typedef struct { int freq; int nchannels; audfmt_e fmt; + int endianness; } audsettings_t; +typedef enum { + AUD_CNOTIFY_ENABLE, + AUD_CNOTIFY_DISABLE +} audcnotification_e; + +struct audio_capture_ops { + void (*notify) (void *opaque, audcnotification_e cmd); + void (*capture) (void *opaque, void *buf, int size); + void (*destroy) (void *opaque); +}; + +struct capture_ops { + void (*info) (void *opaque); + void (*destroy) (void *opaque); +}; + +typedef struct CaptureState { + void *opaque; + struct capture_ops ops; + LIST_ENTRY (CaptureState) entries; +} CaptureState; + typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; +typedef struct CaptureVoiceOut CaptureVoiceOut; typedef struct SWVoiceIn SWVoiceIn; typedef struct QEMUSoundCard { @@ -66,6 +97,13 @@ AudioState *AUD_init (void); void AUD_help (void); void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); void AUD_remove_card (QEMUSoundCard *card); +CaptureVoiceOut *AUD_add_capture ( + AudioState *s, + audsettings_t *as, + struct audio_capture_ops *ops, + void *opaque + ); +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque); SWVoiceOut *AUD_open_out ( QEMUSoundCard *card, @@ -73,8 +111,7 @@ SWVoiceOut *AUD_open_out ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings, - int sw_endian + audsettings_t *settings ); void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); @@ -92,8 +129,7 @@ SWVoiceIn *AUD_open_in ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings, - int sw_endian + audsettings_t *settings ); void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); @@ -111,7 +147,7 @@ static inline void *advance (void *p, int incr) } uint32_t popcount (uint32_t u); -inline uint32_t lsbindex (uint32_t u); +uint32_t lsbindex (uint32_t u); #ifdef __GNUC__ #define audio_MIN(a, b) ( __extension__ ({ \ diff --git a/tools/ioemu/audio/audio_int.h b/tools/ioemu/audio/audio_int.h index ca240ccc7b..1a15d4ced8 100644 --- a/tools/ioemu/audio/audio_int.h +++ b/tools/ioemu/audio/audio_int.h @@ -61,13 +61,14 @@ struct audio_pcm_info { int align; int shift; int bytes_per_second; - int swap_endian; + int swap_endianness; }; +typedef struct SWVoiceCap SWVoiceCap; + typedef struct HWVoiceOut { int enabled; int pending_disable; - int valid; struct audio_pcm_info info; f_sample *clip; @@ -79,6 +80,7 @@ typedef struct HWVoiceOut { int samples; LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; + LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; struct audio_pcm_ops *pcm_ops; LIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -160,14 +162,34 @@ struct audio_pcm_ops { int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; +struct capture_callback { + struct audio_capture_ops ops; + void *opaque; + LIST_ENTRY (capture_callback) entries; +}; + +struct CaptureVoiceOut { + HWVoiceOut hw; + void *buf; + LIST_HEAD (cb_listhead, capture_callback) cb_head; + LIST_ENTRY (CaptureVoiceOut) entries; +}; + +struct SWVoiceCap { + SWVoiceOut sw; + CaptureVoiceOut *cap; + LIST_ENTRY (SWVoiceCap) entries; +}; + struct AudioState { struct audio_driver *drv; void *drv_opaque; QEMUTimer *ts; - LIST_HEAD (card_head, QEMUSoundCard) card_head; + LIST_HEAD (card_listhead, QEMUSoundCard) card_head; LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; + LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head; int nb_hw_voices_out; int nb_hw_voices_in; }; @@ -182,8 +204,7 @@ extern struct audio_driver coreaudio_audio_driver; extern struct audio_driver dsound_audio_driver; extern volume_t nominal_volume; -void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as, - int swap_endian); +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len); @@ -204,15 +225,6 @@ static inline int audio_ring_dist (int dst, int src, int len) return (dst >= src) ? (dst - src) : (len - src + dst); } -static inline int audio_need_to_swap_endian (int endianness) -{ -#ifdef WORDS_BIGENDIAN - return endianness != 1; -#else - return endianness != 0; -#endif -} - #if defined __GNUC__ #define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2))) #define INIT_FIELD(f) . f diff --git a/tools/ioemu/audio/audio_template.h b/tools/ioemu/audio/audio_template.h index 23d024201a..13e1c3efbb 100644 --- a/tools/ioemu/audio/audio_template.h +++ b/tools/ioemu/audio/audio_template.h @@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYPE) ( SW *sw, HW *hw, const char *name, - audsettings_t *as, - int endian + audsettings_t *as ) { int err; - audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian)); + audio_pcm_init_info (&sw->info, as); sw->hw = hw; sw->active = 0; #ifdef DAC @@ -164,7 +163,7 @@ static int glue (audio_pcm_sw_init_, TYPE) ( #endif [sw->info.nchannels == 2] [sw->info.sign] - [sw->info.swap_endian] + [sw->info.swap_endianness] [sw->info.bits == 16]; sw->name = qemu_strdup (name); @@ -200,6 +199,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) HW *hw = *hwp; if (!hw->sw_head.lh_first) { +#ifdef DAC + audio_detach_capture (hw); +#endif LIST_REMOVE (hw, entries); glue (s->nb_hw_voices_, TYPE) += 1; glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); @@ -266,7 +268,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) hw->pcm_ops = drv->pcm_ops; LIST_INIT (&hw->sw_head); - +#ifdef DAC + LIST_INIT (&hw->cap_head); +#endif if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { goto err0; } @@ -283,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) #endif [hw->info.nchannels == 2] [hw->info.sign] - [hw->info.swap_endian] + [hw->info.swap_endianness] [hw->info.bits == 16]; if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { @@ -292,6 +296,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); glue (s->nb_hw_voices_, TYPE) -= 1; +#ifdef DAC + audio_attach_capture (s, hw); +#endif return hw; err1: @@ -328,8 +335,7 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( AudioState *s, const char *sw_name, - audsettings_t *as, - int sw_endian + audsettings_t *as ) { SW *sw; @@ -357,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { goto err3; } @@ -399,8 +405,7 @@ SW *glue (AUD_open_, TYPE) ( const char *name, void *callback_opaque , audio_callback_fn_t callback_fn, - audsettings_t *as, - int sw_endian + audsettings_t *as ) { AudioState *s; @@ -421,7 +426,7 @@ SW *glue (AUD_open_, TYPE) ( s = card->audio; - if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) { + if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { audio_print_settings (as); goto fail; } @@ -473,12 +478,12 @@ SW *glue (AUD_open_, TYPE) ( } glue (audio_pcm_sw_fini_, TYPE) (sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) { goto fail; } } else { - sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian); + sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); if (!sw) { dolog ("Failed to create voice `%s'\n", name); return NULL; diff --git a/tools/ioemu/audio/coreaudio.c b/tools/ioemu/audio/coreaudio.c index 534fb3ef7c..8512f122b0 100644 --- a/tools/ioemu/audio/coreaudio.c +++ b/tools/ioemu/audio/coreaudio.c @@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc( #endif } - /* cleanup */ - mixeng_clear (src, frameCount); rpos = (rpos + frameCount) % hw->samples; core->decr += frameCount; core->rpos = rpos; @@ -297,7 +295,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) UInt32 propertySize; int err; int bits = 8; - int endianess = 0; const char *typ = "playback"; AudioValueRange frameRange; @@ -310,16 +307,9 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { bits = 16; - endianess = 1; } - audio_pcm_init_info ( - &hw->info, - as, - /* Following is irrelevant actually since we do not use - mixengs clipping routines */ - audio_need_to_swap_endian (endianess) - ); + audio_pcm_init_info (&hw->info, as); /* open default output device */ propertySize = sizeof(core->outputDeviceID); diff --git a/tools/ioemu/audio/dsound_template.h b/tools/ioemu/audio/dsound_template.h index 38ba5b9ca0..0896b04a03 100644 --- a/tools/ioemu/audio/dsound_template.h +++ b/tools/ioemu/audio/dsound_template.h @@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) ( int i; LPVOID p1 = NULL, p2 = NULL; DWORD blen1 = 0, blen2 = 0; + DWORD flag; +#ifdef DSBTYPE_IN + flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; +#else + flag = entire ? DSBLOCK_ENTIREBUFFER : 0; +#endif for (i = 0; i < conf.lock_retries; ++i) { hr = glue (IFACE, _Lock) ( buf, @@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) ( &blen1, &p2, &blen2, - (entire -#ifdef DSBTYPE_IN - ? DSCBLOCK_ENTIREBUFFER -#else - ? DSBLOCK_ENTIREBUFFER -#endif - : 0) + flag ); if (FAILED (hr)) { @@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) } ds->first_time = 1; - - audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); if (bc.dwBufferBytes & hw->info.align) { dolog ( diff --git a/tools/ioemu/audio/dsoundaudio.c b/tools/ioemu/audio/dsoundaudio.c index 63c5a50573..90a0333f13 100644 --- a/tools/ioemu/audio/dsoundaudio.c +++ b/tools/ioemu/audio/dsoundaudio.c @@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) if (src_len1) { hw->clip (dst, src1, src_len1); - mixeng_clear (src1, src_len1); } if (src_len2) { dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - mixeng_clear (src2, src_len2); } hw->rpos = pos % hw->samples; @@ -987,6 +985,12 @@ static void *dsound_audio_init (void) hr = IDirectSound_Initialize (s->dsound, NULL); if (FAILED (hr)) { dsound_logerr (hr, "Could not initialize DirectSound\n"); + + hr = IDirectSound_Release (s->dsound); + if (FAILED (hr)) { + dsound_logerr (hr, "Could not release DirectSound\n"); + } + s->dsound = NULL; return NULL; } diff --git a/tools/ioemu/audio/fmodaudio.c b/tools/ioemu/audio/fmodaudio.c index 072d8a830a..5875ba15e1 100644 --- a/tools/ioemu/audio/fmodaudio.c +++ b/tools/ioemu/audio/fmodaudio.c @@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) if (src_len1) { hw->clip (dst, src1, src_len1); - mixeng_clear (src1, src_len1); } if (src_len2) { dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - mixeng_clear (src2, src_len2); } hw->rpos = pos % hw->samples; @@ -360,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) { int bits16, mode, channel; FMODVoiceOut *fmd = (FMODVoiceOut *) hw; + audsettings_t obt_as = *as; mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( @@ -386,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) fmd->channel = channel; /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); bits16 = (mode & FSOUND_16BITS) != 0; hw->samples = conf.nb_samples; return 0; @@ -420,6 +420,7 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) { int bits16, mode; FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + audsettings_t obt_as = *as; if (conf.broken_adc) { return -1; @@ -442,7 +443,8 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) } /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); bits16 = (mode & FSOUND_16BITS) != 0; hw->samples = conf.nb_samples; return 0; diff --git a/tools/ioemu/audio/noaudio.c b/tools/ioemu/audio/noaudio.c index aa3581168d..a3423e5eb1 100644 --- a/tools/ioemu/audio/noaudio.c +++ b/tools/ioemu/audio/noaudio.c @@ -40,22 +40,21 @@ static int no_run_out (HWVoiceOut *hw) { NoVoiceOut *no = (NoVoiceOut *) hw; int live, decr, samples; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - - if (bytes > INT_MAX) { - samples = INT_MAX >> hw->info.shift; - } - else { - samples = bytes >> hw->info.shift; - } + int64_t now; + int64_t ticks; + int64_t bytes; live = audio_pcm_hw_get_live_out (&no->hw); if (!live) { return 0; } + now = qemu_get_clock (vm_clock); + ticks = now - no->old_ticks; + bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; + bytes = audio_MIN (bytes, INT_MAX); + samples = bytes >> hw->info.shift; + no->old_ticks = now; decr = audio_MIN (live, samples); hw->rpos = (hw->rpos + decr) % hw->samples; @@ -69,7 +68,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len) static int no_init_out (HWVoiceOut *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, as, 0); + audio_pcm_init_info (&hw->info, as); hw->samples = 1024; return 0; } @@ -88,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) static int no_init_in (HWVoiceIn *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, as, 0); + audio_pcm_init_info (&hw->info, as); hw->samples = 1024; return 0; } @@ -101,17 +100,20 @@ static void no_fini_in (HWVoiceIn *hw) static int no_run_in (HWVoiceIn *hw) { NoVoiceIn *no = (NoVoiceIn *) hw; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; int live = audio_pcm_hw_get_live_in (hw); int dead = hw->samples - live; - int samples; + int samples = 0; - bytes = audio_MIN (bytes, INT_MAX); - samples = bytes >> hw->info.shift; - samples = audio_MIN (samples, dead); + if (dead) { + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - no->old_ticks; + int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; + no->old_ticks = now; + bytes = audio_MIN (bytes, INT_MAX); + samples = bytes >> hw->info.shift; + samples = audio_MIN (samples, dead); + } return samples; } diff --git a/tools/ioemu/audio/ossaudio.c b/tools/ioemu/audio/ossaudio.c index 7d12f9e34a..125e4c8ff7 100644 --- a/tools/ioemu/audio/ossaudio.c +++ b/tools/ioemu/audio/ossaudio.c @@ -55,12 +55,14 @@ static struct { int fragsize; const char *devpath_out; const char *devpath_in; + int debug; } conf = { .try_mmap = 0, .nfrags = 4, .fragsize = 4096, .devpath_out = "/dev/dsp", - .devpath_in = "/dev/dsp" + .devpath_in = "/dev/dsp", + .debug = 0 }; struct oss_params { @@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw) return 0; } - if (abinfo.bytes < 0 || abinfo.bytes > bufsize) { - ldebug ("warning: Invalid available size, size=%d bufsize=%d\n", - abinfo.bytes, bufsize); + if (abinfo.bytes > bufsize) { + if (conf.debug) { + dolog ("warning: Invalid available size, size=%d bufsize=%d\n" + "please report your OS/audio hw to malc@pulsesoft.com\n", + abinfo.bytes, bufsize); + } + abinfo.bytes = bufsize; + } + + if (abinfo.bytes < 0) { + if (conf.debug) { + dolog ("warning: Invalid available size, size=%d bufsize=%d\n", + abinfo.bytes, bufsize); + } return 0; } @@ -369,15 +382,12 @@ static int oss_run_out (HWVoiceOut *hw) "alignment %d\n", wbytes, written, hw->info.align + 1); } - mixeng_clear (src, wsamples); decr -= wsamples; rpos = (rpos + wsamples) % hw->samples; break; } } - mixeng_clear (src, convert_samples); - rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; } @@ -443,12 +453,9 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; @@ -587,12 +594,9 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; @@ -730,6 +734,8 @@ static struct audio_option oss_options[] = { "Path to DAC device", NULL, 0}, {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in, "Path to ADC device", NULL, 0}, + {"DEBUG", AUD_OPT_BOOL, &conf.debug, + "Turn on some debugging messages", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; diff --git a/tools/ioemu/audio/rate_template.h b/tools/ioemu/audio/rate_template.h index 3e0e77c94e..398d305e92 100644 --- a/tools/ioemu/audio/rate_template.h +++ b/tools/ioemu/audio/rate_template.h @@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, if (rate->opos_inc == (1ULL + UINT_MAX)) { int i, n = *isamp > *osamp ? *osamp : *isamp; for (i = 0; i < n; i++) { - OP (obuf[i].l, ibuf[i].r); + OP (obuf[i].l, ibuf[i].l); OP (obuf[i].r, ibuf[i].r); } *isamp = n; diff --git a/tools/ioemu/audio/sdlaudio.c b/tools/ioemu/audio/sdlaudio.c index 713c7849d8..f2a6896a52 100644 --- a/tools/ioemu/audio/sdlaudio.c +++ b/tools/ioemu/audio/sdlaudio.c @@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ hw->clip (buf, src, chunk); - mixeng_clear (src, chunk); sdl->rpos = (sdl->rpos + chunk) % hw->samples; to_mix -= chunk; buf += chunk << hw->info.shift; @@ -336,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.channels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianess; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianess) - ); + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; s->initialized = 1; diff --git a/tools/ioemu/audio/wavaudio.c b/tools/ioemu/audio/wavaudio.c index 18d2bb0c74..c359fc4f2b 100644 --- a/tools/ioemu/audio/wavaudio.c +++ b/tools/ioemu/audio/wavaudio.c @@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw) hw->clip (dst, src, convert_samples); qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); - mixeng_clear (src, convert_samples); rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; @@ -136,7 +135,8 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) hdr[34] = bits16 ? 0x10 : 0x08; - audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0)); + wav_as.endianness = 0; + audio_pcm_init_info (&hw->info, &wav_as); hw->samples = 1024; wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); diff --git a/tools/ioemu/audio/wavcapture.c b/tools/ioemu/audio/wavcapture.c new file mode 100644 index 0000000000..0f6f7bf016 --- /dev/null +++ b/tools/ioemu/audio/wavcapture.c @@ -0,0 +1,164 @@ +#include "vl.h" + +typedef struct { + QEMUFile *f; + int bytes; + char *path; + int freq; + int bits; + int nchannels; + CaptureVoiceOut *cap; +} WAVState; + +/* VICE code: Store number as little endian. */ +static void le_store (uint8_t *buf, uint32_t val, int len) +{ + int i; + for (i = 0; i < len; i++) { + buf[i] = (uint8_t) (val & 0xff); + val >>= 8; + } +} + +static void wav_notify (void *opaque, audcnotification_e cmd) +{ + (void) opaque; + (void) cmd; +} + +static void wav_destroy (void *opaque) +{ + WAVState *wav = opaque; + uint8_t rlen[4]; + uint8_t dlen[4]; + uint32_t datalen = wav->bytes; + uint32_t rifflen = datalen + 36; + + if (!wav->f) { + return; + } + + le_store (rlen, rifflen, 4); + le_store (dlen, datalen, 4); + + qemu_fseek (wav->f, 4, SEEK_SET); + qemu_put_buffer (wav->f, rlen, 4); + + qemu_fseek (wav->f, 32, SEEK_CUR); + qemu_put_buffer (wav->f, dlen, 4); + fclose (wav->f); + if (wav->path) { + qemu_free (wav->path); + } +} + +static void wav_capture (void *opaque, void *buf, int size) +{ + WAVState *wav = opaque; + + qemu_put_buffer (wav->f, buf, size); + wav->bytes += size; +} + +static void wav_capture_destroy (void *opaque) +{ + WAVState *wav = opaque; + + AUD_del_capture (wav->cap, wav); +} + +static void wav_capture_info (void *opaque) +{ + WAVState *wav = opaque; + char *path = wav->path; + + term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n", + wav->freq, wav->bits, wav->nchannels, + path ? path : "", wav->bytes); +} + +static struct capture_ops wav_capture_ops = { + .destroy = wav_capture_destroy, + .info = wav_capture_info +}; + +int wav_start_capture (CaptureState *s, const char *path, int freq, + int bits, int nchannels) +{ + WAVState *wav; + uint8_t hdr[] = { + 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, + 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 + }; + audsettings_t as; + struct audio_capture_ops ops; + int stereo, bits16, shift; + CaptureVoiceOut *cap; + + if (bits != 8 && bits != 16) { + term_printf ("incorrect bit count %d, must be 8 or 16\n", bits); + return -1; + } + + if (nchannels != 1 && nchannels != 2) { + term_printf ("incorrect channel count %d, must be 1 or 2\n", + nchannels); + return -1; + } + + stereo = nchannels == 2; + bits16 = bits == 16; + + as.freq = freq; + as.nchannels = 1 << stereo; + as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; + as.endianness = 0; + + ops.notify = wav_notify; + ops.capture = wav_capture; + ops.destroy = wav_destroy; + + wav = qemu_mallocz (sizeof (*wav)); + if (!wav) { + term_printf ("Could not allocate memory for wav capture (%zu bytes)", + sizeof (*wav)); + return -1; + } + + shift = bits16 + stereo; + hdr[34] = bits16 ? 0x10 : 0x08; + + le_store (hdr + 22, as.nchannels, 2); + le_store (hdr + 24, freq, 4); + le_store (hdr + 28, freq << shift, 4); + le_store (hdr + 32, 1 << shift, 2); + + wav->f = fopen (path, "wb"); + if (!wav->f) { + term_printf ("Failed to open wave file `%s'\nReason: %s\n", + path, strerror (errno)); + qemu_free (wav); + return -1; + } + + wav->path = qemu_strdup (path); + wav->bits = bits; + wav->nchannels = nchannels; + wav->freq = freq; + + qemu_put_buffer (wav->f, hdr, sizeof (hdr)); + + cap = AUD_add_capture (NULL, &as, &ops, wav); + if (!cap) { + term_printf ("Failed to add audio capture\n"); + qemu_free (wav); + return -1; + } + + wav->cap = cap; + s->opaque = wav; + s->ops = wav_capture_ops; + return 0; +} diff --git a/tools/ioemu/block-cow.c b/tools/ioemu/block-cow.c index 6a42a46ef4..ff73cac0f9 100644 --- a/tools/ioemu/block-cow.c +++ b/tools/ioemu/block-cow.c @@ -250,6 +250,12 @@ static int cow_create(const char *filename, int64_t image_sectors, return 0; } +static void cow_flush(BlockDriverState *bs) +{ + BDRVCowState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_cow = { "cow", sizeof(BDRVCowState), @@ -259,6 +265,7 @@ BlockDriver bdrv_cow = { cow_write, cow_close, cow_create, + cow_flush, cow_is_allocated, }; #endif diff --git a/tools/ioemu/block-qcow.c b/tools/ioemu/block-qcow.c index b28fe58d72..d7fd9d534b 100644 --- a/tools/ioemu/block-qcow.c +++ b/tools/ioemu/block-qcow.c @@ -693,6 +693,12 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, return 0; } +static void qcow_flush(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_qcow = { "qcow", sizeof(BDRVQcowState), @@ -702,6 +708,7 @@ BlockDriver bdrv_qcow = { qcow_write, qcow_close, qcow_create, + qcow_flush, qcow_is_allocated, qcow_set_key, qcow_make_empty diff --git a/tools/ioemu/block-vmdk.c b/tools/ioemu/block-vmdk.c index 03bbb7a765..3143077f49 100644 --- a/tools/ioemu/block-vmdk.c +++ b/tools/ioemu/block-vmdk.c @@ -426,6 +426,12 @@ static void vmdk_close(BlockDriverState *bs) close(s->fd); } +static void vmdk_flush(BlockDriverState *bs) +{ + BDRVVmdkState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_vmdk = { "vmdk", sizeof(BDRVVmdkState), @@ -435,5 +441,6 @@ BlockDriver bdrv_vmdk = { vmdk_write, vmdk_close, vmdk_create, + vmdk_flush, vmdk_is_allocated, }; diff --git a/tools/ioemu/block-vpc.c b/tools/ioemu/block-vpc.c index e4c51bab2a..bdc3b8891c 100644 --- a/tools/ioemu/block-vpc.c +++ b/tools/ioemu/block-vpc.c @@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) bitmap_offset = 512 * s->pagetable[pagetable_index]; block_offset = bitmap_offset + 512 + (512 * pageentry_index); -// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n", +// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n", // sector_num, pagetable_index, pageentry_index, // bitmap_offset, block_offset); diff --git a/tools/ioemu/block-vvfat.c b/tools/ioemu/block-vvfat.c index 84d2a08ad7..9dedf9115f 100644 --- a/tools/ioemu/block-vvfat.c +++ b/tools/ioemu/block-vvfat.c @@ -2772,6 +2772,7 @@ BlockDriver bdrv_vvfat = { vvfat_read, vvfat_write, vvfat_close, + NULL, /* ??? Not sure if we can do any meaningful flushing. */ NULL, vvfat_is_allocated }; diff --git a/tools/ioemu/block.c b/tools/ioemu/block.c index 330d5c146d..210cb7a51e 100644 --- a/tools/ioemu/block.c +++ b/tools/ioemu/block.c @@ -615,6 +615,14 @@ const char *bdrv_get_device_name(BlockDriverState *bs) return bs->device_name; } +void bdrv_flush(BlockDriverState *bs) +{ + if (bs->drv->bdrv_flush) + bs->drv->bdrv_flush(bs); + if (bs->backing_hd) + bdrv_flush(bs->backing_hd); +} + void bdrv_info(void) { BlockDriverState *bs; @@ -754,6 +762,51 @@ static void raw_close(BlockDriverState *bs) close(s->fd); } +#ifdef _WIN32 +#include +#include + +int qemu_ftruncate64(int fd, int64_t length) +{ + LARGE_INTEGER li; + LONG high; + HANDLE h; + BOOL res; + + if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) + return -1; + + h = (HANDLE)_get_osfhandle(fd); + + /* get current position, ftruncate do not change position */ + li.HighPart = 0; + li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); + if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) + return -1; + + high = length >> 32; + if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN)) + return -1; + res = SetEndOfFile(h); + + /* back to old position */ + SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); + return res ? 0 : -1; +} + +static int set_sparse(int fd) +{ + DWORD returned; + return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, + NULL, 0, NULL, 0, &returned, NULL); +} +#else +static inline int set_sparse(int fd) +{ + return 1; +} +#endif + static int raw_create(const char *filename, int64_t total_size, const char *backing_file, int flags) { @@ -766,11 +819,18 @@ static int raw_create(const char *filename, int64_t total_size, 0644); if (fd < 0) return -EIO; + set_sparse(fd); ftruncate(fd, total_size * 512); close(fd); return 0; } +static void raw_flush(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_raw = { "raw", sizeof(BDRVRawState), @@ -780,6 +840,7 @@ BlockDriver bdrv_raw = { raw_write, raw_close, raw_create, + raw_flush, }; void bdrv_init(void) diff --git a/tools/ioemu/block_int.h b/tools/ioemu/block_int.h index e3038160e6..c2a2e30a9f 100644 --- a/tools/ioemu/block_int.h +++ b/tools/ioemu/block_int.h @@ -36,6 +36,7 @@ struct BlockDriver { void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, int64_t total_sectors, const char *backing_file, int flags); + void (*bdrv_flush)(BlockDriverState *bs); int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); diff --git a/tools/ioemu/cocoa.m b/tools/ioemu/cocoa.m index b508b52144..9551affa34 100644 --- a/tools/ioemu/cocoa.m +++ b/tools/ioemu/cocoa.m @@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState *ds) kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front /* handle monitor key events */ } else { + int keysym = 0; + switch([event keyCode]) { - case 123: - kbd_put_keysym(QEMU_KEY_LEFT); - break; - case 124: - kbd_put_keysym(QEMU_KEY_RIGHT); - break; - case 125: - kbd_put_keysym(QEMU_KEY_DOWN); - break; - case 126: - kbd_put_keysym(QEMU_KEY_UP); - break; - default: - kbd_put_keysym([[event characters] characterAtIndex:0]); - break; + case 115: + keysym = QEMU_KEY_HOME; + break; + case 117: + keysym = QEMU_KEY_DELETE; + break; + case 119: + keysym = QEMU_KEY_END; + break; + case 123: + keysym = QEMU_KEY_LEFT; + break; + case 124: + keysym = QEMU_KEY_RIGHT; + break; + case 125: + keysym = QEMU_KEY_DOWN; + break; + case 126: + keysym = QEMU_KEY_UP; + break; + default: + { + NSString *ks = [event characters]; + + if ([ks length] > 0) + keysym = [ks characterAtIndex:0]; + } } + if (keysym) + kbd_put_keysym(keysym); } } } @@ -867,10 +884,9 @@ static void setupWindowMenu(void) /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; - } -static void CustomApplicationMain (argc, argv) +static void CustomApplicationMain(void) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; QemuCocoaGUIController *gui_controller; @@ -904,8 +920,8 @@ int main(int argc, char **argv) { gArgc = argc; gArgv = argv; - - CustomApplicationMain (argc, argv); - + + CustomApplicationMain(); + return 0; } diff --git a/tools/ioemu/configure b/tools/ioemu/configure old mode 100644 new mode 100755 index 9b7c8050fa..98e1d03bfd --- a/tools/ioemu/configure +++ b/tools/ioemu/configure @@ -96,6 +96,8 @@ check_gcc="no" softmmu="yes" user="no" build_docs="no" +build_acpi_tables="no" +uname_release="" # OS specific targetos=`uname -s` @@ -212,7 +214,7 @@ for opt do ;; --fmod-inc=*) fmod_inc="$optarg" ;; - --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" + --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no" ;; --disable-slirp) slirp="no" ;; @@ -236,6 +238,10 @@ for opt do ;; --enable-user) user="yes" ;; + --enable-uname-release=*) uname_release="$optarg" + ;; + --enable-iasl) build_acpi_tables="yes" + ;; esac done @@ -283,6 +289,8 @@ echo " --enable-user enable all linux usermode emulation targets" echo " --disable-user disable all linux usermode emulation targets" echo " --fmod-lib path to FMOD library" echo " --fmod-inc path to FMOD includes" +echo " --enable-uname-release=R Return R for uname -r in usermode emulation" +echo " --enable-iasl compilation of ACPI tables with the IASL compiler" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 @@ -292,15 +300,21 @@ cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" -if [ ! -x "`which $cc`" ] ; then - echo "Compiler $cc could not be found" - exit +# check that the C compiler works. +cat > $TMPC </dev/null ; then + : C compiler works ok +else + echo "ERROR: \"$cc\" either does not exist or does not work" + exit 1 fi if test "$mingw32" = "yes" ; then linux="no" EXESUF=".exe" - gdbstub="no" oss="no" if [ "$cpu" = "i386" ] ; then kqemu="yes" @@ -551,6 +565,8 @@ fi echo "FMOD support $fmod $fmod_support" echo "kqemu support $kqemu" echo "Documentation $build_docs" +[ ! -z "$uname_release" ] && \ +echo "uname -r $uname_release" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -703,6 +719,9 @@ echo "TARGET_DIRS=$target_list" >> $config_mak if [ "$build_docs" = "yes" ] ; then echo "BUILD_DOCS=yes" >> $config_mak fi +if [ "$build_acpi_tables" = "yes" ] ; then + echo "BUILD_ACPI_TABLES=yes" >> $config_mak +fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then @@ -711,6 +730,8 @@ if [ "$bsd" = "yes" ] ; then echo "#define _BSD 1" >> $config_h fi +echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h + for target in $target_list; do target_dir="$target" config_mak=$target_dir/config.mak @@ -723,6 +744,7 @@ target_bigendian="no" [ "$target_cpu" = "ppc" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes +[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes target_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" @@ -759,6 +781,7 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h echo "include ../config-host.mak" >> $config_mak echo "#include \"../config-host.h\"" >> $config_h +bflt="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h @@ -779,6 +802,7 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then echo "TARGET_ARCH=arm" >> $config_mak echo "#define TARGET_ARCH \"arm\"" >> $config_h echo "#define TARGET_ARM 1" >> $config_h + bflt="yes" elif test "$target_cpu" = "sparc" ; then echo "TARGET_ARCH=sparc" >> $config_mak echo "#define TARGET_ARCH \"sparc\"" >> $config_h @@ -809,10 +833,13 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then echo "TARGET_ARCH=mips" >> $config_mak echo "#define TARGET_ARCH \"mips\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h -elif test "$target_cpu" = "sh4" ; then + echo "CONFIG_SOFTFLOAT=yes" >> $config_mak + echo "#define CONFIG_SOFTFLOAT 1" >> $config_h +elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then echo "TARGET_ARCH=sh4" >> $config_mak echo "#define TARGET_ARCH \"sh4\"" >> $config_h echo "#define TARGET_SH4 1" >> $config_h + bflt="yes" else echo "Unsupported target CPU" exit 1 @@ -834,10 +861,14 @@ if expr $target : '.*-dm' > /dev/null ; then echo "#define CONFIG_DM 1" >> $config_h fi -if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h fi +if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then + echo "TARGET_HAS_BFLT=yes" >> $config_mak + echo "#define TARGET_HAS_BFLT 1" >> $config_h +fi # sdl defines if test "$target_user_only" = "no"; then diff --git a/tools/ioemu/console.c b/tools/ioemu/console.c index 9174881840..dfa93bcef6 100644 --- a/tools/ioemu/console.c +++ b/tools/ioemu/console.c @@ -27,8 +27,8 @@ #define DEFAULT_BACKSCROLL 512 #define MAX_CONSOLES 12 -#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) -#define RGB(r, g, b) RGBA(r, g, b, 0xff) +#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff) typedef struct TextAttributes { uint8_t fgcol:4; @@ -53,6 +53,57 @@ enum TTYState { TTY_STATE_CSI, }; +typedef struct QEMUFIFO { + uint8_t *buf; + int buf_size; + int count, wptr, rptr; +} QEMUFIFO; + +int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) +{ + int l, len; + + l = f->buf_size - f->count; + if (len1 > l) + len1 = l; + len = len1; + while (len > 0) { + l = f->buf_size - f->wptr; + if (l > len) + l = len; + memcpy(f->buf + f->wptr, buf, l); + f->wptr += l; + if (f->wptr >= f->buf_size) + f->wptr = 0; + buf += l; + len -= l; + } + f->count += len1; + return len1; +} + +int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) +{ + int l, len; + + if (len1 > f->count) + len1 = f->count; + len = len1; + while (len > 0) { + l = f->buf_size - f->rptr; + if (l > len) + l = len; + memcpy(buf, f->buf + f->rptr, l); + f->rptr += l; + if (f->rptr >= f->buf_size) + f->rptr = 0; + buf += l; + len -= l; + } + f->count -= len1; + return len1; +} + /* ??? This is mis-named. It is used for both text and graphical consoles. */ struct TextConsole { @@ -81,8 +132,13 @@ struct TextConsole { int nb_esc_params; /* kbd read handler */ + IOCanRWHandler *fd_can_read; IOReadHandler *fd_read; void *fd_opaque; + /* fifo for key pressed */ + QEMUFIFO out_fifo; + uint8_t out_fifo_buf[16]; + QEMUTimer *kbd_timer; }; static TextConsole *active_console; @@ -274,24 +330,24 @@ enum color_names { static const uint32_t color_table_rgb[2][8] = { { /* dark */ - RGB(0x00, 0x00, 0x00), /* black */ - RGB(0xaa, 0x00, 0x00), /* red */ - RGB(0x00, 0xaa, 0x00), /* green */ - RGB(0xaa, 0xaa, 0x00), /* yellow */ - RGB(0x00, 0x00, 0xaa), /* blue */ - RGB(0xaa, 0x00, 0xaa), /* magenta */ - RGB(0x00, 0xaa, 0xaa), /* cyan */ - RGB(0xaa, 0xaa, 0xaa), /* white */ + QEMU_RGB(0x00, 0x00, 0x00), /* black */ + QEMU_RGB(0xaa, 0x00, 0x00), /* red */ + QEMU_RGB(0x00, 0xaa, 0x00), /* green */ + QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */ + QEMU_RGB(0x00, 0x00, 0xaa), /* blue */ + QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */ + QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */ + QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */ }, { /* bright */ - RGB(0x00, 0x00, 0x00), /* black */ - RGB(0xff, 0x00, 0x00), /* red */ - RGB(0x00, 0xff, 0x00), /* green */ - RGB(0xff, 0xff, 0x00), /* yellow */ - RGB(0x00, 0x00, 0xff), /* blue */ - RGB(0xff, 0x00, 0xff), /* magenta */ - RGB(0x00, 0xff, 0xff), /* cyan */ - RGB(0xff, 0xff, 0xff), /* white */ + QEMU_RGB(0x00, 0x00, 0x00), /* black */ + QEMU_RGB(0xff, 0x00, 0x00), /* red */ + QEMU_RGB(0x00, 0xff, 0x00), /* green */ + QEMU_RGB(0xff, 0xff, 0x00), /* yellow */ + QEMU_RGB(0x00, 0x00, 0xff), /* blue */ + QEMU_RGB(0xff, 0x00, 0xff), /* magenta */ + QEMU_RGB(0x00, 0xff, 0xff), /* cyan */ + QEMU_RGB(0xff, 0xff, 0xff), /* white */ } }; @@ -563,7 +619,6 @@ static void console_put_lf(TextConsole *s) TextCell *c; int x, y1; - s->x = 0; s->y++; if (s->y >= s->height) { s->y = s->height - 1; @@ -712,15 +767,12 @@ static void console_putchar(TextConsole *s, int ch) console_put_lf(s); break; case '\b': /* backspace */ - if(s->x > 0) s->x--; - y1 = (s->y_base + s->y) % s->total_height; - c = &s->cells[y1 * s->width + s->x]; - c->ch = ' '; - c->t_attrib = s->t_attrib; - update_xy(s, s->x, s->y); + if (s->x > 0) + s->x--; break; case '\t': /* tabspace */ if (s->x + (8 - (s->x % 8)) > s->width) { + s->x = 0; console_put_lf(s); } else { s->x = s->x + (8 - (s->x % 8)); @@ -739,8 +791,10 @@ static void console_putchar(TextConsole *s, int ch) c->t_attrib = s->t_attrib; update_xy(s, s->x, s->y); s->x++; - if (s->x >= s->width) + if (s->x >= s->width) { + s->x = 0; console_put_lf(s); + } break; } break; @@ -835,6 +889,7 @@ static void console_chr_add_read_handler(CharDriverState *chr, IOReadHandler *fd_read, void *opaque) { TextConsole *s = chr->opaque; + s->fd_can_read = fd_can_read; s->fd_read = fd_read; s->fd_opaque = opaque; } @@ -854,6 +909,28 @@ static void console_send_event(CharDriverState *chr, int event) } } +static void kbd_send_chars(void *opaque) +{ + TextConsole *s = opaque; + int len; + uint8_t buf[16]; + + len = s->fd_can_read(s->fd_opaque); + if (len > s->out_fifo.count) + len = s->out_fifo.count; + if (len > 0) { + if (len > sizeof(buf)) + len = sizeof(buf); + qemu_fifo_read(&s->out_fifo, buf, len); + s->fd_read(s->fd_opaque, buf, len); + } + /* characters are pending: we send them a bit later (XXX: + horrible, should change char device API) */ + if (s->out_fifo.count > 0) { + qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1); + } +} + /* called when an ascii key is pressed */ void kbd_put_keysym(int keysym) { @@ -879,25 +956,26 @@ void kbd_put_keysym(int keysym) console_scroll(10); break; default: - if (s->fd_read) { - /* convert the QEMU keysym to VT100 key string */ - q = buf; - if (keysym >= 0xe100 && keysym <= 0xe11f) { - *q++ = '\033'; - *q++ = '['; - c = keysym - 0xe100; - if (c >= 10) - *q++ = '0' + (c / 10); - *q++ = '0' + (c % 10); - *q++ = '~'; - } else if (keysym >= 0xe120 && keysym <= 0xe17f) { - *q++ = '\033'; - *q++ = '['; - *q++ = keysym & 0xff; - } else { + /* convert the QEMU keysym to VT100 key string */ + q = buf; + if (keysym >= 0xe100 && keysym <= 0xe11f) { + *q++ = '\033'; + *q++ = '['; + c = keysym - 0xe100; + if (c >= 10) + *q++ = '0' + (c / 10); + *q++ = '0' + (c % 10); + *q++ = '~'; + } else if (keysym >= 0xe120 && keysym <= 0xe17f) { + *q++ = '\033'; + *q++ = '['; + *q++ = keysym & 0xff; + } else { *q++ = keysym; - } - s->fd_read(s->fd_opaque, buf, q - buf); + } + if (s->fd_read) { + qemu_fifo_write(&s->out_fifo, buf, q - buf); + kbd_send_chars(s); } break; } @@ -984,6 +1062,10 @@ CharDriverState *text_console_init(DisplayState *ds) chr->chr_add_read_handler = console_chr_add_read_handler; chr->chr_send_event = console_send_event; + s->out_fifo.buf = s->out_fifo_buf; + s->out_fifo.buf_size = sizeof(s->out_fifo_buf); + s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s); + if (!color_inited) { color_inited = 1; set_color_table(ds); diff --git a/tools/ioemu/cpu-all.h b/tools/ioemu/cpu-all.h index b9d0cb1351..a3c04f7083 100644 --- a/tools/ioemu/cpu-all.h +++ b/tools/ioemu/cpu-all.h @@ -878,6 +878,10 @@ extern uint8_t *phys_ram_dirty; #define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ +/* acts like a ROM when read and like a device when written. As an + exception, the write memory callback gets the ram offset instead of + the physical address */ +#define IO_MEM_ROMD (1) typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); @@ -946,15 +950,107 @@ void cpu_tlb_update_dirty(CPUState *env); void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -/* profiling */ -#ifdef CONFIG_PROFILER -static inline int64_t profile_getclock(void) +/*******************************************/ +/* host CPU ticks (if available) */ + +#if defined(__powerpc__) + +static inline uint32_t get_tbl(void) +{ + uint32_t tbl; + asm volatile("mftb %0" : "=r" (tbl)); + return tbl; +} + +static inline uint32_t get_tbu(void) +{ + uint32_t tbl; + asm volatile("mftbu %0" : "=r" (tbl)); + return tbl; +} + +static inline int64_t cpu_get_real_ticks(void) +{ + uint32_t l, h, h1; + /* NOTE: we test if wrapping has occurred */ + do { + h = get_tbu(); + l = get_tbl(); + h1 = get_tbu(); + } while (h != h1); + return ((int64_t)h << 32) | l; +} + +#elif defined(__i386__) + +static inline int64_t cpu_get_real_ticks(void) { int64_t val; asm volatile ("rdtsc" : "=A" (val)); return val; } +#elif defined(__x86_64__) + +static inline int64_t cpu_get_real_ticks(void) +{ + uint32_t low,high; + int64_t val; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val <<= 32; + val |= low; + return val; +} + +#elif defined(__ia64) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); + return val; +} + +#elif defined(__s390__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); + return val; +} + +#elif defined(__sparc_v9__) + +static inline int64_t cpu_get_real_ticks (void) +{ +#if defined(_LP64) + uint64_t rval; + asm volatile("rd %%tick,%0" : "=r"(rval)); + return rval; +#else + union { + uint64_t i64; + struct { + uint32_t high; + uint32_t low; + } i32; + } rval; + asm volatile("rd %%tick,%1; srlx %1,32,%0" + : "=r"(rval.i32.high), "=r"(rval.i32.low)); + return rval.i64; +#endif +} +#endif + +/* profiling */ +#ifdef CONFIG_PROFILER +static inline int64_t profile_getclock(void) +{ + return cpu_get_real_ticks(); +} + extern int64_t kqemu_time, kqemu_time_start; extern int64_t qemu_time, qemu_time_start; extern int64_t tlb_flush_time; diff --git a/tools/ioemu/cpu-defs.h b/tools/ioemu/cpu-defs.h index 665158a381..674c0bd3fb 100644 --- a/tools/ioemu/cpu-defs.h +++ b/tools/ioemu/cpu-defs.h @@ -47,7 +47,7 @@ typedef uint32_t target_ulong; #elif TARGET_LONG_SIZE == 8 typedef int64_t target_long; typedef uint64_t target_ulong; -#define TARGET_FMT_lx "%016llx" +#define TARGET_FMT_lx "%016" PRIx64 #else #error TARGET_LONG_SIZE undefined #endif diff --git a/tools/ioemu/cpu-exec.c b/tools/ioemu/cpu-exec.c index 8a585c1066..60239d4b96 100644 --- a/tools/ioemu/cpu-exec.c +++ b/tools/ioemu/cpu-exec.c @@ -47,7 +47,7 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } #endif -#ifndef TARGET_SPARC +#if !(defined(TARGET_SPARC) || defined(TARGET_SH4)) #define reg_T2 #endif @@ -175,9 +175,13 @@ static inline TranslationBlock *tb_find_fast(void) pc = env->regs[15]; #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 - flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); + // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled + flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) + | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); #else - flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); + // FPU enable . MMU enabled . MMU no-fault . Supervisor + flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1) + | env->psrs; #endif cs_base = env->npc; pc = env->pc; @@ -253,7 +257,7 @@ int cpu_exec(CPUState *env1) uint32_t *saved_regwptr; #endif #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) int saved_i7, tmp_T0; #endif int ret, interrupt_request; @@ -323,7 +327,7 @@ int cpu_exec(CPUState *env1) #if defined(reg_T2) saved_T2 = T2; #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) /* we also save i7 because longjmp may not restore it */ asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); #endif @@ -447,7 +451,7 @@ int cpu_exec(CPUState *env1) T0 = 0; /* force lookup of first TB */ for(;;) { -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) /* g1 can be modified by some libc? functions */ tmp_T0 = T0; #endif @@ -467,7 +471,7 @@ int cpu_exec(CPUState *env1) do_interrupt(intno, 0, 0, 0, 1); /* ensure that no TB jump will be modified as the program flow was changed */ -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -486,7 +490,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -497,7 +501,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -516,7 +520,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -534,7 +538,7 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; do_interrupt(env->interrupt_index); env->interrupt_index = 0; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -561,11 +565,13 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_SH4) /* XXXXX */ #endif + /* Don't use the cached interupt_request value, + do_interrupt may have updated the EXITTB flag. */ if (env->interrupt_request & CPU_INTERRUPT_EXITTB) { env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -633,7 +639,7 @@ int cpu_exec(CPUState *env1) lookup_symbol(tb->pc)); } #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) T0 = tmp_T0; #endif /* see if we can patch the calling TB. When the TB @@ -669,7 +675,9 @@ int cpu_exec(CPUState *env1) "mov %%o7,%%i0" : /* no outputs */ : "r" (gen_func) - : "i0", "i1", "i2", "i3", "i4", "i5"); + : "i0", "i1", "i2", "i3", "i4", "i5", + "l0", "l1", "l2", "l3", "l4", "l5", + "l6", "l7"); #elif defined(__arm__) asm volatile ("mov pc, %0\n\t" ".global exec_loop\n\t" @@ -834,7 +842,7 @@ int cpu_exec(CPUState *env1) #else #error unsupported target CPU #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); #endif T0 = saved_T0; @@ -1168,19 +1176,14 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, a virtual CPU fault */ cpu_restore_state(tb, env, pc, puc); } - if (ret == 1) { #if 0 printf("PF exception: NIP=0x%08x error=0x%x %p\n", env->nip, env->error_code, tb); #endif /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); - // do_raise_exception_err(env->exception_index, env->error_code); - } else { - /* activate soft MMU for this block */ - cpu_resume_from_signal(env, puc); - } + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); /* never comes here */ return 1; } diff --git a/tools/ioemu/disas.c b/tools/ioemu/disas.c index c38da08fd1..fd91b9220a 100644 --- a/tools/ioemu/disas.c +++ b/tools/ioemu/disas.c @@ -58,7 +58,7 @@ perror_memory (status, memaddr, info) /* Actually, address between memaddr and memaddr + len was out of bounds. */ (*info->fprintf_func) (info->stream, - "Address 0x%llx is out of bounds.\n", memaddr); + "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); } /* This could be in a separate file, to save miniscule amounts of space @@ -73,7 +73,7 @@ generic_print_address (addr, info) bfd_vma addr; struct disassemble_info *info; { - (*info->fprintf_func) (info->stream, "0x%llx", addr); + (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); } /* Just return the given address. */ diff --git a/tools/ioemu/dyngen-exec.h b/tools/ioemu/dyngen-exec.h index 6952c3a2c8..0c392283d4 100644 --- a/tools/ioemu/dyngen-exec.h +++ b/tools/ioemu/dyngen-exec.h @@ -35,12 +35,15 @@ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; +// Linux/Sparc64 defines uint64_t +#if !(defined (__sparc_v9__) && defined(__linux__)) /* XXX may be done for all 64 bits targets ? */ #if defined (__x86_64__) || defined(__ia64) typedef unsigned long uint64_t; #else typedef unsigned long long uint64_t; #endif +#endif /* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd prior to this and will cause an error in compliation, conflicting @@ -50,11 +53,14 @@ typedef signed char int8_t; #endif typedef signed short int16_t; typedef signed int int32_t; +// Linux/Sparc64 defines int64_t +#if !(defined (__sparc_v9__) && defined(__linux__)) #if defined (__x86_64__) || defined(__ia64) typedef signed long int64_t; #else typedef signed long long int64_t; #endif +#endif #define INT8_MIN (-128) #define INT16_MIN (-32767-1) @@ -121,6 +127,19 @@ extern int printf(const char *, ...); #define AREG3 "s2" #endif #ifdef __sparc__ +#ifdef HOST_SOLARIS +#define AREG0 "g2" +#define AREG1 "g3" +#define AREG2 "g4" +#define AREG3 "g5" +#define AREG4 "g6" +#else +#ifdef __sparc_v9__ +#define AREG0 "g1" +#define AREG1 "g4" +#define AREG2 "g5" +#define AREG3 "g7" +#else #define AREG0 "g6" #define AREG1 "g1" #define AREG2 "g2" @@ -133,6 +152,8 @@ extern int printf(const char *, ...); #define AREG9 "l5" #define AREG10 "l6" #define AREG11 "l7" +#endif +#endif #define USE_FP_CONVERT #endif #ifdef __s390__ @@ -241,10 +262,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; ASM_NAME(__op_gen_label) #n) #endif #ifdef __sparc__ -#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \ - "nop") -#define GOTO_LABEL_PARAM(n) asm volatile ( \ - "set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop") +#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop") +#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop") #endif #ifdef __arm__ #define EXIT_TB() asm volatile ("b exec_loop") diff --git a/tools/ioemu/dyngen.c b/tools/ioemu/dyngen.c index c1f348a94f..5fb921e28d 100644 --- a/tools/ioemu/dyngen.c +++ b/tools/ioemu/dyngen.c @@ -1196,7 +1196,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name) } else { #ifdef HOST_SPARC if (sym_name[0] == '.') - snprintf(name, sizeof(name), + snprintf(name, name_size, "(long)(&__dot_%s)", sym_name + 1); else @@ -1440,6 +1440,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC) { +#define INSN_SAVE 0x9de3a000 +#define INSN_RET 0x81c7e008 +#define INSN_RETL 0x81c3e008 +#define INSN_RESTORE 0x81e80000 +#define INSN_RETURN 0x81cfe008 +#define INSN_NOP 0x01000000 +#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp +#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp + uint32_t start_insn, end_insn1, end_insn2; uint8_t *p; p = (void *)(p_end - 8); @@ -1448,13 +1457,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -128) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE) + /* SPARC v7: ret; restore; */ ; + else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP) + /* SPARC v9: return; nop; */ ; + else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP) + /* SPARC v7: retl; sub %sp, nn, %sp; */ ; + else + error("ret; restore; not found at end of %s", name); + } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) { + ; } else { error("No save at the beginning of %s", name); } @@ -1462,7 +1479,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); - if (skip_insn == 0x01000000) + if (skip_insn == INSN_NOP) p -= 4; } #endif @@ -1470,21 +1487,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC64) { +#define INSN_SAVE 0x9de3a000 +#define INSN_RET 0x81c7e008 +#define INSN_RETL 0x81c3e008 +#define INSN_RESTORE 0x81e80000 +#define INSN_RETURN 0x81cfe008 +#define INSN_NOP 0x01000000 +#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp +#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp + uint32_t start_insn, end_insn1, end_insn2, skip_insn; uint8_t *p; p = (void *)(p_end - 8); +#if 0 + /* XXX: check why it occurs */ if (p <= p_start) error("empty code for %s", name); +#endif start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -256) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE) + /* SPARC v7: ret; restore; */ ; + else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP) + /* SPARC v9: return; nop; */ ; + else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP) + /* SPARC v7: retl; sub %sp, nn, %sp; */ ; + else + error("ret; restore; not found at end of %s", name); + } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) { + ; } else { error("No save at the beginning of %s", name); } @@ -2151,6 +2188,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, reloc_offset, reloc_offset, name, addend, reloc_offset); break; + case R_SPARC_WDISP22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3fffff) " + " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " + " & 0x3fffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend, + rel->r_offset - start_offset); + break; default: error("unsupported sparc relocation (%d)", type); } @@ -2168,7 +2217,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; get_reloc_expr(name, sizeof(name), sym_name); - type = ELF64_R_TYPE(rel->r_info); + type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { @@ -2192,6 +2241,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " | ((%s + %d) & 0x3ff);\n", reloc_offset, reloc_offset, name, addend); break; + case R_SPARC_OLO10: + addend += ELF64_R_TYPE_DATA (rel->r_info); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3ff) " + " | ((%s + %d) & 0x3ff);\n", + reloc_offset, reloc_offset, name, addend); + break; case R_SPARC_WDISP30: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = " @@ -2202,8 +2260,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, reloc_offset, reloc_offset, name, addend, reloc_offset); break; + case R_SPARC_WDISP22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3fffff) " + " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " + " & 0x3fffff);\n", + reloc_offset, reloc_offset, name, addend, + reloc_offset); + break; default: - error("unsupported sparc64 relocation (%d)", type); + error("unsupported sparc64 relocation (%d) for symbol %s", type, name); } } } diff --git a/tools/ioemu/dyngen.h b/tools/ioemu/dyngen.h index 5bb170e94d..fe0a9364e7 100644 --- a/tools/ioemu/dyngen.h +++ b/tools/ioemu/dyngen.h @@ -19,7 +19,13 @@ */ int __op_param1, __op_param2, __op_param3; -int __op_gen_label1, __op_gen_label2, __op_gen_label3; +#ifdef __sparc__ + void __op_gen_label1(){} + void __op_gen_label2(){} + void __op_gen_label3(){} +#else + int __op_gen_label1, __op_gen_label2, __op_gen_label3; +#endif int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ diff --git a/tools/ioemu/elf.h b/tools/ioemu/elf.h index 0dc82e7ca4..8ceb949769 100644 --- a/tools/ioemu/elf.h +++ b/tools/ioemu/elf.h @@ -227,6 +227,7 @@ typedef struct { #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000) #define R_386_NONE 0 #define R_386_32 1 @@ -326,6 +327,7 @@ typedef struct { #define R_SPARC_10 30 #define R_SPARC_11 31 #define R_SPARC_64 32 +#define R_SPARC_OLO10 33 #define R_SPARC_WDISP16 40 #define R_SPARC_WDISP19 41 #define R_SPARC_7 43 diff --git a/tools/ioemu/exec-all.h b/tools/ioemu/exec-all.h index 42ed0f63f6..eb4fa76b6c 100644 --- a/tools/ioemu/exec-all.h +++ b/tools/ioemu/exec-all.h @@ -571,7 +571,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) ldub_code(addr); } pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; - if (pd > IO_MEM_ROM) { + if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr); } return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; diff --git a/tools/ioemu/exec.c b/tools/ioemu/exec.c index f900e09f00..88acff0917 100644 --- a/tools/ioemu/exec.c +++ b/tools/ioemu/exec.c @@ -1488,7 +1488,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, if (is_softmmu) #endif { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* IO memory case */ address = vaddr | pd; addend = paddr; @@ -1513,9 +1513,11 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, te->addr_code = -1; } if (prot & PAGE_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { - /* ROM: access is ignored (same as unassigned) */ - te->addr_write = vaddr | IO_MEM_ROM; + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + (pd & IO_MEM_ROMD)) { + /* write access calls the I/O callback */ + te->addr_write = vaddr | + (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD)); } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { te->addr_write = vaddr | IO_MEM_NOTDIRTY; @@ -1779,15 +1781,24 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, { target_phys_addr_t addr, end_addr; PhysPageDesc *p; + CPUState *env; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + size; for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); p->phys_offset = phys_offset; - if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) phys_offset += TARGET_PAGE_SIZE; } + + /* since each CPU stores ram addresses in its TLB cache, we must + reset the modified entries */ + /* XXX: slow ! */ + for(env = first_cpu; env != NULL; env = env->next_cpu) { + tlb_flush(env, 1); + } } static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) @@ -2048,7 +2059,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } } else { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { @@ -2103,7 +2115,8 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, } if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && - (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* do nothing */ } else { unsigned long addr1; @@ -2135,7 +2148,8 @@ uint32_t ldl_phys(target_phys_addr_t addr) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); @@ -2164,7 +2178,8 @@ uint64_t ldq_phys(target_phys_addr_t addr) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #ifdef TARGET_WORDS_BIGENDIAN diff --git a/tools/ioemu/fpu/softfloat-native.c b/tools/ioemu/fpu/softfloat-native.c index e54820239c..bbdb3d66d9 100644 --- a/tools/ioemu/fpu/softfloat-native.c +++ b/tools/ioemu/fpu/softfloat-native.c @@ -6,7 +6,7 @@ void set_float_rounding_mode(int val STATUS_PARAM) { STATUS(float_rounding_mode) = val; -#if defined(_BSD) && !defined(__APPLE__) +#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) fpsetround(val); #elif defined(__arm__) /* nothing to do */ @@ -22,9 +22,14 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) } #endif -#if defined(_BSD) -#define lrint(d) ((long)rint(d)) -#define llrint(d) ((long long)rint(d)) +#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) +#define lrint(d) ((int32_t)rint(d)) +#define llrint(d) ((int64_t)rint(d)) +#define lrintf(f) ((int32_t)rint(f)) +#define llrintf(f) ((int64_t)rint(f)) +#define sqrtf(f) ((float)sqrt(f)) +#define remainderf(fa, fb) ((float)remainder(fa, fb)) +#define rintf(f) ((float)rint(f)) #endif #if defined(__powerpc__) diff --git a/tools/ioemu/gdbstub.c b/tools/ioemu/gdbstub.c index bca9b1e2a6..6ad393f799 100644 --- a/tools/ioemu/gdbstub.c +++ b/tools/ioemu/gdbstub.c @@ -17,6 +17,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" #ifdef CONFIG_USER_ONLY #include #include @@ -24,16 +25,25 @@ #include #include #include +#include #include "qemu.h" #else #include "vl.h" #endif -#include -#include -#include +#include "qemu_socket.h" +#ifdef _WIN32 +/* XXX: these constants may be independent of the host ones even for Unix */ +#ifndef SIGTRAP +#define SIGTRAP 5 +#endif +#ifndef SIGINT +#define SIGINT 2 +#endif +#else #include +#endif //#define DEBUG_GDB @@ -69,7 +79,7 @@ static int get_char(GDBState *s) int ret; for(;;) { - ret = read(s->fd, &ch, 1); + ret = recv(s->fd, &ch, 1, 0); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return -1; @@ -87,7 +97,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len) int ret; while (len > 0) { - ret = write(s->fd, buf, len); + ret = send(s->fd, buf, len, 0); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return; @@ -305,11 +315,11 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) for(i = 0; i < 24; i++) { registers[i + 8] = tswapl(env->regwptr[i]); } +#ifndef TARGET_SPARC64 /* fill in fprs */ for (i = 0; i < 32; i++) { registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); } -#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); { @@ -327,16 +337,21 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[72] = 0; return 73 * sizeof(target_ulong); #else - for (i = 0; i < 32; i += 2) { - registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i])); + /* fill in fprs */ + for (i = 0; i < 64; i += 2) { + uint64_t tmp; + + tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32; + tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1])); + registers[i/2 + 32] = tmp; } - registers[81] = tswapl(env->pc); - registers[82] = tswapl(env->npc); - registers[83] = tswapl(env->tstate[env->tl]); - registers[84] = tswapl(env->fsr); - registers[85] = tswapl(env->fprs); - registers[86] = tswapl(env->y); - return 87 * sizeof(target_ulong); + registers[64] = tswapl(env->pc); + registers[65] = tswapl(env->npc); + registers[66] = tswapl(env->tstate[env->tl]); + registers[67] = tswapl(env->fsr); + registers[68] = tswapl(env->fprs); + registers[69] = tswapl(env->y); + return 70 * sizeof(target_ulong); #endif } @@ -353,11 +368,11 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) for(i = 0; i < 24; i++) { env->regwptr[i] = tswapl(registers[i + 8]); } +#ifndef TARGET_SPARC64 /* fill in fprs */ for (i = 0; i < 32; i++) { *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); } -#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); PUT_PSR(env, tswapl(registers[65])); @@ -367,18 +382,16 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->npc = tswapl(registers[69]); env->fsr = tswapl(registers[70]); #else - for (i = 0; i < 32; i += 2) { - uint64_t tmp; - tmp = tswapl(registers[i/2 + 64]) << 32; - tmp |= tswapl(registers[i/2 + 64 + 1]); - *((uint64_t *)&env->fpr[i]) = tmp; + for (i = 0; i < 64; i += 2) { + *((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32); + *((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff); } - env->pc = tswapl(registers[81]); - env->npc = tswapl(registers[82]); - env->tstate[env->tl] = tswapl(registers[83]); - env->fsr = tswapl(registers[84]); - env->fprs = tswapl(registers[85]); - env->y = tswapl(registers[86]); + env->pc = tswapl(registers[64]); + env->npc = tswapl(registers[65]); + env->tstate[env->tl] = tswapl(registers[66]); + env->fsr = tswapl(registers[67]); + env->fprs = tswapl(registers[68]); + env->y = tswapl(registers[69]); #endif } #elif defined (TARGET_ARM) @@ -494,7 +507,12 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) int i; #define SAVE(x) *ptr++=tswapl(x) - for (i = 0; i < 16; i++) SAVE(env->gregs[i]); + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]); + } else { + for (i = 0; i < 8; i++) SAVE(env->gregs[i]); + } + for (i = 8; i < 16; i++) SAVE(env->gregs[i]); SAVE (env->pc); SAVE (env->pr); SAVE (env->gbr); @@ -517,7 +535,12 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) int i; #define LOAD(x) (x)=*ptr++; - for (i = 0; i < 16; i++) LOAD(env->gregs[i]); + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); + } else { + for (i = 0; i < 8; i++) LOAD(env->gregs[i]); + } + for (i = 8; i < 16; i++) LOAD(env->gregs[i]); LOAD (env->pc); LOAD (env->pr); LOAD (env->gbr); @@ -545,7 +568,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; - uint32_t addr, len; + target_ulong addr, len; #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); @@ -560,7 +583,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) break; case 'c': if (*p != '\0') { - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); #if defined(TARGET_I386) env->eip = addr; #elif defined (TARGET_PPC) @@ -616,10 +639,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) put_packet(s, "OK"); break; case 'm': - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, NULL, 16); + len = strtoull(p, NULL, 16); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { @@ -628,10 +651,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) } break; case 'M': - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (*p == ':') p++; hextomem(mem_buf, p, len); @@ -644,10 +667,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; @@ -661,10 +684,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); @@ -672,6 +695,18 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) goto breakpoint_error; } break; +#ifdef CONFIG_USER_ONLY + case 'q': + if (strncmp(p, "Offsets", 7) == 0) { + TaskState *ts = env->opaque; + + sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset, + ts->info->data_offset, ts->info->data_offset); + put_packet(s, buf); + break; + } + /* Fall through. */ +#endif default: // unknown_command: /* put empty packet */ @@ -829,7 +864,7 @@ static void gdb_read(void *opaque) int i, size; uint8_t buf[4096]; - size = read(s->fd, buf, sizeof(buf)); + size = recv(s->fd, buf, sizeof(buf), 0); if (size < 0) return; if (size == 0) { @@ -866,7 +901,7 @@ static void gdb_accept(void *opaque) /* set short latency */ val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); #ifdef CONFIG_USER_ONLY s = &gdbserver_state; @@ -881,9 +916,11 @@ static void gdb_accept(void *opaque) s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; +#ifdef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK); +#else + socket_set_nonblock(fd); -#ifndef CONFIG_USER_ONLY /* stop the VM */ vm_stop(EXCP_INTERRUPT); @@ -907,7 +944,7 @@ static int gdbserver_open(int port) /* allow fast reuse */ val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); @@ -923,7 +960,7 @@ static int gdbserver_open(int port) return -1; } #ifndef CONFIG_USER_ONLY - fcntl(fd, F_SETFL, O_NONBLOCK); + socket_set_nonblock(fd); #endif return fd; } diff --git a/tools/ioemu/hw/acpi-dsdt.dsl b/tools/ioemu/hw/acpi-dsdt.dsl new file mode 100644 index 0000000000..fc4081fd8c --- /dev/null +++ b/tools/ioemu/hw/acpi-dsdt.dsl @@ -0,0 +1,559 @@ +/* + * QEMU ACPI DSDT ASL definition + * + * Copyright (c) 2006 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +DefinitionBlock ( + "acpi-dsdt.aml", // Output Filename + "DSDT", // Signature + 0x01, // DSDT Compliance Revision + "QEMU", // OEMID + "QEMUDSDT", // TABLE ID + 0x1 // OEM Revision + ) +{ + Scope (\) + { + /* CMOS memory access */ + OperationRegion (CMS, SystemIO, 0x70, 0x02) + Field (CMS, ByteAcc, NoLock, Preserve) + { + CMSI, 8, + CMSD, 8 + } + Method (CMRD, 1, NotSerialized) + { + Store (Arg0, CMSI) + Store (CMSD, Local0) + Return (Local0) + } + + /* Debug Output */ + OperationRegion (DBG, SystemIO, 0xb044, 0x04) + Field (DBG, DWordAcc, NoLock, Preserve) + { + DBGL, 32, + } + } + + + /* PCI Bus definition */ + Scope(\_SB) { + Device(PCI0) { + Name (_HID, EisaId ("PNP0A03")) + Name (_ADR, 0x00) + Name (_UID, 1) + Name(_PRT, Package() { + /* PCI IRQ routing table, example from ACPI 2.0a specification, + section 6.2.8.1 */ + /* Note: we provide the same info as the PCI routing + table of the Bochs BIOS */ + + // PCI Slot 0 + Package() {0x0000ffff, 0, LNKD, 0}, + Package() {0x0000ffff, 1, LNKA, 0}, + Package() {0x0000ffff, 2, LNKB, 0}, + Package() {0x0000ffff, 3, LNKC, 0}, + + // PCI Slot 1 + Package() {0x0001ffff, 0, LNKA, 0}, + Package() {0x0001ffff, 1, LNKB, 0}, + Package() {0x0001ffff, 2, LNKC, 0}, + Package() {0x0001ffff, 3, LNKD, 0}, + + // PCI Slot 2 + Package() {0x0002ffff, 0, LNKB, 0}, + Package() {0x0002ffff, 1, LNKC, 0}, + Package() {0x0002ffff, 2, LNKD, 0}, + Package() {0x0002ffff, 3, LNKA, 0}, + + // PCI Slot 3 + Package() {0x0003ffff, 0, LNKC, 0}, + Package() {0x0003ffff, 1, LNKD, 0}, + Package() {0x0003ffff, 2, LNKA, 0}, + Package() {0x0003ffff, 3, LNKB, 0}, + + // PCI Slot 4 + Package() {0x0004ffff, 0, LNKD, 0}, + Package() {0x0004ffff, 1, LNKA, 0}, + Package() {0x0004ffff, 2, LNKB, 0}, + Package() {0x0004ffff, 3, LNKC, 0}, + + // PCI Slot 5 + Package() {0x0005ffff, 0, LNKA, 0}, + Package() {0x0005ffff, 1, LNKB, 0}, + Package() {0x0005ffff, 2, LNKC, 0}, + Package() {0x0005ffff, 3, LNKD, 0}, + }) + + Method (_CRS, 0, NotSerialized) + { + Name (MEMP, ResourceTemplate () + { + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x00FF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0100, // Address Length + ,, ) + IO (Decode16, + 0x0CF8, // Address Range Minimum + 0x0CF8, // Address Range Maximum + 0x01, // Address Alignment + 0x08, // Address Length + ) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x0CF7, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0CF8, // Address Length + ,, , TypeStatic) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0D00, // Address Range Minimum + 0xFFFF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0xF300, // Address Length + ,, , TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0x000A0000, // Address Range Minimum + 0x000BFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00020000, // Address Length + ,, , AddressRangeMemory, TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0x00000000, // Address Range Minimum + 0xFEBFFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00000000, // Address Length + ,, MEMF, AddressRangeMemory, TypeStatic) + }) + CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN) + CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX) + CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN) + /* compute available RAM */ + Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0) + ShiftLeft(Local0, 16, Local0) + Add(Local0, 0x1000000, Local0) + /* update field of last region */ + Store(Local0, PMIN) + Subtract (PMAX, PMIN, PLEN) + Increment (PLEN) + Return (MEMP) + } + } + } + + Scope(\_SB.PCI0) { + + /* PIIX3 ISA bridge */ + Device (ISA) { + Name (_ADR, 0x00010000) + + /* PIIX PCI to ISA irq remapping */ + OperationRegion (P40C, PCI_Config, 0x60, 0x04) + + + /* Keyboard seems to be important for WinXP install */ + Device (KBD) + { + Name (_HID, EisaId ("PNP0303")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) + } + + Method (_CRS, 0, NotSerialized) + { + Name (TMP, ResourceTemplate () + { + IO (Decode16, + 0x0060, // Address Range Minimum + 0x0060, // Address Range Maximum + 0x01, // Address Alignment + 0x01, // Address Length + ) + IO (Decode16, + 0x0064, // Address Range Minimum + 0x0064, // Address Range Maximum + 0x01, // Address Alignment + 0x01, // Address Length + ) + IRQNoFlags () + {1} + }) + Return (TMP) + } + } + + /* PS/2 mouse */ + Device (MOU) + { + Name (_HID, EisaId ("PNP0F13")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) + } + + Method (_CRS, 0, NotSerialized) + { + Name (TMP, ResourceTemplate () + { + IRQNoFlags () {12} + }) + Return (TMP) + } + } + + /* PS/2 floppy controller */ + Device (FDC0) + { + Name (_HID, EisaId ("PNP0700")) + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) + IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) + IRQNoFlags () {6} + DMA (Compatibility, NotBusMaster, Transfer8) {2} + }) + Return (BUF0) + } + } + + /* Parallel port */ + Device (LPT) + { + Name (_HID, EisaId ("PNP0400")) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSA, Local0) + And (Local0, 0x80000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) + IRQNoFlags () {7} + }) + Return (BUF0) + } + } + + /* Serial Ports */ + Device (COM1) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x01) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSC, Local0) + And (Local0, 0x08000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) + IRQNoFlags () {4} + }) + Return (BUF0) + } + } + + Device (COM2) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x02) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSC, Local0) + And (Local0, 0x80000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) + IRQNoFlags () {3} + }) + Return (BUF0) + } + } + } + + /* PIIX4 PM */ + Device (PX13) { + Name (_ADR, 0x00010003) + + OperationRegion (P13C, PCI_Config, 0x5c, 0x24) + Field (P13C, DWordAcc, NoLock, Preserve) + { + DRSA, 32, + DRSB, 32, + DRSC, 32, + DRSE, 32, + DRSF, 32, + DRSG, 32, + DRSH, 32, + DRSI, 32, + DRSJ, 32 + } + } + } + + /* PCI IRQs */ + Scope(\_SB) { + Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) + { + PRQ0, 8, + PRQ1, 8, + PRQ2, 8, + PRQ3, 8 + } + + Device(LNKA){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 1) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ0, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ0, 0x80, PRQ0) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ0, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ0) + } + } + Device(LNKB){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 2) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ1, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ1, 0x80, PRQ1) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ1, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ1) + } + } + Device(LNKC){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 3) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ2, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ2, 0x80, PRQ2) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ2, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ2) + } + } + Device(LNKD){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 4) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ3, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ3, 0x80, PRQ3) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ3, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ3) + } + } + } + + /* S5 = power off state */ + Name (_S5, Package (4) { + 0x00, // PM1a_CNT.SLP_TYP + 0x00, // PM2a_CNT.SLP_TYP + 0x00, // reserved + 0x00, // reserved + }) +} diff --git a/tools/ioemu/hw/acpi-dsdt.hex b/tools/ioemu/hw/acpi-dsdt.hex new file mode 100644 index 0000000000..f4f50bd655 --- /dev/null +++ b/tools/ioemu/hw/acpi-dsdt.hex @@ -0,0 +1,278 @@ +/* + * + * Intel ACPI Component Architecture + * ASL Optimizing Compiler version 20060421 [Apr 29 2006] + * Copyright (C) 2000 - 2006 Intel Corporation + * Supports ACPI Specification Revision 3.0a + * + * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006 + * + * C source code output + * + */ +unsigned char AmlCode[] = +{ + 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */ + 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */ + 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ + 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */ + 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */ + 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */ + 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */ + 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */ + 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */ + 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */ + 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */ + 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */ + 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */ + 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */ + 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */ + 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */ + 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ + 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ + 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ + 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */ + 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ + 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */ + 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */ + 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */ + 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ + 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */ + 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ + 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */ + 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ + 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */ + 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */ + 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ + 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */ + 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ + 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */ + 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ + 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */ + 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */ + 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */ + 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ + 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */ + 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ + 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ + 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */ + 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */ + 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */ + 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */ + 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */ + 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */ + 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */ + 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */ + 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */ + 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */ + 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */ + 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */ + 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */ + 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */ + 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */ + 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */ + 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */ + 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */ + 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */ + 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */ + 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ + 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ + 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ + 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ + 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ + 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ + 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ + 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */ + 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */ + 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */ + 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */ + 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */ + 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */ + 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */ + 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */ + 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */ + 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */ + 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */ + 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ + 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ + 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ + 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */ + 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */ + 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */ + 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */ + 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */ + 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */ + 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */ + 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */ + 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */ + 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */ + 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */ + 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */ + 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */ + 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */ + 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */ + 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */ + 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */ + 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */ + 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */ + 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */ + 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */ + 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */ + 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */ + 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */ + 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */ + 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */ + 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */ + 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */ + 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */ + 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */ + 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */ + 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */ + 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */ + 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */ + 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */ + 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */ + 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */ + 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */ + 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */ + 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */ + 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */ + 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */ + 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */ + 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */ + 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */ + 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */ + 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */ + 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */ + 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */ + 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */ + 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */ + 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */ + 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */ + 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */ + 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */ + 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */ + 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */ + 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */ + 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */ + 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */ + 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */ + 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */ + 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */ + 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */ + 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */ + 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */ + 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */ + 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */ + 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */ + 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */ + 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */ + 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */ + 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */ + 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */ + 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */ + 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */ + 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */ + 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */ + 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */ + 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */ + 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */ + 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */ + 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */ + 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */ + 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */ + 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */ + 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */ + 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */ + 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */ + 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */ + 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */ + 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */ + 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */ + 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */ + 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */ + 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */ + 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */ + 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */ + 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */ + 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */ + 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */ + 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */ + 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */ + 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */ + 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */ + 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */ + 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */ + 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */ + 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */ + 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */ + 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */ + 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */ + 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */ + 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */ + 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */ + 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */ + 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */ + 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */ + 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */ + 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */ + 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */ + 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */ + 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */ + 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */ + 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */ + 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */ + 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */ + 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */ + 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */ + 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */ + 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */ + 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */ + 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */ + 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */ + 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */ + 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */ + 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */ + 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */ + 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */ + 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ + 0x00,0x00, +}; diff --git a/tools/ioemu/hw/acpi.c b/tools/ioemu/hw/acpi.c new file mode 100644 index 0000000000..6c20a4e937 --- /dev/null +++ b/tools/ioemu/hw/acpi.c @@ -0,0 +1,615 @@ +/* + * ACPI implementation + * + * Copyright (c) 2006 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "vl.h" + +//#define DEBUG + +/* i82731AB (PIIX4) compatible power management function */ +#define PM_FREQ 3579545 + +/* XXX: make them variable */ +#define PM_IO_BASE 0xb000 +#define SMI_CMD_IO_ADDR 0xb040 +#define ACPI_DBG_IO_ADDR 0xb044 + +typedef struct PIIX4PMState { + PCIDevice dev; + uint16_t pmsts; + uint16_t pmen; + uint16_t pmcntrl; + QEMUTimer *tmr_timer; + int64_t tmr_overflow_time; +} PIIX4PMState; + +#define RTC_EN (1 << 10) +#define PWRBTN_EN (1 << 8) +#define GBL_EN (1 << 5) +#define TMROF_EN (1 << 0) + +#define SCI_EN (1 << 0) + +#define SUS_EN (1 << 13) + +/* Note: only used for ACPI bios init. Could be deleted when ACPI init + is integrated in Bochs BIOS */ +static PIIX4PMState *piix4_pm_state; + +static uint32_t get_pmtmr(PIIX4PMState *s) +{ + uint32_t d; + d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); + return d & 0xffffff; +} + +static int get_pmsts(PIIX4PMState *s) +{ + int64_t d; + int pmsts; + pmsts = s->pmsts; + d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); + if (d >= s->tmr_overflow_time) + s->pmsts |= TMROF_EN; + return pmsts; +} + +static void pm_update_sci(PIIX4PMState *s) +{ + int sci_level, pmsts; + int64_t expire_time; + + pmsts = get_pmsts(s); + sci_level = (((pmsts & s->pmen) & + (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); + pci_set_irq(&s->dev, 0, sci_level); + /* schedule a timer interruption if needed */ + if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { + expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ); + qemu_mod_timer(s->tmr_timer, expire_time); + } else { + qemu_del_timer(s->tmr_timer); + } +} + +static void pm_tmr_timer(void *opaque) +{ + PIIX4PMState *s = opaque; + pm_update_sci(s); +} + +static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4PMState *s = opaque; + addr &= 0x3f; + switch(addr) { + case 0x00: + { + int64_t d; + int pmsts; + pmsts = get_pmsts(s); + if (pmsts & val & TMROF_EN) { + /* if TMRSTS is reset, then compute the new overflow time */ + d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); + s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; + } + s->pmsts &= ~val; + pm_update_sci(s); + } + break; + case 0x02: + s->pmen = val; + pm_update_sci(s); + break; + case 0x04: + { + int sus_typ; + s->pmcntrl = val & ~(SUS_EN); + if (val & SUS_EN) { + /* change suspend type */ + sus_typ = (val >> 10) & 3; + switch(sus_typ) { + case 0: /* soft power off */ + qemu_system_shutdown_request(); + break; + default: + break; + } + } + } + break; + default: + break; + } +#ifdef DEBUG + printf("PM writew port=0x%04x val=0x%04x\n", addr, val); +#endif +} + +static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + addr &= 0x3f; + switch(addr) { + case 0x00: + val = get_pmsts(s); + break; + case 0x02: + val = s->pmen; + break; + case 0x04: + val = s->pmcntrl; + break; + default: + val = 0; + break; + } +#ifdef DEBUG + printf("PM readw port=0x%04x val=0x%04x\n", addr, val); +#endif + return val; +} + +static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + // PIIX4PMState *s = opaque; + addr &= 0x3f; +#ifdef DEBUG + printf("PM writel port=0x%04x val=0x%08x\n", addr, val); +#endif +} + +static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + addr &= 0x3f; + switch(addr) { + case 0x08: + val = get_pmtmr(s); + break; + default: + val = 0; + break; + } +#ifdef DEBUG + printf("PM readl port=0x%04x val=0x%08x\n", addr, val); +#endif + return val; +} + +static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4PMState *s = opaque; +#ifdef DEBUG + printf("SMI cmd val=0x%02x\n", val); +#endif + switch(val) { + case 0xf0: /* ACPI disable */ + s->pmcntrl &= ~SCI_EN; + break; + case 0xf1: /* ACPI enable */ + s->pmcntrl |= SCI_EN; + break; + } +} + +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) +{ +#if defined(DEBUG) + printf("ACPI: DBG: 0x%08x\n", val); +#endif +} + +/* XXX: we still add it to the PIIX3 and we count on the fact that + OSes are smart enough to accept this strange configuration */ +void piix4_pm_init(PCIBus *bus, int devfn) +{ + PIIX4PMState *s; + uint8_t *pci_conf; + uint32_t pm_io_base; + + s = (PIIX4PMState *)pci_register_device(bus, + "PM", sizeof(PIIX4PMState), + devfn, NULL, NULL); + pci_conf = s->dev.config; + pci_conf[0x00] = 0x86; + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x13; + pci_conf[0x03] = 0x71; + pci_conf[0x08] = 0x00; // revision number + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x80; // other bridge device + pci_conf[0x0b] = 0x06; // bridge device + pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x3d] = 0x01; // interrupt pin 1 + + pm_io_base = PM_IO_BASE; + pci_conf[0x40] = pm_io_base | 1; + pci_conf[0x41] = pm_io_base >> 8; + register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); + register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); + register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); + register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); + + register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s); + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + + /* XXX: which specification is used ? The i82731AB has different + mappings */ + pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10; + pci_conf[0x63] = 0x60; + pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | + (serial_hds[1] != NULL ? 0x90 : 0); + + s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); + piix4_pm_state = s; +} + +/* ACPI tables */ +/* XXX: move them in the Bochs BIOS ? */ + +/*************************************************/ + +/* Table structure from Linux kernel (the ACPI tables are under the + BSD license) */ + +#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ + uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\ + uint32_t length; /* Length of table, in bytes, including header */\ + uint8_t revision; /* ACPI Specification minor version # */\ + uint8_t checksum; /* To make sum of entire table == 0 */\ + uint8_t oem_id [6]; /* OEM identification */\ + uint8_t oem_table_id [8]; /* OEM table identification */\ + uint32_t oem_revision; /* OEM revision number */\ + uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\ + uint32_t asl_compiler_revision; /* ASL compiler revision number */ + + +struct acpi_table_header /* ACPI common table header */ +{ + ACPI_TABLE_HEADER_DEF +}; + +struct rsdp_descriptor /* Root System Descriptor Pointer */ +{ + uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */ + uint8_t checksum; /* To make sum of struct == 0 */ + uint8_t oem_id [6]; /* OEM identification */ + uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ + uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ + uint32_t length; /* XSDT Length in bytes including hdr */ + uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ + uint8_t extended_checksum; /* Checksum of entire table */ + uint8_t reserved [3]; /* Reserved field must be 0 */ +}; + +/* + * ACPI 1.0 Root System Description Table (RSDT) + */ +struct rsdt_descriptor_rev1 +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t table_offset_entry [2]; /* Array of pointers to other */ + /* ACPI tables */ +}; + +/* + * ACPI 1.0 Firmware ACPI Control Structure (FACS) + */ +struct facs_descriptor_rev1 +{ + uint8_t signature[4]; /* ACPI Signature */ + uint32_t length; /* Length of structure, in bytes */ + uint32_t hardware_signature; /* Hardware configuration signature */ + uint32_t firmware_waking_vector; /* ACPI OS waking vector */ + uint32_t global_lock; /* Global Lock */ + uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */ + uint32_t reserved1 : 31; /* Must be 0 */ + uint8_t resverved3 [40]; /* Reserved - must be zero */ +}; + + +/* + * ACPI 1.0 Fixed ACPI Description Table (FADT) + */ +struct fadt_descriptor_rev1 +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t firmware_ctrl; /* Physical address of FACS */ + uint32_t dsdt; /* Physical address of DSDT */ + uint8_t model; /* System Interrupt Model */ + uint8_t reserved1; /* Reserved */ + uint16_t sci_int; /* System vector of SCI interrupt */ + uint32_t smi_cmd; /* Port address of SMI command port */ + uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ + uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ + uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ + uint8_t reserved2; /* Reserved - must be zero */ + uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ + uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ + uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ + uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ + uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ + uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ + uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ + uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ + uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ + uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ + uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ + uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ + uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ + uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ + uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ + uint8_t reserved3; /* Reserved */ + uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ + uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ + uint16_t flush_size; /* Size of area read to flush caches */ + uint16_t flush_stride; /* Stride used in flushing caches */ + uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ + uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ + uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ + uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ + uint8_t century; /* Index to century in RTC CMOS RAM */ + uint8_t reserved4; /* Reserved */ + uint8_t reserved4a; /* Reserved */ + uint8_t reserved4b; /* Reserved */ +#if 0 + uint32_t wb_invd : 1; /* The wbinvd instruction works properly */ + uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ + uint32_t proc_c1 : 1; /* All processors support C1 state */ + uint32_t plvl2_up : 1; /* C2 state works on MP system */ + uint32_t pwr_button : 1; /* Power button is handled as a generic feature */ + uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ + uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ + uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ + uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ + uint32_t reserved5 : 23; /* Reserved - must be zero */ +#else + uint32_t flags; +#endif +}; + +/* + * MADT values and structures + */ + +/* Values for MADT PCATCompat */ + +#define DUAL_PIC 0 +#define MULTIPLE_APIC 1 + + +/* Master MADT */ + +struct multiple_apic_table +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t local_apic_address; /* Physical address of local APIC */ +#if 0 + uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */ + uint32_t reserved1 : 31; +#else + uint32_t flags; +#endif +}; + + +/* Values for Type in APIC_HEADER_DEF */ + +#define APIC_PROCESSOR 0 +#define APIC_IO 1 +#define APIC_XRUPT_OVERRIDE 2 +#define APIC_NMI 3 +#define APIC_LOCAL_NMI 4 +#define APIC_ADDRESS_OVERRIDE 5 +#define APIC_IO_SAPIC 6 +#define APIC_LOCAL_SAPIC 7 +#define APIC_XRUPT_SOURCE 8 +#define APIC_RESERVED 9 /* 9 and greater are reserved */ + +/* + * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) + */ +#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ + uint8_t type; \ + uint8_t length; + +/* Sub-structures for MADT */ + +struct madt_processor_apic +{ + APIC_HEADER_DEF + uint8_t processor_id; /* ACPI processor id */ + uint8_t local_apic_id; /* Processor's local APIC id */ +#if 0 + uint32_t processor_enabled: 1; /* Processor is usable if set */ + uint32_t reserved2 : 31; /* Reserved, must be zero */ +#else + uint32_t flags; +#endif +}; + +struct madt_io_apic +{ + APIC_HEADER_DEF + uint8_t io_apic_id; /* I/O APIC ID */ + uint8_t reserved; /* Reserved - must be zero */ + uint32_t address; /* APIC physical address */ + uint32_t interrupt; /* Global system interrupt where INTI + * lines start */ +}; + +#include "acpi-dsdt.hex" + +static int acpi_checksum(const uint8_t *data, int len) +{ + int sum, i; + sum = 0; + for(i = 0; i < len; i++) + sum += data[i]; + return (-sum) & 0xff; +} + +static void acpi_build_table_header(struct acpi_table_header *h, + char *sig, int len) +{ + memcpy(h->signature, sig, 4); + h->length = cpu_to_le32(len); + h->revision = 0; + memcpy(h->oem_id, "QEMU ", 6); + memcpy(h->oem_table_id, "QEMU", 4); + memcpy(h->oem_table_id + 4, sig, 4); + h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, "QEMU", 4); + h->asl_compiler_revision = cpu_to_le32(1); + h->checksum = acpi_checksum((void *)h, len); +} + +#define ACPI_TABLES_BASE 0x000e8000 + +/* base_addr must be a multiple of 4KB */ +void acpi_bios_init(void) +{ + struct rsdp_descriptor *rsdp; + struct rsdt_descriptor_rev1 *rsdt; + struct fadt_descriptor_rev1 *fadt; + struct facs_descriptor_rev1 *facs; + struct multiple_apic_table *madt; + uint8_t *dsdt; + uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr; + uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size; + int i; + + /* compute PCI I/O addresses */ + pm_io_base = (piix4_pm_state->dev.config[0x40] | + (piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f; + + base_addr = ACPI_TABLES_BASE; + + /* reserve memory space for tables */ + addr = base_addr; + rsdp = (void *)(phys_ram_base + addr); + addr += sizeof(*rsdp); + + rsdt_addr = addr; + rsdt = (void *)(phys_ram_base + addr); + addr += sizeof(*rsdt); + + fadt_addr = addr; + fadt = (void *)(phys_ram_base + addr); + addr += sizeof(*fadt); + + /* XXX: FACS should be in RAM */ + addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */ + facs_addr = addr; + facs = (void *)(phys_ram_base + addr); + addr += sizeof(*facs); + + dsdt_addr = addr; + dsdt = (void *)(phys_ram_base + addr); + addr += sizeof(AmlCode); + + addr = (addr + 7) & ~7; + madt_addr = addr; + madt_size = sizeof(*madt) + + sizeof(struct madt_processor_apic) * smp_cpus + + sizeof(struct madt_io_apic); + madt = (void *)(phys_ram_base + addr); + addr += madt_size; + + acpi_tables_size = addr - base_addr; + + cpu_register_physical_memory(base_addr, acpi_tables_size, + base_addr | IO_MEM_ROM); + + /* RSDP */ + memset(rsdp, 0, sizeof(*rsdp)); + memcpy(rsdp->signature, "RSD PTR ", 8); + memcpy(rsdp->oem_id, "QEMU ", 6); + rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr); + rsdp->checksum = acpi_checksum((void *)rsdp, 20); + + /* RSDT */ + rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); + rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); + acpi_build_table_header((struct acpi_table_header *)rsdt, + "RSDT", sizeof(*rsdt)); + + /* FADT */ + memset(fadt, 0, sizeof(*fadt)); + fadt->firmware_ctrl = cpu_to_le32(facs_addr); + fadt->dsdt = cpu_to_le32(dsdt_addr); + fadt->model = 1; + fadt->reserved1 = 0; + fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]); + fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR); + fadt->acpi_enable = 0xf1; + fadt->acpi_disable = 0xf0; + fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base); + fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04); + fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08); + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm_tmr_len = 4; + fadt->plvl2_lat = cpu_to_le16(50); + fadt->plvl3_lat = cpu_to_le16(50); + fadt->plvl3_lat = cpu_to_le16(50); + /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */ + fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6)); + acpi_build_table_header((struct acpi_table_header *)fadt, "FACP", + sizeof(*fadt)); + + /* FACS */ + memset(facs, 0, sizeof(*facs)); + memcpy(facs->signature, "FACS", 4); + facs->length = cpu_to_le32(sizeof(*facs)); + + /* DSDT */ + memcpy(dsdt, AmlCode, sizeof(AmlCode)); + + /* MADT */ + { + struct madt_processor_apic *apic; + struct madt_io_apic *io_apic; + + memset(madt, 0, madt_size); + madt->local_apic_address = cpu_to_le32(0xfee00000); + madt->flags = cpu_to_le32(1); + apic = (void *)(madt + 1); + for(i=0;itype = APIC_PROCESSOR; + apic->length = sizeof(*apic); + apic->processor_id = i; + apic->local_apic_id = i; + apic->flags = cpu_to_le32(1); + apic++; + } + io_apic = (void *)apic; + io_apic->type = APIC_IO; + io_apic->length = sizeof(*io_apic); + io_apic->io_apic_id = smp_cpus; + io_apic->address = cpu_to_le32(0xfec00000); + io_apic->interrupt = cpu_to_le32(0); + + acpi_build_table_header((struct acpi_table_header *)madt, + "APIC", madt_size); + } +} diff --git a/tools/ioemu/hw/adlib.c b/tools/ioemu/hw/adlib.c index f482d1fa84..b47bc3eece 100644 --- a/tools/ioemu/hw/adlib.c +++ b/tools/ioemu/hw/adlib.c @@ -301,6 +301,7 @@ int Adlib_init (AudioState *audio) as.freq = conf.freq; as.nchannels = SHIFT; as.fmt = AUD_FMT_S16; + as.endianness = AUDIO_HOST_ENDIANNESS; AUD_register_card (audio, "adlib", &s->card); @@ -310,8 +311,7 @@ int Adlib_init (AudioState *audio) "adlib", s, adlib_callback, - &as, - 0 /* XXX: little endian? */ + &as ); if (!s->voice) { Adlib_fini (s); diff --git a/tools/ioemu/hw/apb_pci.c b/tools/ioemu/hw/apb_pci.c new file mode 100644 index 0000000000..02e9824b39 --- /dev/null +++ b/tools/ioemu/hw/apb_pci.c @@ -0,0 +1,232 @@ +/* + * QEMU Ultrasparc APB PCI host + * + * Copyright (c) 2006 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState APBState; + +static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + APBState *s = opaque; + int i; + + for (i = 11; i < 32; i++) { + if ((val & (1 << i)) != 0) + break; + } + s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11); +} + +static uint32_t pci_apb_config_readl (void *opaque, + target_phys_addr_t addr) +{ + APBState *s = opaque; + uint32_t val; + int devfn; + + devfn = (s->config_reg >> 8) & 0xFF; + val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_config_write[] = { + &pci_apb_config_writel, + &pci_apb_config_writel, + &pci_apb_config_writel, +}; + +static CPUReadMemoryFunc *pci_apb_config_read[] = { + &pci_apb_config_readl, + &pci_apb_config_readl, + &pci_apb_config_readl, +}; + +static void apb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + //PCIBus *s = opaque; + + switch (addr & 0x3f) { + case 0x00: // Control/Status + case 0x10: // AFSR + case 0x18: // AFAR + case 0x20: // Diagnostic + case 0x28: // Target address space + // XXX + default: + break; + } +} + +static uint32_t apb_config_readl (void *opaque, + target_phys_addr_t addr) +{ + //PCIBus *s = opaque; + uint32_t val; + + switch (addr & 0x3f) { + case 0x00: // Control/Status + case 0x10: // AFSR + case 0x18: // AFAR + case 0x20: // Diagnostic + case 0x28: // Target address space + // XXX + default: + val = 0; + break; + } + return val; +} + +static CPUWriteMemoryFunc *apb_config_write[] = { + &apb_config_writel, + &apb_config_writel, + &apb_config_writel, +}; + +static CPUReadMemoryFunc *apb_config_read[] = { + &apb_config_readl, + &apb_config_readl, + &apb_config_readl, +}; + +static CPUWriteMemoryFunc *pci_apb_write[] = { + &pci_host_data_writeb, + &pci_host_data_writew, + &pci_host_data_writel, +}; + +static CPUReadMemoryFunc *pci_apb_read[] = { + &pci_host_data_readb, + &pci_host_data_readw, + &pci_host_data_readl, +}; + +static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outb(NULL, addr & 0xffff, val); +} + +static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outw(NULL, addr & 0xffff, val); +} + +static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outl(NULL, addr & 0xffff, val); +} + +static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inb(NULL, addr & 0xffff); + return val; +} + +static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inw(NULL, addr & 0xffff); + return val; +} + +static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inl(NULL, addr & 0xffff); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_iowrite[] = { + &pci_apb_iowriteb, + &pci_apb_iowritew, + &pci_apb_iowritel, +}; + +static CPUReadMemoryFunc *pci_apb_ioread[] = { + &pci_apb_ioreadb, + &pci_apb_ioreadw, + &pci_apb_ioreadl, +}; + +/* ??? This is probably wrong. */ +static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, + void *pic) +{ + APBState *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data, apb_config, pci_ioport; + + s = qemu_mallocz(sizeof(APBState)); + /* Ultrasparc APB main bus */ + s->bus = pci_register_bus(pci_apb_set_irq, pic, 0); + + pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, + pci_apb_config_write, s); + apb_config = cpu_register_io_memory(0, apb_config_read, + apb_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_apb_read, + pci_apb_write, s); + pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, + pci_apb_iowrite, s); + + cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); + cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); + cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); + cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom + + d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), + -1, NULL, NULL); + d->config[0x00] = 0x8e; // vendor_id : Sun + d->config[0x01] = 0x10; + d->config[0x02] = 0x00; // device_id + d->config[0x03] = 0xa0; + d->config[0x04] = 0x06; // command = bus master, pci mem + d->config[0x05] = 0x00; + d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + d->config[0x07] = 0x03; // status = medium devsel + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x00; // programming i/f + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + return s->bus; +} + + diff --git a/tools/ioemu/hw/apic.c b/tools/ioemu/hw/apic.c index 65f96a5b76..8f88cce011 100644 --- a/tools/ioemu/hw/apic.c +++ b/tools/ioemu/hw/apic.c @@ -239,7 +239,7 @@ void cpu_set_apic_base(CPUState *env, uint64_t val) { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_set_apic_base: %016llx\n", val); + printf("cpu_set_apic_base: %016" PRIx64 "\n", val); #endif s->apicbase = (val & 0xfffff000) | (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); @@ -255,7 +255,7 @@ uint64_t cpu_get_apic_base(CPUState *env) { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase); + printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); #endif return s->apicbase; } diff --git a/tools/ioemu/hw/cdrom.c b/tools/ioemu/hw/cdrom.c new file mode 100644 index 0000000000..a43b417902 --- /dev/null +++ b/tools/ioemu/hw/cdrom.c @@ -0,0 +1,156 @@ +/* + * QEMU ATAPI CD-ROM Emulator + * + * Copyright (c) 2006 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. + */ + +/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved + here. */ + +#include + +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +/* same toc as bochs. Return -1 if error or the toc length */ +/* XXX: check this */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) +{ + uint8_t *q; + int len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, 0); + q += 3; + } else { + /* sector 0 */ + cpu_to_be32wu((uint32_t *)q, 0); + q += 4; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_be32wu((uint32_t *)q, nb_sectors); + q += 4; + } + len = q - buf; + cpu_to_be16wu((uint16_t *)buf, len - 2); + return len; +} + +/* mostly same info as PearPc */ +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) +{ + uint8_t *q; + int len; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_be32wu((uint32_t *)q, nb_sectors); + q += 4; + } + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + if (msf) { + *q++ = 0; + lba_to_msf(q, 0); + q += 3; + } else { + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } + + len = q - buf; + cpu_to_be16wu((uint16_t *)buf, len - 2); + return len; +} + + diff --git a/tools/ioemu/hw/cuda.c b/tools/ioemu/hw/cuda.c index dec5ffb310..f3c2b56010 100644 --- a/tools/ioemu/hw/cuda.c +++ b/tools/ioemu/hw/cuda.c @@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) } #if 0 #ifdef DEBUG_CUDA - printf("latch=%d counter=%lld delta_next=%lld\n", + printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", s->latch, d, next_time - d); #endif #endif diff --git a/tools/ioemu/hw/es1370.c b/tools/ioemu/hw/es1370.c index 9fddd9d8b3..0d2d861166 100644 --- a/tools/ioemu/hw/es1370.c +++ b/tools/ioemu/hw/es1370.c @@ -423,6 +423,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) as.freq = new_freq; as.nchannels = 1 << (new_fmt & 1); as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; + as.endianness = 0; if (i == ADC_CHANNEL) { s->adc_voice = @@ -432,8 +433,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) "es1370.adc", s, es1370_adc_callback, - &as, - 0 /* little endian */ + &as ); } else { @@ -444,8 +444,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) i ? "es1370.dac2" : "es1370.dac1", s, i ? es1370_dac2_callback : es1370_dac1_callback, - &as, - 0 /* litle endian */ + &as ); } } @@ -479,9 +478,10 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) IO_WRITE_PROTO (es1370_writeb) { ES1370State *s = opaque; - addr = es1370_fixup (s, addr); uint32_t shift, mask; + addr = es1370_fixup (s, addr); + switch (addr) { case ES1370_REG_CONTROL: case ES1370_REG_CONTROL + 1: diff --git a/tools/ioemu/hw/esp.c b/tools/ioemu/hw/esp.c index c0acbe6783..cdd062f789 100644 --- a/tools/ioemu/hw/esp.c +++ b/tools/ioemu/hw/esp.c @@ -38,17 +38,14 @@ do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level) #define ESPDMA_REGS 4 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f -#define TI_BUFSZ 1024*1024 // XXX +#define TI_BUFSZ 32 #define DMA_VER 0xa0000000 #define DMA_INTR 1 #define DMA_INTREN 0x10 +#define DMA_WRITE_MEM 0x100 #define DMA_LOADED 0x04000000 typedef struct ESPState ESPState; -typedef int ESPDMAFunc(ESPState *s, - target_phys_addr_t phys_addr, - int transfer_size1); - struct ESPState { BlockDriverState **bd; uint8_t rregs[ESP_MAXREG]; @@ -57,12 +54,14 @@ struct ESPState { uint32_t espdmaregs[ESPDMA_REGS]; uint32_t ti_size; uint32_t ti_rptr, ti_wptr; - int ti_dir; uint8_t ti_buf[TI_BUFSZ]; + int sense; int dma; - ESPDMAFunc *dma_cb; - int64_t offset, len; - int target; + SCSIDevice *scsi_dev[MAX_DISKS]; + SCSIDevice *current_dev; + uint8_t cmdbuf[TI_BUFSZ]; + int cmdlen; + int do_cmd; }; #define STAT_DO 0x00 @@ -83,394 +82,200 @@ struct ESPState { #define SEQ_0 0x0 #define SEQ_CD 0x4 -/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */ -static void lba_to_msf(uint8_t *buf, int lba) +static int get_cmd(ESPState *s, uint8_t *buf) { - lba += 150; - buf[0] = (lba / 75) / 60; - buf[1] = (lba / 75) % 60; - buf[2] = lba % 75; -} - -static inline void cpu_to_ube16(uint8_t *buf, int val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; -} - -/* same toc as bochs. Return -1 if error or the toc length */ -/* XXX: check this */ -static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) -{ - uint8_t *q; - int len; - - if (start_track > 1 && start_track != 0xaa) - return -1; - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - if (start_track <= 1) { - *q++ = 0; /* reserved */ - *q++ = 0x14; /* ADR, control */ - *q++ = 1; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, 0); - q += 3; - } else { - /* sector 0 */ - cpu_to_ube32(q, 0); - q += 4; - } - } - /* lead out track */ - *q++ = 0; /* reserved */ - *q++ = 0x16; /* ADR, control */ - *q++ = 0xaa; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -/* mostly same info as PearPc */ -static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, - int session_num) -{ - uint8_t *q; - int len; - - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa0; /* lead-in */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* first track */ - *q++ = 0x00; /* disk type */ - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa1; - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* last track */ - *q++ = 0x00; - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa2; /* lead-out */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - - *q++ = 1; /* session number */ - *q++ = 0x14; /* ADR, control */ - *q++ = 0; /* track number */ - *q++ = 1; /* point */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - if (msf) { - *q++ = 0; - lba_to_msf(q, 0); - q += 3; - } else { - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; - } - - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -static int esp_write_dma_cb(ESPState *s, - target_phys_addr_t phys_addr, - int transfer_size1) -{ - DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", - s->offset, s->len, s->ti_size, transfer_size1); - bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len); - s->offset = 0; - s->len = 0; - s->target = 0; - return 0; -} - -static void handle_satn(ESPState *s) -{ - uint8_t buf[32]; uint32_t dmaptr, dmalen; - unsigned int i; - int64_t nb_sectors; int target; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; - DPRINTF("Select with ATN len %d target %d\n", dmalen, target); + DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); + DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); cpu_physical_memory_read(dmaptr, buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); dmalen++; } - for (i = 0; i < dmalen; i++) { - DPRINTF("Command %2.2x\n", buf[i]); - } - s->ti_dir = 0; + s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; - if (target >= 4 || !s->bd[target]) { // No such drive + if (target >= 4 || !s->scsi_dev[target]) { + // No such drive s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); - return; + return 0; } - switch (buf[1]) { - case 0x0: - DPRINTF("Test Unit Ready (len %d)\n", buf[5]); - break; - case 0x12: - DPRINTF("Inquiry (len %d)\n", buf[5]); - memset(s->ti_buf, 0, 36); - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - s->ti_buf[0] = 5; - memcpy(&s->ti_buf[16], "QEMU CDROM ", 16); - } else { - s->ti_buf[0] = 0; - memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16); - } - memcpy(&s->ti_buf[8], "QEMU ", 8); - s->ti_buf[2] = 1; - s->ti_buf[3] = 2; - s->ti_buf[4] = 32; - s->ti_dir = 1; - s->ti_size = 36; - break; - case 0x1a: - DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]); - break; - case 0x25: - DPRINTF("Read Capacity (len %d)\n", buf[5]); - memset(s->ti_buf, 0, 8); - bdrv_get_geometry(s->bd[target], &nb_sectors); - s->ti_buf[0] = (nb_sectors >> 24) & 0xff; - s->ti_buf[1] = (nb_sectors >> 16) & 0xff; - s->ti_buf[2] = (nb_sectors >> 8) & 0xff; - s->ti_buf[3] = nb_sectors & 0xff; - s->ti_buf[4] = 0; - s->ti_buf[5] = 0; - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) - s->ti_buf[6] = 8; // sector size 2048 - else - s->ti_buf[6] = 2; // sector size 512 - s->ti_buf[7] = 0; - s->ti_dir = 1; - s->ti_size = 8; - break; - case 0x28: - { - int64_t offset, len; + s->current_dev = s->scsi_dev[target]; + return dmalen; +} - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; - len = ((buf[8] << 8) | buf[9]) * 4; - s->ti_size = len * 2048; - } else { - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; - s->ti_size = len * 512; - } - DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); - if (s->ti_size > TI_BUFSZ) { - DPRINTF("size too large %d\n", s->ti_size); - } - bdrv_read(s->bd[target], offset, s->ti_buf, len); - // XXX error handling - s->ti_dir = 1; - break; - } - case 0x2a: - { - int64_t offset, len; +static void do_cmd(ESPState *s, uint8_t *buf) +{ + int32_t datalen; + int lun; - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; - len = ((buf[8] << 8) | buf[9]) * 4; - s->ti_size = len * 2048; - } else { - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; - s->ti_size = len * 512; - } - DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); - if (s->ti_size > TI_BUFSZ) { - DPRINTF("size too large %d\n", s->ti_size); - } - s->dma_cb = esp_write_dma_cb; - s->offset = offset; - s->len = len; - s->target = target; - // XXX error handling - s->ti_dir = 0; - break; - } - case 0x43: - { - int start_track, format, msf, len; - - msf = buf[2] & 2; - format = buf[3] & 0xf; - start_track = buf[7]; - bdrv_get_geometry(s->bd[target], &nb_sectors); - DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); - switch(format) { - case 0: - len = cdrom_read_toc(nb_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->ti_size = len; - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - s->ti_size = 12; - break; - case 2: - len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->ti_size = len; - break; - default: - error_cmd: - DPRINTF("Read TOC error\n"); - // XXX error handling - break; - } - s->ti_dir = 1; - break; + DPRINTF("do_cmd: busid 0x%x\n", buf[0]); + lun = buf[0] & 7; + datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); + if (datalen == 0) { + s->ti_size = 0; + } else { + s->rregs[4] = STAT_IN | STAT_TC; + if (datalen > 0) { + s->rregs[4] |= STAT_DI; + s->ti_size = datalen; + } else { + s->rregs[4] |= STAT_DO; + s->ti_size = -datalen; } - default: - DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); - break; } - s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); } -static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) +static void handle_satn(ESPState *s) { - uint32_t dmaptr, dmalen; + uint8_t buf[32]; + int len; - dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer status len %d\n", dmalen); + len = get_cmd(s, buf); + if (len) + do_cmd(s, buf); +} + +static void handle_satn_stop(ESPState *s) +{ + s->cmdlen = get_cmd(s, s->cmdbuf); + if (s->cmdlen) { + DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); + s->do_cmd = 1; + s->espdmaregs[1] += s->cmdlen; + s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; + s->rregs[5] = INTR_BS | INTR_FC; + s->rregs[6] = SEQ_CD; + s->espdmaregs[0] |= DMA_INTR; + pic_set_irq(s->irq, 1); + } +} + +static void write_response(ESPState *s) +{ + uint32_t dmaptr; + + DPRINTF("Transfer status (sense=%d)\n", s->sense); + s->ti_buf[0] = s->sense; + s->ti_buf[1] = 0; if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); - cpu_physical_memory_write(dmaptr, buf, len); + DPRINTF("DMA Direction: %c\n", + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); + cpu_physical_memory_write(dmaptr, s->ti_buf, 2); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; } else { - memcpy(s->ti_buf, buf, len); - s->ti_size = dmalen; + s->ti_size = 2; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = dmalen; + s->rregs[7] = 2; } s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); } -static const uint8_t okbuf[] = {0, 0}; +static void esp_command_complete(void *opaque, uint32_t tag, int sense) +{ + ESPState *s = (ESPState *)opaque; + + DPRINTF("SCSI Command complete\n"); + if (s->ti_size != 0) + DPRINTF("SCSI command completed unexpectedly\n"); + s->ti_size = 0; + if (sense) + DPRINTF("Command failed\n"); + s->sense = sense; + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; +} static void handle_ti(ESPState *s) { - uint32_t dmaptr, dmalen; + uint32_t dmaptr, dmalen, minlen, len, from, to; unsigned int i; + int to_device; + uint8_t buf[TARGET_PAGE_SIZE]; dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer Information len %d\n", dmalen); + if (dmalen==0) { + dmalen=0x10000; + } + + if (s->do_cmd) + minlen = (dmalen < 32) ? dmalen : 32; + else + minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; + DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); - for (i = 0; i < s->ti_size; i++) { + /* Check if the transfer writes to to reads from the device. */ + to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; + DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", + to_device ? 'r': 'w', dmaptr, s->ti_size); + from = s->espdmaregs[1]; + to = from + minlen; + for (i = 0; i < minlen; i += len, from += len) { dmaptr = iommu_translate(s->espdmaregs[1] + i); - if (s->ti_dir) - cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); - else - cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); - } - if (s->dma_cb) { - s->dma_cb(s, s->espdmaregs[1], dmalen); - s->dma_cb = NULL; + if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { + len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); + } else { + len = to - from; + } + DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); + s->ti_size -= len; + if (s->do_cmd) { + DPRINTF("command len %d + %d\n", s->cmdlen, len); + cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); + return; + } else { + if (to_device) { + cpu_physical_memory_read(dmaptr, buf, len); + scsi_write_data(s->current_dev, buf, len); + } else { + scsi_read_data(s->current_dev, buf, len); + cpu_physical_memory_write(dmaptr, buf, len); + } + } } - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS; + if (s->ti_size) { + s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); + } + s->rregs[5] = INTR_BS; s->rregs[6] = 0; + s->rregs[7] = 0; s->espdmaregs[0] |= DMA_INTR; - } else { - s->ti_size = dmalen; - s->ti_rptr = 0; - s->ti_wptr = 0; - s->rregs[7] = dmalen; - } + } else if (s->do_cmd) { + DPRINTF("command len %d\n", s->cmdlen); + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); + return; + } pic_set_irq(s->irq, 1); } @@ -484,9 +289,8 @@ static void esp_reset(void *opaque) s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; - s->ti_dir = 0; s->dma = 0; - s->dma_cb = NULL; + s->do_cmd = 0; } static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) @@ -501,7 +305,12 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) // FIFO if (s->ti_size > 0) { s->ti_size--; - s->rregs[saddr] = s->ti_buf[s->ti_rptr++]; + if ((s->rregs[4] & 6) == 0) { + /* Data in/out. */ + scsi_read_data(s->current_dev, &s->rregs[2], 0); + } else { + s->rregs[2] = s->ti_buf[s->ti_rptr++]; + } pic_set_irq(s->irq, 1); } if (s->ti_size == 0) { @@ -536,8 +345,17 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 2: // FIFO - s->ti_size++; - s->ti_buf[s->ti_wptr++] = val & 0xff; + if (s->do_cmd) { + s->cmdbuf[s->cmdlen++] = val & 0xff; + } else if ((s->rregs[4] & 6) == 0) { + uint8_t buf; + buf = val & 0xff; + s->ti_size--; + scsi_write_data(s->current_dev, &buf, 0); + } else { + s->ti_size++; + s->ti_buf[s->ti_wptr++] = val & 0xff; + } break; case 3: s->rregs[saddr] = val; @@ -574,11 +392,11 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 0x11: DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); - dma_write(s, okbuf, 2); + write_response(s); break; case 0x12: DPRINTF("Message Accepted (%2.2x)\n", val); - dma_write(s, okbuf, 2); + write_response(s); s->rregs[5] = INTR_DC; s->rregs[6] = 0; break; @@ -586,11 +404,12 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Set ATN (%2.2x)\n", val); break; case 0x42: + DPRINTF("Set ATN (%2.2x)\n", val); handle_satn(s); break; case 0x43: DPRINTF("Set ATN & stop (%2.2x)\n", val); - handle_satn(s); + handle_satn_stop(s); break; default: DPRINTF("Unhandled ESP command (%2.2x)\n", val); @@ -660,7 +479,7 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va val |= DMA_VER; break; case 1: - s->espdmaregs[0] = DMA_LOADED; + s->espdmaregs[0] |= DMA_LOADED; break; default: break; @@ -693,7 +512,6 @@ static void esp_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); - qemu_put_be32s(f, &s->ti_dir); qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); qemu_put_be32s(f, &s->dma); } @@ -714,7 +532,6 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); - qemu_get_be32s(f, &s->ti_dir); qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); qemu_get_be32s(f, &s->dma); @@ -725,6 +542,7 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd { ESPState *s; int esp_io_memory, espdma_io_memory; + int i; s = qemu_mallocz(sizeof(ESPState)); if (!s) @@ -743,5 +561,11 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd register_savevm("esp", espaddr, 1, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) { + s->scsi_dev[i] = + scsi_disk_init(bs_table[i], esp_command_complete, s); + } + } } diff --git a/tools/ioemu/hw/grackle_pci.c b/tools/ioemu/hw/grackle_pci.c new file mode 100644 index 0000000000..e3cbceb49a --- /dev/null +++ b/tools/ioemu/hw/grackle_pci.c @@ -0,0 +1,156 @@ +/* + * QEMU Grackle (heathrow PPC) PCI host + * + * Copyright (c) 2006 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState GrackleState; + +static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + GrackleState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + s->config_reg = val; +} + +static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) +{ + GrackleState *s = opaque; + uint32_t val; + + val = s->config_reg; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_grackle_config_write[] = { + &pci_grackle_config_writel, + &pci_grackle_config_writel, + &pci_grackle_config_writel, +}; + +static CPUReadMemoryFunc *pci_grackle_config_read[] = { + &pci_grackle_config_readl, + &pci_grackle_config_readl, + &pci_grackle_config_readl, +}; + +static CPUWriteMemoryFunc *pci_grackle_write[] = { + &pci_host_data_writeb, + &pci_host_data_writew, + &pci_host_data_writel, +}; + +static CPUReadMemoryFunc *pci_grackle_read[] = { + &pci_host_data_readb, + &pci_host_data_readw, + &pci_host_data_readl, +}; + +/* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ +static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_grackle_init(uint32_t base, void *pic) +{ + GrackleState *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data; + + s = qemu_mallocz(sizeof(GrackleState)); + s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0); + + pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, + pci_grackle_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, + pci_grackle_write, s); + cpu_register_physical_memory(base, 0x1000, pci_mem_config); + cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); + d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice), + 0, NULL, NULL); + d->config[0x00] = 0x57; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x02; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x01; + d->config[0x0a] = 0x00; // class_sub = host + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x00; // header_type + + d->config[0x18] = 0x00; // primary_bus + d->config[0x19] = 0x01; // secondary_bus + d->config[0x1a] = 0x00; // subordinate_bus + d->config[0x1c] = 0x00; + d->config[0x1d] = 0x00; + + d->config[0x20] = 0x00; // memory_base + d->config[0x21] = 0x00; + d->config[0x22] = 0x01; // memory_limit + d->config[0x23] = 0x00; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x00; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x00; + +#if 0 + /* PCI2PCI bridge same values as PearPC - check this */ + d->config[0x00] = 0x11; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x01; // header_type + + d->config[0x18] = 0x0; // primary_bus + d->config[0x19] = 0x1; // secondary_bus + d->config[0x1a] = 0x1; // subordinate_bus + d->config[0x1c] = 0x10; // io_base + d->config[0x1d] = 0x20; // io_limit + + d->config[0x20] = 0x80; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x90; // memory_limit + d->config[0x23] = 0x80; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x84; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x85; +#endif + return s->bus; +} + diff --git a/tools/ioemu/hw/i8259.c b/tools/ioemu/hw/i8259.c index 6c2ddfff8c..c747f106e9 100644 --- a/tools/ioemu/hw/i8259.c +++ b/tools/ioemu/hw/i8259.c @@ -531,7 +531,7 @@ void irq_info(void) for (i = 0; i < 16; i++) { count = irq_count[i]; if (count > 0) - term_printf("%2d: %lld\n", i, count); + term_printf("%2d: %" PRId64 "\n", i, count); } #endif } diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c index 444bfe6184..92d33ef6e0 100644 --- a/tools/ioemu/hw/ide.c +++ b/tools/ioemu/hw/ide.c @@ -1133,127 +1133,6 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, } } -/* same toc as bochs. Return -1 if error or the toc length */ -/* XXX: check this */ -static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) -{ - uint8_t *q; - int nb_sectors, len; - - if (start_track > 1 && start_track != 0xaa) - return -1; - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - if (start_track <= 1) { - *q++ = 0; /* reserved */ - *q++ = 0x14; /* ADR, control */ - *q++ = 1; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, 0); - q += 3; - } else { - /* sector 0 */ - cpu_to_ube32(q, 0); - q += 4; - } - } - /* lead out track */ - *q++ = 0; /* reserved */ - *q++ = 0x16; /* ADR, control */ - *q++ = 0xaa; /* track number */ - *q++ = 0; /* reserved */ - nb_sectors = s->nb_sectors >> 2; - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -/* mostly same info as PearPc */ -static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, - int session_num) -{ - uint8_t *q; - int nb_sectors, len; - - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa0; /* lead-in */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* first track */ - *q++ = 0x00; /* disk type */ - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa1; - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* last track */ - *q++ = 0x00; - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa2; /* lead-out */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - nb_sectors = s->nb_sectors >> 2; - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - - *q++ = 1; /* session number */ - *q++ = 0x14; /* ADR, control */ - *q++ = 0; /* track number */ - *q++ = 1; /* point */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - if (msf) { - *q++ = 0; - lba_to_msf(q, 0); - q += 3; - } else { - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; - } - - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1501,7 +1380,7 @@ static void ide_atapi_cmd(IDEState *s) start_track = packet[6]; switch(format) { case 0: - len = cdrom_read_toc(s, buf, msf, start_track); + len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1515,7 +1394,7 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 12, max_len); break; case 2: - len = cdrom_read_toc_raw(s, buf, msf, start_track); + len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1829,6 +1708,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: + if (s->bs) + bdrv_flush(s->bs); + s->status = READY_STAT; + ide_set_irq(s); + break; case WIN_STANDBYNOW1: case WIN_IDLEIMMEDIATE: s->status = READY_STAT; @@ -2563,7 +2447,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) { PCIIDEState *d; uint8_t *pci_conf; @@ -2571,7 +2455,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) /* register a function 1 of PIIX3 */ d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", sizeof(PCIIDEState), - ((PCIDevice *)piix3_state)->devfn + 1, + devfn, NULL, NULL); d->type = IDE_TYPE_PIIX3; diff --git a/tools/ioemu/hw/lsi53c895a.c b/tools/ioemu/hw/lsi53c895a.c new file mode 100644 index 0000000000..24dff0eff5 --- /dev/null +++ b/tools/ioemu/hw/lsi53c895a.c @@ -0,0 +1,1571 @@ +/* + * QEMU LSI53C895A SCSI Host Bus Adapter emulation + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +/* ??? Need to check if the {read,write}[wl] routines work properly on + big-endian targets. */ + +#include "vl.h" + +//#define DEBUG_LSI +//#define DEBUG_LSI_REG + +#ifdef DEBUG_LSI +#define DPRINTF(fmt, args...) \ +do { printf("lsi_scsi: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) +#endif + +#define LSI_SCNTL0_TRG 0x01 +#define LSI_SCNTL0_AAP 0x02 +#define LSI_SCNTL0_EPC 0x08 +#define LSI_SCNTL0_WATN 0x10 +#define LSI_SCNTL0_START 0x20 + +#define LSI_SCNTL1_SST 0x01 +#define LSI_SCNTL1_IARB 0x02 +#define LSI_SCNTL1_AESP 0x04 +#define LSI_SCNTL1_RST 0x08 +#define LSI_SCNTL1_CON 0x10 +#define LSI_SCNTL1_DHP 0x20 +#define LSI_SCNTL1_ADB 0x40 +#define LSI_SCNTL1_EXC 0x80 + +#define LSI_SCNTL2_WSR 0x01 +#define LSI_SCNTL2_VUE0 0x02 +#define LSI_SCNTL2_VUE1 0x04 +#define LSI_SCNTL2_WSS 0x08 +#define LSI_SCNTL2_SLPHBEN 0x10 +#define LSI_SCNTL2_SLPMD 0x20 +#define LSI_SCNTL2_CHM 0x40 +#define LSI_SCNTL2_SDU 0x80 + +#define LSI_ISTAT0_DIP 0x01 +#define LSI_ISTAT0_SIP 0x02 +#define LSI_ISTAT0_INTF 0x04 +#define LSI_ISTAT0_CON 0x08 +#define LSI_ISTAT0_SEM 0x10 +#define LSI_ISTAT0_SIGP 0x20 +#define LSI_ISTAT0_SRST 0x40 +#define LSI_ISTAT0_ABRT 0x80 + +#define LSI_ISTAT1_SI 0x01 +#define LSI_ISTAT1_SRUN 0x02 +#define LSI_ISTAT1_FLSH 0x04 + +#define LSI_SSTAT0_SDP0 0x01 +#define LSI_SSTAT0_RST 0x02 +#define LSI_SSTAT0_WOA 0x04 +#define LSI_SSTAT0_LOA 0x08 +#define LSI_SSTAT0_AIP 0x10 +#define LSI_SSTAT0_OLF 0x20 +#define LSI_SSTAT0_ORF 0x40 +#define LSI_SSTAT0_ILF 0x80 + +#define LSI_SIST0_PAR 0x01 +#define LSI_SIST0_RST 0x02 +#define LSI_SIST0_UDC 0x04 +#define LSI_SIST0_SGE 0x08 +#define LSI_SIST0_RSL 0x10 +#define LSI_SIST0_SEL 0x20 +#define LSI_SIST0_CMP 0x40 +#define LSI_SIST0_MA 0x80 + +#define LSI_SIST1_HTH 0x01 +#define LSI_SIST1_GEN 0x02 +#define LSI_SIST1_STO 0x04 +#define LSI_SIST1_SBMC 0x10 + +#define LSI_SOCL_IO 0x01 +#define LSI_SOCL_CD 0x02 +#define LSI_SOCL_MSG 0x04 +#define LSI_SOCL_ATN 0x08 +#define LSI_SOCL_SEL 0x10 +#define LSI_SOCL_BSY 0x20 +#define LSI_SOCL_ACK 0x40 +#define LSI_SOCL_REQ 0x80 + +#define LSI_DSTAT_IID 0x01 +#define LSI_DSTAT_SIR 0x04 +#define LSI_DSTAT_SSI 0x08 +#define LSI_DSTAT_ABRT 0x10 +#define LSI_DSTAT_BF 0x20 +#define LSI_DSTAT_MDPE 0x40 +#define LSI_DSTAT_DFE 0x80 + +#define LSI_DCNTL_COM 0x01 +#define LSI_DCNTL_IRQD 0x02 +#define LSI_DCNTL_STD 0x04 +#define LSI_DCNTL_IRQM 0x08 +#define LSI_DCNTL_SSM 0x10 +#define LSI_DCNTL_PFEN 0x20 +#define LSI_DCNTL_PFF 0x40 +#define LSI_DCNTL_CLSE 0x80 + +#define LSI_DMODE_MAN 0x01 +#define LSI_DMODE_BOF 0x02 +#define LSI_DMODE_ERMP 0x04 +#define LSI_DMODE_ERL 0x08 +#define LSI_DMODE_DIOM 0x10 +#define LSI_DMODE_SIOM 0x20 + +#define LSI_CTEST2_DACK 0x01 +#define LSI_CTEST2_DREQ 0x02 +#define LSI_CTEST2_TEOP 0x04 +#define LSI_CTEST2_PCICIE 0x08 +#define LSI_CTEST2_CM 0x10 +#define LSI_CTEST2_CIO 0x20 +#define LSI_CTEST2_SIGP 0x40 +#define LSI_CTEST2_DDIR 0x80 + +#define LSI_CTEST5_BL2 0x04 +#define LSI_CTEST5_DDIR 0x08 +#define LSI_CTEST5_MASR 0x10 +#define LSI_CTEST5_DFSN 0x20 +#define LSI_CTEST5_BBCK 0x40 +#define LSI_CTEST5_ADCK 0x80 + +#define LSI_CCNTL0_DILS 0x01 +#define LSI_CCNTL0_DISFC 0x10 +#define LSI_CCNTL0_ENNDJ 0x20 +#define LSI_CCNTL0_PMJCTL 0x40 +#define LSI_CCNTL0_ENPMJ 0x80 + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 +#define PHASE_MASK 7 + +/* The HBA is ID 7, so for simplicitly limit to 7 devices. */ +#define LSI_MAX_DEVS 7 + +typedef struct { + PCIDevice pci_dev; + int mmio_io_addr; + int ram_io_addr; + uint32_t script_ram_base; + uint32_t data_len; + + int carry; /* ??? Should this be an a visible register somewhere? */ + int sense; + uint8_t msg; + /* Nonzero if a Wait Reselect instruction has been issued. */ + int waiting; + SCSIDevice *scsi_dev[LSI_MAX_DEVS]; + SCSIDevice *current_dev; + int current_lun; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint8_t istat0; + uint8_t istat1; + uint8_t dcmd; + uint8_t dstat; + uint8_t dien; + uint8_t sist0; + uint8_t sist1; + uint8_t sien0; + uint8_t sien1; + uint8_t mbox0; + uint8_t mbox1; + uint8_t dfifo; + uint8_t ctest3; + uint8_t ctest4; + uint8_t ctest5; + uint8_t ccntl0; + uint8_t ccntl1; + uint32_t dsp; + uint32_t dsps; + uint8_t dmode; + uint8_t dcntl; + uint8_t scntl0; + uint8_t scntl1; + uint8_t scntl2; + uint8_t scntl3; + uint8_t sstat0; + uint8_t sstat1; + uint8_t scid; + uint8_t sxfer; + uint8_t socl; + uint8_t sdid; + uint8_t sfbr; + uint8_t stest1; + uint8_t stest2; + uint8_t stest3; + uint8_t stime0; + uint8_t respid0; + uint8_t respid1; + uint32_t mmrs; + uint32_t mmws; + uint32_t sfs; + uint32_t drs; + uint32_t sbms; + uint32_t dmbs; + uint32_t dnad64; + uint32_t pmjad1; + uint32_t pmjad2; + uint32_t rbc; + uint32_t ua; + uint32_t ia; + uint32_t sbc; + uint32_t csbc; + uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ + + /* Script ram is stored as 32-bit words in host byteorder. */ + uint32_t script_ram[2048]; +} LSIState; + +static void lsi_soft_reset(LSIState *s) +{ + DPRINTF("Reset\n"); + s->carry = 0; + + s->waiting = 0; + s->dsa = 0; + s->dnad = 0; + s->dbc = 0; + s->temp = 0; + memset(s->scratch, 0, sizeof(s->scratch)); + s->istat0 = 0; + s->istat1 = 0; + s->dcmd = 0; + s->dstat = 0; + s->dien = 0; + s->sist0 = 0; + s->sist1 = 0; + s->sien0 = 0; + s->sien1 = 0; + s->mbox0 = 0; + s->mbox1 = 0; + s->dfifo = 0; + s->ctest3 = 0; + s->ctest4 = 0; + s->ctest5 = 0; + s->ccntl0 = 0; + s->ccntl1 = 0; + s->dsp = 0; + s->dsps = 0; + s->dmode = 0; + s->dcntl = 0; + s->scntl0 = 0xc0; + s->scntl1 = 0; + s->scntl2 = 0; + s->scntl3 = 0; + s->sstat0 = 0; + s->sstat1 = 0; + s->scid = 7; + s->sxfer = 0; + s->socl = 0; + s->stest1 = 0; + s->stest2 = 0; + s->stest3 = 0; + s->stime0 = 0; + s->respid0 = 0x80; + s->respid1 = 0; + s->mmrs = 0; + s->mmws = 0; + s->sfs = 0; + s->drs = 0; + s->sbms = 0; + s->dmbs = 0; + s->dnad64 = 0; + s->pmjad1 = 0; + s->pmjad2 = 0; + s->rbc = 0; + s->ua = 0; + s->ia = 0; + s->sbc = 0; + s->csbc = 0; +} + +static uint8_t lsi_reg_readb(LSIState *s, int offset); +static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); + +static inline uint32_t read_dword(LSIState *s, uint32_t addr) +{ + uint32_t buf; + + /* Optimize reading from SCRIPTS RAM. */ + if ((addr & 0xffffe000) == s->script_ram_base) { + return s->script_ram[(addr & 0x1fff) >> 2]; + } + cpu_physical_memory_read(addr, (uint8_t *)&buf, 4); + return cpu_to_le32(buf); +} + +static void lsi_stop_script(LSIState *s) +{ + s->istat1 &= ~LSI_ISTAT1_SRUN; +} + +static void lsi_update_irq(LSIState *s) +{ + int level; + static int last_level; + + /* It's unclear whether the DIP/SIP bits should be cleared when the + Interrupt Status Registers are cleared or when istat0 is read. + We currently do the formwer, which seems to work. */ + level = 0; + if (s->dstat) { + if (s->dstat & s->dien) + level = 1; + s->istat0 |= LSI_ISTAT0_DIP; + } else { + s->istat0 &= ~LSI_ISTAT0_DIP; + } + + if (s->sist0 || s->sist1) { + if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1)) + level = 1; + s->istat0 |= LSI_ISTAT0_SIP; + } else { + s->istat0 &= ~LSI_ISTAT0_SIP; + } + if (s->istat0 & LSI_ISTAT0_INTF) + level = 1; + + if (level != last_level) { + DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n", + level, s->dstat, s->sist1, s->sist0); + last_level = level; + } + pci_set_irq(&s->pci_dev, 0, level); +} + +/* Stop SCRIPTS execution and raise a SCSI interrupt. */ +static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1) +{ + uint32_t mask0; + uint32_t mask1; + + DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + stat1, stat0, s->sist1, s->sist0); + s->sist0 |= stat0; + s->sist1 |= stat1; + /* Stop processor on fatal or unmasked interrupt. As a special hack + we don't stop processing when raising STO. Instead continue + execution and stop at the next insn that accesses the SCSI bus. */ + mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL); + mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH); + mask1 &= ~LSI_SIST1_STO; + if (s->sist0 & mask0 || s->sist1 & mask1) { + lsi_stop_script(s); + } + lsi_update_irq(s); +} + +/* Stop SCRIPTS execution and raise a DMA interrupt. */ +static void lsi_script_dma_interrupt(LSIState *s, int stat) +{ + DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat); + s->dstat |= stat; + lsi_update_irq(s); + lsi_stop_script(s); +} + +static inline void lsi_set_phase(LSIState *s, int phase) +{ + s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase; +} + +static void lsi_bad_phase(LSIState *s, int out, int new_phase) +{ + /* Trigger a phase mismatch. */ + if (s->ccntl0 & LSI_CCNTL0_ENPMJ) { + if ((s->ccntl0 & LSI_CCNTL0_PMJCTL) || out) { + s->dsp = s->pmjad1; + } else { + s->dsp = s->pmjad2; + } + DPRINTF("Data phase mismatch jump to %08x\n", s->dsp); + } else { + DPRINTF("Phase mismatch interrupt\n"); + lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); + lsi_stop_script(s); + } + lsi_set_phase(s, new_phase); +} + +static void lsi_do_dma(LSIState *s, int out) +{ + uint8_t buf[TARGET_PAGE_SIZE]; + uint32_t addr; + uint32_t count; + int n; + + count = s->dbc; + addr = s->dnad; + DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in", + addr, count, s->data_len); + /* ??? Too long transfers are truncated. Don't know if this is the + correct behavior. */ + if (count > s->data_len) { + /* If the DMA length is greater then the device data length then + a phase mismatch will occur. */ + count = s->data_len; + s->dbc = count; + lsi_bad_phase(s, out, PHASE_ST); + } + + s->csbc += count; + + /* ??? Set SFBR to first data byte. */ + while (count) { + n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; + if (out) { + cpu_physical_memory_read(addr, buf, n); + scsi_write_data(s->current_dev, buf, n); + } else { + scsi_read_data(s->current_dev, buf, n); + cpu_physical_memory_write(addr, buf, n); + } + addr += n; + count -= n; + } +} + + +static void lsi_do_command(LSIState *s) +{ + uint8_t buf[16]; + int n; + + DPRINTF("Send command len=%d\n", s->dbc); + if (s->dbc > 16) + s->dbc = 16; + cpu_physical_memory_read(s->dnad, buf, s->dbc); + s->sfbr = buf[0]; + n = scsi_send_command(s->current_dev, 0, buf, s->current_lun); + if (n > 0) { + s->data_len = n; + lsi_set_phase(s, PHASE_DI); + } else if (n < 0) { + s->data_len = -n; + lsi_set_phase(s, PHASE_DO); + } +} + +static void lsi_command_complete(void *opaque, uint32_t tag, int sense) +{ + LSIState *s = (LSIState *)opaque; + + DPRINTF("Command complete sense=%d\n", sense); + s->sense = sense; + lsi_set_phase(s, PHASE_ST); +} + +static void lsi_do_status(LSIState *s) +{ + DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); + if (s->dbc != 1) + BADF("Bad Status move\n"); + s->dbc = 1; + s->msg = s->sense; + cpu_physical_memory_write(s->dnad, &s->msg, 1); + s->sfbr = s->msg; + lsi_set_phase(s, PHASE_MI); + s->msg = 0; /* COMMAND COMPLETE */ +} + +static void lsi_disconnect(LSIState *s) +{ + s->scntl1 &= ~LSI_SCNTL1_CON; + s->sstat1 &= ~PHASE_MASK; +} + +static void lsi_do_msgin(LSIState *s) +{ + DPRINTF("Message in len=%d\n", s->dbc); + s->dbc = 1; + s->sfbr = s->msg; + cpu_physical_memory_write(s->dnad, &s->msg, 1); + if (s->msg == 0) { + lsi_disconnect(s); + } else { + /* ??? Check if ATN (not yet implemented) is asserted and maybe + switch to PHASE_MO. */ + lsi_set_phase(s, PHASE_CMD); + } +} + +static void lsi_do_msgout(LSIState *s) +{ + uint8_t msg; + + DPRINTF("MSG out len=%d\n", s->dbc); + if (s->dbc != 1) { + /* Multibyte messages not implemented. */ + s->msg = 7; /* MESSAGE REJECT */ + //s->dbc = 1; + //lsi_bad_phase(s, 1, PHASE_MI); + lsi_set_phase(s, PHASE_MI); + return; + } + cpu_physical_memory_read(s->dnad, &msg, 1); + s->sfbr = msg; + s->dnad++; + + switch (msg) { + case 0x00: + DPRINTF("Got Disconnect\n"); + lsi_disconnect(s); + return; + case 0x08: + DPRINTF("Got No Operation\n"); + lsi_set_phase(s, PHASE_CMD); + return; + } + if ((msg & 0x80) == 0) { + DPRINTF("Unimplemented message 0x%d\n", msg); + s->msg = 7; /* MESSAGE REJECT */ + lsi_bad_phase(s, 1, PHASE_MI); + return; + } + s->current_lun = msg & 7; + DPRINTF("Select LUN %d\n", s->current_lun); + lsi_set_phase(s, PHASE_CMD); +} + +/* Sign extend a 24-bit value. */ +static inline int32_t sxt24(int32_t n) +{ + return (n << 8) >> 8; +} + +static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) +{ + int n; + uint8_t buf[TARGET_PAGE_SIZE]; + + DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + while (count) { + n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; + cpu_physical_memory_read(src, buf, n); + cpu_physical_memory_write(dest, buf, n); + src += n; + dest += n; + count -= n; + } +} + +static void lsi_execute_script(LSIState *s) +{ + uint32_t insn; + uint32_t addr; + int opcode; + + s->istat1 |= LSI_ISTAT1_SRUN; +again: + insn = read_dword(s, s->dsp); + addr = read_dword(s, s->dsp + 4); + DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr); + s->dsps = addr; + s->dcmd = insn >> 24; + s->dsp += 8; + switch (insn >> 30) { + case 0: /* Block move. */ + if (s->sist1 & LSI_SIST1_STO) { + DPRINTF("Delayed select timeout\n"); + lsi_stop_script(s); + break; + } + s->dbc = insn & 0xffffff; + s->rbc = s->dbc; + if (insn & (1 << 29)) { + /* Indirect addressing. */ + addr = read_dword(s, addr); + } else if (insn & (1 << 28)) { + uint32_t buf[2]; + int32_t offset; + /* Table indirect addressing. */ + offset = sxt24(addr); + cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8); + s->dbc = cpu_to_le32(buf[0]); + addr = cpu_to_le32(buf[1]); + } + if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { + DPRINTF("Wrong phase got %d expected %d\n", + s->sstat1 & PHASE_MASK, (insn >> 24) & 7); + lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); + break; + } + s->dnad = addr; + switch (s->sstat1 & 0x7) { + case PHASE_DO: + lsi_do_dma(s, 1); + break; + case PHASE_DI: + lsi_do_dma(s, 0); + break; + case PHASE_CMD: + lsi_do_command(s); + break; + case PHASE_ST: + lsi_do_status(s); + break; + case PHASE_MO: + lsi_do_msgout(s); + break; + case PHASE_MI: + lsi_do_msgin(s); + break; + default: + BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK); + exit(1); + } + s->dfifo = s->dbc & 0xff; + s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3); + s->sbc = s->dbc; + s->rbc -= s->dbc; + s->ua = addr + s->dbc; + /* ??? Set ESA. */ + s->ia = s->dsp - 8; + break; + + case 1: /* IO or Read/Write instruction. */ + opcode = (insn >> 27) & 7; + if (opcode < 5) { + uint32_t id; + + if (insn & (1 << 25)) { + id = read_dword(s, s->dsa + sxt24(insn)); + } else { + id = addr; + } + id = (id >> 16) & 0xf; + if (insn & (1 << 26)) { + addr = s->dsp + sxt24(addr); + } + s->dnad = addr; + switch (opcode) { + case 0: /* Select */ + s->sstat0 |= LSI_SSTAT0_WOA; + s->scntl1 &= ~LSI_SCNTL1_IARB; + s->sdid = id; + if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { + DPRINTF("Selected absent target %d\n", id); + lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); + lsi_disconnect(s); + break; + } + DPRINTF("Selected target %d%s\n", + id, insn & (1 << 3) ? " ATN" : ""); + /* ??? Linux drivers compain when this is set. Maybe + it only applies in low-level mode (unimplemented). + lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ + s->current_dev = s->scsi_dev[id]; + s->scntl1 |= LSI_SCNTL1_CON; + if (insn & (1 << 3)) { + s->socl |= LSI_SOCL_ATN; + } + lsi_set_phase(s, PHASE_MO); + break; + case 1: /* Disconnect */ + DPRINTF("Wait Disconect\n"); + s->scntl1 &= ~LSI_SCNTL1_CON; + break; + case 2: /* Wait Reselect */ + DPRINTF("Wait Reselect\n"); + s->waiting = 1; + break; + case 3: /* Set */ + DPRINTF("Set%s%s%s%s\n", + insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + s->socl |= LSI_SOCL_ATN; + lsi_set_phase(s, PHASE_MO); + } + if (insn & (1 << 9)) { + BADF("Target mode not implemented\n"); + exit(1); + } + if (insn & (1 << 10)) + s->carry = 1; + break; + case 4: /* Clear */ + DPRINTF("Clear%s%s%s%s\n", + insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + s->socl &= ~LSI_SOCL_ATN; + } + if (insn & (1 << 10)) + s->carry = 0; + break; + } + } else { + uint8_t op0; + uint8_t op1; + uint8_t data8; + int reg; + int operator; +#ifdef DEBUG_LSI + static const char *opcode_names[3] = + {"Write", "Read", "Read-Modify-Write"}; + static const char *operator_names[8] = + {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"}; +#endif + + reg = ((insn >> 16) & 0x7f) | (insn & 0x80); + data8 = (insn >> 8) & 0xff; + opcode = (insn >> 27) & 7; + operator = (insn >> 24) & 7; + DPRINTF("%s reg 0x%x %s data8 %d%s\n", + opcode_names[opcode - 5], reg, + operator_names[operator], data8, + (insn & (1 << 23)) ? " SFBR" : ""); + op0 = op1 = 0; + switch (opcode) { + case 5: /* From SFBR */ + op0 = s->sfbr; + op1 = data8; + break; + case 6: /* To SFBR */ + if (operator) + op0 = lsi_reg_readb(s, reg); + op1 = data8; + break; + case 7: /* Read-modify-write */ + if (operator) + op0 = lsi_reg_readb(s, reg); + if (insn & (1 << 23)) { + op1 = s->sfbr; + } else { + op1 = data8; + } + break; + } + + switch (operator) { + case 0: /* move */ + op0 = op1; + break; + case 1: /* Shift left */ + op1 = op0 >> 7; + op0 = (op0 << 1) | s->carry; + s->carry = op1; + break; + case 2: /* OR */ + op0 |= op1; + break; + case 3: /* XOR */ + op0 |= op1; + break; + case 4: /* AND */ + op0 &= op1; + break; + case 5: /* SHR */ + op1 = op0 & 1; + op0 = (op0 >> 1) | (s->carry << 7); + break; + case 6: /* ADD */ + op0 += op1; + s->carry = op0 < op1; + break; + case 7: /* ADC */ + op0 += op1 + s->carry; + if (s->carry) + s->carry = op0 <= op1; + else + s->carry = op0 < op1; + break; + } + + switch (opcode) { + case 5: /* From SFBR */ + case 7: /* Read-modify-write */ + lsi_reg_writeb(s, reg, op0); + break; + case 6: /* To SFBR */ + s->sfbr = op0; + break; + } + } + break; + + case 2: /* Transfer Control. */ + { + int cond; + int jmp; + + if ((insn & 0x002e0000) == 0) { + DPRINTF("NOP\n"); + break; + } + if (s->sist1 & LSI_SIST1_STO) { + DPRINTF("Delayed select timeout\n"); + lsi_stop_script(s); + break; + } + cond = jmp = (insn & (1 << 19)) != 0; + if (cond == jmp && (insn & (1 << 21))) { + DPRINTF("Compare carry %d\n", s->carry == jmp); + cond = s->carry != 0; + } + if (cond == jmp && (insn & (1 << 17))) { + DPRINTF("Compare phase %d %c= %d\n", + (s->sstat1 & PHASE_MASK), + jmp ? '=' : '!', + ((insn >> 24) & 7)); + cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); + } + if (cond == jmp && (insn & (1 << 18))) { + uint8_t mask; + + mask = (~insn >> 8) & 0xff; + DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n", + s->sfbr, mask, jmp ? '=' : '!', insn & mask); + cond = (s->sfbr & mask) == (insn & mask); + } + if (cond == jmp) { + if (insn & (1 << 23)) { + /* Relative address. */ + addr = s->dsp + sxt24(addr); + } + switch ((insn >> 27) & 7) { + case 0: /* Jump */ + DPRINTF("Jump to 0x%08x\n", addr); + s->dsp = addr; + break; + case 1: /* Call */ + DPRINTF("Call 0x%08x\n", addr); + s->temp = s->dsp; + s->dsp = addr; + break; + case 2: /* Return */ + DPRINTF("Return to 0x%08x\n", s->temp); + s->dsp = s->temp; + break; + case 3: /* Interrupt */ + DPRINTF("Interrupt 0x%08x\n", s->dsps); + if ((insn & (1 << 20)) != 0) { + s->istat0 |= LSI_ISTAT0_INTF; + lsi_update_irq(s); + } else { + lsi_script_dma_interrupt(s, LSI_DSTAT_SIR); + } + break; + default: + DPRINTF("Illegal transfer control\n"); + lsi_script_dma_interrupt(s, LSI_DSTAT_IID); + break; + } + } else { + DPRINTF("Control condition failed\n"); + } + } + break; + + case 3: + if ((insn & (1 << 29)) == 0) { + /* Memory move. */ + uint32_t dest; + /* ??? The docs imply the destination address is loaded into + the TEMP register. However the Linux drivers rely on + the value being presrved. */ + dest = read_dword(s, s->dsp); + s->dsp += 4; + lsi_memcpy(s, dest, addr, insn & 0xffffff); + } else { + uint8_t data[7]; + int reg; + int n; + int i; + + if (insn & (1 << 28)) { + addr = s->dsa + sxt24(addr); + } + n = (insn & 7); + reg = (insn >> 16) & 0xff; + if (insn & (1 << 24)) { + DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + cpu_physical_memory_read(addr, data, n); + for (i = 0; i < n; i++) { + lsi_reg_writeb(s, reg + i, data[i]); + } + } else { + DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + for (i = 0; i < n; i++) { + data[i] = lsi_reg_readb(s, reg + i); + } + cpu_physical_memory_write(addr, data, n); + } + } + } + /* ??? Need to avoid infinite loops. */ + if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { + if (s->dcntl & LSI_DCNTL_SSM) { + lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); + } else { + goto again; + } + } + DPRINTF("SCRIPTS execution stopped\n"); +} + +static uint8_t lsi_reg_readb(LSIState *s, int offset) +{ + uint8_t tmp; +#define CASE_GET_REG32(name, addr) \ + case addr: return s->name & 0xff; \ + case addr + 1: return (s->name >> 8) & 0xff; \ + case addr + 2: return (s->name >> 16) & 0xff; \ + case addr + 3: return (s->name >> 24) & 0xff; + +#ifdef DEBUG_LSI_REG + DPRINTF("Read reg %x\n", offset); +#endif + switch (offset) { + case 0x00: /* SCNTL0 */ + return s->scntl0; + case 0x01: /* SCNTL1 */ + return s->scntl1; + case 0x02: /* SCNTL2 */ + return s->scntl2; + case 0x03: /* SCNTL3 */ + return s->scntl3; + case 0x04: /* SCID */ + return s->scid; + case 0x05: /* SXFER */ + return s->sxfer; + case 0x06: /* SDID */ + return s->sdid; + case 0x07: /* GPREG0 */ + return 0x7f; + case 0xb: /* SBCL */ + /* ??? This is not correct. However it's (hopefully) only + used for diagnostics, so should be ok. */ + return 0; + case 0xc: /* DSTAT */ + tmp = s->dstat | 0x80; + if ((s->istat0 & LSI_ISTAT0_INTF) == 0) + s->dstat = 0; + lsi_update_irq(s); + return tmp; + case 0x0d: /* SSTAT0 */ + return s->sstat0; + case 0x0e: /* SSTAT1 */ + return s->sstat1; + case 0x0f: /* SSTAT2 */ + return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; + CASE_GET_REG32(dsa, 0x10) + case 0x14: /* ISTAT0 */ + return s->istat0; + case 0x16: /* MBOX0 */ + return s->mbox0; + case 0x17: /* MBOX1 */ + return s->mbox1; + case 0x18: /* CTEST0 */ + return 0xff; + case 0x19: /* CTEST1 */ + return 0; + case 0x1a: /* CTEST2 */ + tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM; + if (s->istat0 & LSI_ISTAT0_SIGP) { + s->istat0 &= ~LSI_ISTAT0_SIGP; + tmp |= LSI_CTEST2_SIGP; + } + return tmp; + case 0x1b: /* CTEST3 */ + return s->ctest3; + CASE_GET_REG32(temp, 0x1c) + case 0x20: /* DFIFO */ + return 0; + case 0x21: /* CTEST4 */ + return s->ctest4; + case 0x22: /* CTEST5 */ + return s->ctest5; + case 0x24: /* DBC[0:7] */ + return s->dbc & 0xff; + case 0x25: /* DBC[8:15] */ + return (s->dbc >> 8) & 0xff; + case 0x26: /* DBC[16->23] */ + return (s->dbc >> 16) & 0xff; + case 0x27: /* DCMD */ + return s->dcmd; + CASE_GET_REG32(dsp, 0x2c) + CASE_GET_REG32(dsps, 0x30) + CASE_GET_REG32(scratch[0], 0x34) + case 0x38: /* DMODE */ + return s->dmode; + case 0x39: /* DIEN */ + return s->dien; + case 0x3b: /* DCNTL */ + return s->dcntl; + case 0x40: /* SIEN0 */ + return s->sien0; + case 0x41: /* SIEN1 */ + return s->sien1; + case 0x42: /* SIST0 */ + tmp = s->sist0; + s->sist0 = 0; + lsi_update_irq(s); + return tmp; + case 0x43: /* SIST1 */ + tmp = s->sist1; + s->sist1 = 0; + lsi_update_irq(s); + return tmp; + case 0x47: /* GPCNTL0 */ + return 0x0f; + case 0x48: /* STIME0 */ + return s->stime0; + case 0x4a: /* RESPID0 */ + return s->respid0; + case 0x4b: /* RESPID1 */ + return s->respid1; + case 0x4d: /* STEST1 */ + return s->stest1; + case 0x4e: /* STEST2 */ + return s->stest2; + case 0x4f: /* STEST3 */ + return s->stest3; + case 0x52: /* STEST4 */ + return 0xe0; + case 0x56: /* CCNTL0 */ + return s->ccntl0; + case 0x57: /* CCNTL1 */ + return s->ccntl1; + case 0x58: case 0x59: /* SBDL */ + return 0; + CASE_GET_REG32(mmrs, 0xa0) + CASE_GET_REG32(mmws, 0xa4) + CASE_GET_REG32(sfs, 0xa8) + CASE_GET_REG32(drs, 0xac) + CASE_GET_REG32(sbms, 0xb0) + CASE_GET_REG32(dmbs, 0xb4) + CASE_GET_REG32(dnad64, 0xb8) + CASE_GET_REG32(pmjad1, 0xc0) + CASE_GET_REG32(pmjad2, 0xc4) + CASE_GET_REG32(rbc, 0xc8) + CASE_GET_REG32(ua, 0xcc) + CASE_GET_REG32(ia, 0xd4) + CASE_GET_REG32(sbc, 0xd8) + CASE_GET_REG32(csbc, 0xdc) + } + if (offset >= 0x5c && offset < 0xa0) { + int n; + int shift; + n = (offset - 0x58) >> 2; + shift = (offset & 3) * 8; + return (s->scratch[n] >> shift) & 0xff; + } + BADF("readb 0x%x\n", offset); + exit(1); +#undef CASE_GET_REG32 +} + +static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) +{ +#define CASE_SET_REG32(name, addr) \ + case addr : s->name &= 0xffffff00; s->name |= val; break; \ + case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \ + case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \ + case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break; + +#ifdef DEBUG_LSI_REG + DPRINTF("Write reg %x = %02x\n", offset, val); +#endif + switch (offset) { + case 0x00: /* SCNTL0 */ + s->scntl0 = val; + if (val & LSI_SCNTL0_START) { + BADF("Start sequence not implemented\n"); + } + break; + case 0x01: /* SCNTL1 */ + s->scntl1 = val & ~LSI_SCNTL1_SST; + if (val & LSI_SCNTL1_IARB) { + BADF("Immediate Arbritration not implemented\n"); + } + if (val & LSI_SCNTL1_RST) { + s->sstat0 |= LSI_SSTAT0_RST; + lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); + } else { + s->sstat0 &= ~LSI_SSTAT0_RST; + } + break; + case 0x02: /* SCNTL2 */ + val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS); + s->scntl3 = val; + break; + case 0x03: /* SCNTL3 */ + s->scntl3 = val; + break; + case 0x04: /* SCID */ + s->scid = val; + break; + case 0x05: /* SXFER */ + s->sxfer = val; + break; + case 0x07: /* GPREG0 */ + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Linux writes to these readonly registers on startup. */ + return; + CASE_SET_REG32(dsa, 0x10) + case 0x14: /* ISTAT0 */ + s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0); + if (val & LSI_ISTAT0_ABRT) { + lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT); + } + if (val & LSI_ISTAT0_INTF) { + s->istat0 &= ~LSI_ISTAT0_INTF; + lsi_update_irq(s); + } + if (s->waiting && val & LSI_ISTAT0_SIGP) { + DPRINTF("Woken by SIGP\n"); + s->waiting = 0; + s->dsp = s->dnad; + lsi_execute_script(s); + } + if (val & LSI_ISTAT0_SRST) { + lsi_soft_reset(s); + } + case 0x16: /* MBOX0 */ + s->mbox0 = val; + case 0x17: /* MBOX1 */ + s->mbox1 = val; + case 0x1b: /* CTEST3 */ + s->ctest3 = val & 0x0f; + break; + CASE_SET_REG32(temp, 0x1c) + case 0x21: /* CTEST4 */ + if (val & 7) { + BADF("Unimplemented CTEST4-FBL 0x%x\n", val); + } + s->ctest4 = val; + break; + case 0x22: /* CTEST5 */ + if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) { + BADF("CTEST5 DMA increment not implemented\n"); + } + s->ctest5 = val; + break; + case 0x2c: /* DSPS[0:7] */ + s->dsp &= 0xffffff00; + s->dsp |= val; + break; + case 0x2d: /* DSPS[8:15] */ + s->dsp &= 0xffff00ff; + s->dsp |= val << 8; + break; + case 0x2e: /* DSPS[16:23] */ + s->dsp &= 0xff00ffff; + s->dsp |= val << 16; + break; + case 0x2f: /* DSPS[14:31] */ + s->dsp &= 0x00ffffff; + s->dsp |= val << 24; + if ((s->dmode & LSI_DMODE_MAN) == 0 + && (s->istat1 & LSI_ISTAT1_SRUN) == 0) + lsi_execute_script(s); + break; + CASE_SET_REG32(dsps, 0x30) + CASE_SET_REG32(scratch[0], 0x34) + case 0x38: /* DMODE */ + if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) { + BADF("IO mappings not implemented\n"); + } + s->dmode = val; + break; + case 0x39: /* DIEN */ + s->dien = val; + lsi_update_irq(s); + break; + case 0x3b: /* DCNTL */ + s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); + if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) + lsi_execute_script(s); + break; + case 0x40: /* SIEN0 */ + s->sien0 = val; + lsi_update_irq(s); + break; + case 0x41: /* SIEN1 */ + s->sien1 = val; + lsi_update_irq(s); + break; + case 0x47: /* GPCNTL0 */ + break; + case 0x48: /* STIME0 */ + s->stime0 = val; + break; + case 0x49: /* STIME1 */ + if (val & 0xf) { + DPRINTF("General purpose timer not implemented\n"); + /* ??? Raising the interrupt immediately seems to be sufficient + to keep the FreeBSD driver happy. */ + lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN); + } + break; + case 0x4a: /* RESPID0 */ + s->respid0 = val; + break; + case 0x4b: /* RESPID1 */ + s->respid1 = val; + break; + case 0x4d: /* STEST1 */ + s->stest1 = val; + break; + case 0x4e: /* STEST2 */ + if (val & 1) { + BADF("Low level mode not implemented\n"); + } + s->stest2 = val; + break; + case 0x4f: /* STEST3 */ + if (val & 0x41) { + BADF("SCSI FIFO test mode not implemented\n"); + } + s->stest3 = val; + break; + case 0x56: /* CCNTL0 */ + s->ccntl0 = val; + break; + case 0x57: /* CCNTL1 */ + s->ccntl1 = val; + break; + CASE_SET_REG32(mmrs, 0xa0) + CASE_SET_REG32(mmws, 0xa4) + CASE_SET_REG32(sfs, 0xa8) + CASE_SET_REG32(drs, 0xac) + CASE_SET_REG32(sbms, 0xb0) + CASE_SET_REG32(dmbs, 0xb4) + CASE_SET_REG32(dnad64, 0xb8) + CASE_SET_REG32(pmjad1, 0xc0) + CASE_SET_REG32(pmjad2, 0xc4) + CASE_SET_REG32(rbc, 0xc8) + CASE_SET_REG32(ua, 0xcc) + CASE_SET_REG32(ia, 0xd4) + CASE_SET_REG32(sbc, 0xd8) + CASE_SET_REG32(csbc, 0xdc) + default: + if (offset >= 0x5c && offset < 0xa0) { + int n; + int shift; + n = (offset - 0x58) >> 2; + shift = (offset & 3) * 8; + s->scratch[n] &= ~(0xff << shift); + s->scratch[n] |= (val & 0xff) << shift; + } else { + BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val); + } + } +#undef CASE_SET_REG32 +} + +static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + lsi_reg_writeb(s, addr & 0xff, val); +} + +static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); +} + +static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); + lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); + lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff); +} + +static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + + return lsi_reg_readb(s, addr & 0xff); +} + +static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + return val; +} + +static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + val |= lsi_reg_readb(s, addr + 2) << 16; + val |= lsi_reg_readb(s, addr + 3) << 24; + return val; +} + +static CPUReadMemoryFunc *lsi_mmio_readfn[3] = { + lsi_mmio_readb, + lsi_mmio_readw, + lsi_mmio_readl, +}; + +static CPUWriteMemoryFunc *lsi_mmio_writefn[3] = { + lsi_mmio_writeb, + lsi_mmio_writew, + lsi_mmio_writel, +}; + +static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + uint32_t newval; + int shift; + + addr &= 0x1fff; + newval = s->script_ram[addr >> 2]; + shift = (addr & 3) * 8; + newval &= ~(0xff << shift); + newval |= val << shift; + s->script_ram[addr >> 2] = newval; +} + +static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + uint32_t newval; + + addr &= 0x1fff; + newval = s->script_ram[addr >> 2]; + if (addr & 2) { + newval = (newval & 0xffff) | (val << 16); + } else { + newval = (newval & 0xffff0000) | val; + } + s->script_ram[addr >> 2] = newval; +} + + +static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0x1fff; + s->script_ram[addr >> 2] = val; +} + +static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + + addr &= 0x1fff; + val = s->script_ram[addr >> 2]; + val >>= (addr & 3) * 8; + return val & 0xff; +} + +static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + + addr &= 0x1fff; + val = s->script_ram[addr >> 2]; + if (addr & 2) + val >>= 16; + return le16_to_cpu(val); +} + +static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0x1fff; + return le32_to_cpu(s->script_ram[addr >> 2]); +} + +static CPUReadMemoryFunc *lsi_ram_readfn[3] = { + lsi_ram_readb, + lsi_ram_readw, + lsi_ram_readl, +}; + +static CPUWriteMemoryFunc *lsi_ram_writefn[3] = { + lsi_ram_writeb, + lsi_ram_writew, + lsi_ram_writel, +}; + +static uint32_t lsi_io_readb(void *opaque, uint32_t addr) +{ + LSIState *s = (LSIState *)opaque; + return lsi_reg_readb(s, addr & 0xff); +} + +static uint32_t lsi_io_readw(void *opaque, uint32_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + return val; +} + +static uint32_t lsi_io_readl(void *opaque, uint32_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + val |= lsi_reg_readb(s, addr + 2) << 16; + val |= lsi_reg_readb(s, addr + 3) << 24; + return val; +} + +static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + lsi_reg_writeb(s, addr & 0xff, val); +} + +static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); +} + +static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); + lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); + lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff); +} + +static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + LSIState *s = (LSIState *)pci_dev; + + DPRINTF("Mapping IO at %08x\n", addr); + + register_ioport_write(addr, 256, 1, lsi_io_writeb, s); + register_ioport_read(addr, 256, 1, lsi_io_readb, s); + register_ioport_write(addr, 256, 2, lsi_io_writew, s); + register_ioport_read(addr, 256, 2, lsi_io_readw, s); + register_ioport_write(addr, 256, 4, lsi_io_writel, s); + register_ioport_read(addr, 256, 4, lsi_io_readl, s); +} + +static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + LSIState *s = (LSIState *)pci_dev; + + DPRINTF("Mapping ram at %08x\n", addr); + s->script_ram_base = addr; + cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr); +} + +static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + LSIState *s = (LSIState *)pci_dev; + + DPRINTF("Mapping registers at %08x\n", addr); + cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr); +} + +void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) +{ + LSIState *s = (LSIState *)opaque; + + if (id < 0) { + for (id = 0; id < LSI_MAX_DEVS; id++) { + if (s->scsi_dev[id] == NULL) + break; + } + } + if (id >= LSI_MAX_DEVS) { + BADF("Bad Device ID %d\n", id); + return; + } + if (s->scsi_dev[id]) { + DPRINTF("Destroying device %d\n", id); + scsi_disk_destroy(s->scsi_dev[id]); + } + DPRINTF("Attaching block device %d\n", id); + s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s); +} + +void *lsi_scsi_init(PCIBus *bus, int devfn) +{ + LSIState *s; + + s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA", + sizeof(*s), devfn, NULL, NULL); + if (s == NULL) { + fprintf(stderr, "lsi-scsi: Failed to register PCI device\n"); + return NULL; + } + + s->pci_dev.config[0x00] = 0x00; + s->pci_dev.config[0x01] = 0x10; + s->pci_dev.config[0x02] = 0x12; + s->pci_dev.config[0x03] = 0x00; + s->pci_dev.config[0x0b] = 0x01; + s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ + + s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn, + lsi_mmio_writefn, s); + s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn, + lsi_ram_writefn, s); + + pci_register_io_region((struct PCIDevice *)s, 0, 256, + PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc); + pci_register_io_region((struct PCIDevice *)s, 1, 0x400, + PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); + pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, + PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); + + lsi_soft_reset(s); + + return s; +} + diff --git a/tools/ioemu/hw/m48t59.c b/tools/ioemu/hw/m48t59.c index 81e64e4418..daa1c524db 100644 --- a/tools/ioemu/hw/m48t59.c +++ b/tools/ioemu/hw/m48t59.c @@ -332,7 +332,10 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) tmp = fromBCD(val); if (tmp >= 0 && tmp <= 99) { get_time(NVRAM, &tm); - tm.tm_year = fromBCD(val); + if (NVRAM->type == 8) + tm.tm_year = fromBCD(val) + 68; // Base year is 1968 + else + tm.tm_year = fromBCD(val); set_time(NVRAM, &tm); } break; @@ -421,7 +424,10 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) case 0x1FFF: /* year */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_year); + if (NVRAM->type == 8) + retval = toBCD(tm.tm_year - 68); // Base year is 1968 + else + retval = toBCD(tm.tm_year); break; default: /* Check lock registers state */ diff --git a/tools/ioemu/hw/mips_r4k.c b/tools/ioemu/hw/mips_r4k.c index 0cb11683ae..22d742a2e3 100644 --- a/tools/ioemu/hw/mips_r4k.c +++ b/tools/ioemu/hw/mips_r4k.c @@ -60,7 +60,7 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count, next++; #if 0 if (logfile) { - fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", + fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", __func__, now, count, compare, next - now); } #endif @@ -214,14 +214,10 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, run. */ bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE); ret = load_image(buf, phys_ram_base + bios_offset); if (ret == BIOS_SIZE) { cpu_register_physical_memory((uint32_t)(0x1fc00000), BIOS_SIZE, bios_offset | IO_MEM_ROM); - env->PC = 0xBFC00000; - if (!kernel_filename) - return; } else { /* not fatal */ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", diff --git a/tools/ioemu/hw/ne2000.c b/tools/ioemu/hw/ne2000.c index 674d83e490..e23c6df069 100644 --- a/tools/ioemu/hw/ne2000.c +++ b/tools/ioemu/hw/ne2000.c @@ -206,7 +206,7 @@ static int ne2000_buffer_full(NE2000State *s) index = s->curpag << 8; boundary = s->boundary << 8; - if (index < boundary) + if (index <= boundary) avail = boundary - index; else avail = (s->stop - s->start) - (index - boundary); diff --git a/tools/ioemu/hw/pc.c b/tools/ioemu/hw/pc.c index d4e4b1b9ca..6bd7288b25 100644 --- a/tools/ioemu/hw/pc.c +++ b/tools/ioemu/hw/pc.c @@ -44,7 +44,6 @@ static PITState *pit; #ifndef CONFIG_DM static IOAPICState *ioapic; #endif /* !CONFIG_DM */ -static USBPort *usb_root_ports[2]; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -63,10 +62,19 @@ static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) } /* TSC handling */ - uint64_t cpu_get_tsc(CPUX86State *env) { - return qemu_get_clock(vm_clock); + /* Note: when using kqemu, it is more logical to return the host TSC + because kqemu does not trap the RDTSC instruction for + performance reasons */ +#if USE_KQEMU + if (env->kqemu_enabled) { + return cpu_get_real_ticks(); + } else +#endif + { + return cpu_get_ticks(); + } } #ifndef CONFIG_DM @@ -201,6 +209,8 @@ static void cmos_init(uint64_t ram_size, int boot_device, BlockDriverState **hd_ case 'a': case 'b': rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ + if (!fd_bootchk) + rtc_set_memory(s, 0x38, 0x01); /* disable signature check */ break; default: case 'c': @@ -272,10 +282,6 @@ static void cmos_init(uint64_t ram_size, int boot_device, BlockDriverState **hd_ } } rtc_set_memory(s, 0x39, val); - - /* Disable check of 0x55AA signature on the last two bytes of - first sector of disk. XXX: make it the default ? */ - // rtc_set_memory(s, 0x38, 1); } void ioport_set_a20(int enable) @@ -567,7 +573,7 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; /* PIIX4 acpi pci configuration space, func 3 */ -extern void pci_piix4_acpi_init(PCIBus *bus); +extern void pci_piix4_acpi_init(PCIBus *bus, int devfn); #ifdef HAS_AUDIO static void audio_init (PCIBus *pci_bus) @@ -630,6 +636,7 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, int bios_size, isa_bios_size; #endif /* !NOBIOS */ PCIBus *pci_bus; + int piix3_devfn = -1; CPUState *env; NICInfo *nd; @@ -774,7 +781,7 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, if (pci_enabled) { pci_bus = i440fx_init(); - piix3_init(pci_bus); + piix3_devfn = piix3_init(pci_bus); } else { pci_bus = NULL; } @@ -852,7 +859,7 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, } if (pci_enabled) { - pci_piix3_ide_init(pci_bus, bs_table); + pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1); } else { for(i = 0; i < 2; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], @@ -872,17 +879,39 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, /* using PIIX4 acpi model */ if (pci_enabled && acpi_enabled) - pci_piix4_acpi_init(pci_bus); + pci_piix4_acpi_init(pci_bus, piix3_devfn + 3); if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, usb_root_ports); - usb_attach(usb_root_ports[0], vm_usb_hub); + usb_uhci_init(pci_bus, piix3_devfn + 2); } + if (pci_enabled && acpi_enabled && 0) { + piix4_pm_init(pci_bus, piix3_devfn + 3); + } + +#if 0 + /* ??? Need to figure out some way for the user to + specify SCSI devices. */ + if (pci_enabled) { + void *scsi; + BlockDriverState *bdrv; + + scsi = lsi_scsi_init(pci_bus, -1); + bdrv = bdrv_new("scsidisk"); + bdrv_open(bdrv, "scsi_disk.img", 0); + lsi_scsi_attach(scsi, bdrv, -1); + bdrv = bdrv_new("scsicd"); + bdrv_open(bdrv, "scsi_cd.iso", 0); + bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + lsi_scsi_attach(scsi, bdrv, -1); + } +#endif /* must be done after all PCI devices are instanciated */ /* XXX: should be done in the Bochs BIOS */ if (pci_enabled) { pci_bios_init(); + if (acpi_enabled) + acpi_bios_init(); } } diff --git a/tools/ioemu/hw/pci.c b/tools/ioemu/hw/pci.c index 096d0d1e05..f58f6fd60c 100644 --- a/tools/ioemu/hw/pci.c +++ b/tools/ioemu/hw/pci.c @@ -25,25 +25,10 @@ //#define DEBUG_PCI -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* just used for simpler irq handling. */ -#define PCI_DEVICES_MAX 64 -#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) - struct PCIBus { int bus_num; int devfn_min; - void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level); + pci_set_irq_fn set_irq; uint32_t config_reg; /* XXX: suppress */ /* low level pic */ SetIRQFunc *low_set_irq; @@ -53,17 +38,24 @@ struct PCIBus { target_phys_addr_t pci_mem_base; static int pci_irq_index; -static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; static PCIBus *first_bus; -static PCIBus *pci_register_bus(void) +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min) { PCIBus *bus; bus = qemu_mallocz(sizeof(PCIBus)); + bus->set_irq = set_irq; + bus->irq_opaque = pic; + bus->devfn_min = devfn_min; first_bus = bus; return bus; } +int pci_bus_num(PCIBus *s) +{ + return s->bus_num; +} + void generic_pci_save(QEMUFile* f, void *opaque) { PCIDevice* s=(PCIDevice*)opaque; @@ -141,16 +133,9 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); } -static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) +target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) { - PCIBus *s = opaque; - s->config_reg = val; -} - -static uint32_t pci_addr_readl(void* opaque, uint32_t addr) -{ - PCIBus *s = opaque; - return s->config_reg; + return addr + pci_mem_base; } static void pci_update_mappings(PCIDevice *d) @@ -218,7 +203,7 @@ static void pci_update_mappings(PCIDevice *d) isa_unassign_ioport(r->addr, r->size); } } else { - cpu_register_physical_memory(r->addr + pci_mem_base, + cpu_register_physical_memory(pci_to_cpu_addr(r->addr), r->size, IO_MEM_UNASSIGNED); } @@ -346,8 +331,7 @@ void pci_default_write_config(PCIDevice *d, } } -static void pci_data_write(void *opaque, uint32_t addr, - uint32_t val, int len) +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) { PCIBus *s = opaque; PCIDevice *pci_dev; @@ -355,18 +339,15 @@ static void pci_data_write(void *opaque, uint32_t addr, #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", - s->config_reg, val, len); + addr, val, len); #endif - if (!(s->config_reg & (1 << 31))) { - return; - } - bus_num = (s->config_reg >> 16) & 0xff; + bus_num = (addr >> 16) & 0xff; if (bus_num != 0) return; - pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) return; - config_addr = (s->config_reg & 0xfc) | (addr & 3); + config_addr = addr & 0xff; #if defined(DEBUG_PCI) printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len); @@ -374,20 +355,17 @@ static void pci_data_write(void *opaque, uint32_t addr, pci_dev->config_write(pci_dev, config_addr, val, len); } -static uint32_t pci_data_read(void *opaque, uint32_t addr, - int len) +uint32_t pci_data_read(void *opaque, uint32_t addr, int len) { PCIBus *s = opaque; PCIDevice *pci_dev; int config_addr, bus_num; uint32_t val; - if (!(s->config_reg & (1 << 31))) - goto fail; - bus_num = (s->config_reg >> 16) & 0xff; + bus_num = (addr >> 16) & 0xff; if (bus_num != 0) goto fail; - pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) { fail: switch(len) { @@ -404,7 +382,7 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr, } goto the_end; } - config_addr = (s->config_reg & 0xfc) | (addr & 3); + config_addr = addr & 0xff; val = pci_dev->config_read(pci_dev, config_addr, len); #if defined(DEBUG_PCI) printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", @@ -413,1133 +391,11 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr, the_end: #if defined(DEBUG_PCI) && 0 printf("pci_data_read: addr=%08x val=%08x len=%d\n", - s->config_reg, val, len); + addr, val, len); #endif return val; } -static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 1); -} - -static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 2); -} - -static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 4); -} - -static uint32_t pci_data_readb(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 1); -} - -static uint32_t pci_data_readw(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 2); -} - -static uint32_t pci_data_readl(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 4); -} - -/* i440FX PCI bridge */ - -static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level); - -PCIBus *i440fx_init(void) -{ - PCIBus *s; - PCIDevice *d; - - s = pci_register_bus(); - s->set_irq = piix3_set_irq; - - register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - - d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0, - NULL, NULL); - - d->config[0x00] = 0x86; // vendor_id - d->config[0x01] = 0x80; - d->config[0x02] = 0x37; // device_id - d->config[0x03] = 0x12; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x00; // class_sub = host2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - return s; -} - -/* PIIX3 PCI to ISA bridge */ - -typedef struct PIIX3State { - PCIDevice dev; -} PIIX3State; - -PIIX3State *piix3_state; - -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (irq_num + slot_addend) & 3; -} - -static inline int get_pci_irq_level(int irq_num) -{ - int pic_level; -#if (PCI_IRQ_WORDS == 2) - pic_level = ((pci_irq_levels[irq_num][0] | - pci_irq_levels[irq_num][1]) != 0); -#else - { - int i; - pic_level = 0; - for(i = 0; i < PCI_IRQ_WORDS; i++) { - if (pci_irq_levels[irq_num][i]) { - pic_level = 1; - break; - } - } - } -#endif - return pic_level; -} - -static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level) -{ - int irq_index, shift, pic_irq, pic_level; - uint32_t *p; - - irq_num = pci_slot_get_pirq(pci_dev, irq_num); - irq_index = pci_dev->irq_index; - p = &pci_irq_levels[irq_num][irq_index >> 5]; - shift = (irq_index & 0x1f); - *p = (*p & ~(1 << shift)) | (level << shift); - - /* now we change the pic irq level according to the piix irq mappings */ - /* XXX: optimize */ - pic_irq = piix3_state->dev.config[0x60 + irq_num]; - if (pic_irq < 16) { - /* the pic level is the logical OR of all the PCI irqs mapped - to it */ - pic_level = 0; - if (pic_irq == piix3_state->dev.config[0x60]) - pic_level |= get_pci_irq_level(0); - if (pic_irq == piix3_state->dev.config[0x61]) - pic_level |= get_pci_irq_level(1); - if (pic_irq == piix3_state->dev.config[0x62]) - pic_level |= get_pci_irq_level(2); - if (pic_irq == piix3_state->dev.config[0x63]) - pic_level |= get_pci_irq_level(3); - pic_set_irq(pic_irq, pic_level); - } -} - -static void piix3_reset(PIIX3State *d) -{ - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; // master, memory and I/O - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; // PCI_status_devsel_medium - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; -} - -void piix3_init(PCIBus *bus) -{ - PIIX3State *d; - uint8_t *pci_conf; - - d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State), - -1, NULL, NULL); - register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); - - piix3_state = d; - pci_conf = d->dev.config; - - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - pci_conf[0x03] = 0x70; - pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA - pci_conf[0x0b] = 0x06; // class_base = PCI_bridge - pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic - - piix3_reset(d); -} - -/* PREP pci init */ - -static inline void set_config(PCIBus *s, target_phys_addr_t addr) -{ - int devfn, i; - - for(i = 0; i < 11; i++) { - if ((addr & (1 << (11 + i))) != 0) - break; - } - devfn = ((addr >> 8) & 7) | (i << 3); - s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); -} - -static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); - pci_data_write(s, addr, val, 1); -} - -static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr, val, 2); -} - -static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr, val, 4); -} - -static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 1); - return val; -} - -static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { - &PPC_PCIIO_writeb, - &PPC_PCIIO_writew, - &PPC_PCIIO_writel, -}; - -static CPUReadMemoryFunc *PPC_PCIIO_read[] = { - &PPC_PCIIO_readb, - &PPC_PCIIO_readw, - &PPC_PCIIO_readl, -}; - -static void prep_set_irq(PCIDevice *d, int irq_num, int level) -{ - /* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ - pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_prep_init(void) -{ - PCIBus *s; - PCIDevice *d; - int PPC_io_memory; - - s = pci_register_bus(); - s->set_irq = prep_set_irq; - - register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, - PPC_PCIIO_write, s); - cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - - /* PCI host bridge */ - d = pci_register_device(s, "PREP Host Bridge - Motorola Raven", - sizeof(PCIDevice), 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id : Motorola - d->config[0x01] = 0x10; - d->config[0x02] = 0x01; // device_id : Raven - d->config[0x03] = 0x48; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - - return s; -} - - -/* Grackle PCI host */ -static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = val; -} - -static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = s->config_reg; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_grackle_config_write[] = { - &pci_grackle_config_writel, - &pci_grackle_config_writel, - &pci_grackle_config_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_config_read[] = { - &pci_grackle_config_readl, - &pci_grackle_config_readl, - &pci_grackle_config_readl, -}; - -static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr, val, 1); -} - -static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr, val, 2); -} - -static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr, val, 4); -} - -static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - val = pci_data_read(s, addr, 1); - return val; -} - -static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - val = pci_data_read(s, addr, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_grackle_write[] = { - &pci_grackle_writeb, - &pci_grackle_writew, - &pci_grackle_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_read[] = { - &pci_grackle_readb, - &pci_grackle_readw, - &pci_grackle_readl, -}; - -void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque) -{ - bus->low_set_irq = set_irq; - bus->irq_opaque = irq_opaque; -} - -/* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ -static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level) -{ - PCIBus *s = d->bus; - s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_grackle_init(uint32_t base) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, - pci_grackle_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, - pci_grackle_write, s); - cpu_register_physical_memory(base, 0x1000, pci_mem_config); - cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); - d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x02; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x01; - d->config[0x0a] = 0x00; // class_sub = host - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - - d->config[0x18] = 0x00; // primary_bus - d->config[0x19] = 0x01; // secondary_bus - d->config[0x1a] = 0x00; // subordinate_bus - d->config[0x1c] = 0x00; - d->config[0x1d] = 0x00; - - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x00; - d->config[0x22] = 0x01; // memory_limit - d->config[0x23] = 0x00; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x00; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x00; - -#if 0 - /* PCI2PCI bridge same values as PearPC - check this */ - d->config[0x00] = 0x11; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x01; // header_type - - d->config[0x18] = 0x0; // primary_bus - d->config[0x19] = 0x1; // secondary_bus - d->config[0x1a] = 0x1; // subordinate_bus - d->config[0x1c] = 0x10; // io_base - d->config[0x1d] = 0x20; // io_limit - - d->config[0x20] = 0x80; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x90; // memory_limit - d->config[0x23] = 0x80; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x84; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x85; -#endif - return s; -} - -/* Uninorth PCI host (for all Mac99 and newer machines */ -static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - int i; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } -#if 0 - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -#else - s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); -#endif -} - -static uint32_t pci_unin_main_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_config_read[] = { - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, -}; - -static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr & 7, val, 1); -} - -static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr & 7, val, 2); -} - -static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr & 7, val, 4); -} - -static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 1); - - return val; -} - -static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - - return val; -} - -static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_write[] = { - &pci_unin_main_writeb, - &pci_unin_main_writew, - &pci_unin_main_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_read[] = { - &pci_unin_main_readb, - &pci_unin_main_readw, - &pci_unin_main_readl, -}; - -#if 0 - -static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = 0x80000000 | (val & ~0x00000001); -} - -static uint32_t pci_unin_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = (s->config_reg | 0x00000001) & ~0x80000000; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_config_write[] = { - &pci_unin_config_writel, - &pci_unin_config_writel, - &pci_unin_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_config_read[] = { - &pci_unin_config_readl, - &pci_unin_config_readl, - &pci_unin_config_readl, -}; - -static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr & 3, val, 1); -} - -static void pci_unin_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr & 3, val, 2); -} - -static void pci_unin_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr & 3, val, 4); -} - -static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 1); - - return val; -} - -static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - - return val; -} - -static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_write[] = { - &pci_unin_writeb, - &pci_unin_writew, - &pci_unin_writel, -}; - -static CPUReadMemoryFunc *pci_unin_read[] = { - &pci_unin_readb, - &pci_unin_readw, - &pci_unin_readl, -}; -#endif - -PCIBus *pci_pmac_init(void) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - /* Use values found on a real PowerMac */ - /* Uninorth main bus */ - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, - pci_unin_main_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, - pci_unin_main_write, s); - cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); - s->devfn_min = 11 << 3; - d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice), - 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1F; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - -#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly - /* pci-to-pci bridge */ - d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, - NULL, NULL); - d->config[0x00] = 0x11; // vendor_id : TI - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x05; // revision - d->config[0x0A] = 0x04; // class_sub = pci2pci - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x20; // latency_timer - d->config[0x0E] = 0x01; // header_type - - d->config[0x18] = 0x01; // primary_bus - d->config[0x19] = 0x02; // secondary_bus - d->config[0x1A] = 0x02; // subordinate_bus - d->config[0x1B] = 0x20; // secondary_latency_timer - d->config[0x1C] = 0x11; // io_base - d->config[0x1D] = 0x01; // io_limit - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x00; // memory_limit - d->config[0x23] = 0x80; - d->config[0x24] = 0x01; // prefetchable_memory_base - d->config[0x25] = 0x80; - d->config[0x26] = 0xF1; // prefectchable_memory_limit - d->config[0x27] = 0x7F; - // d->config[0x34] = 0xdc // capabilities_pointer -#endif -#if 0 // XXX: not needed for now - /* Uninorth AGP bus */ - s = &pci_bridge[1]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, - NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x20; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - // d->config[0x34] = 0x80; // capabilities_pointer -#endif - -#if 0 // XXX: not needed for now - /* Uninorth internal bus */ - s = &pci_bridge[2]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north internal", sizeof(PCIDevice), - 3, 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1E; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer -#endif - return s; -} - -/* Ultrasparc APB PCI host */ -static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - int i; - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -} - -static uint32_t pci_apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_config_write[] = { - &pci_apb_config_writel, - &pci_apb_config_writel, - &pci_apb_config_writel, -}; - -static CPUReadMemoryFunc *pci_apb_config_read[] = { - &pci_apb_config_readl, - &pci_apb_config_readl, - &pci_apb_config_readl, -}; - -static void apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - //PCIBus *s = opaque; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - break; - } -} - -static uint32_t apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - //PCIBus *s = opaque; - uint32_t val; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - val = 0; - break; - } - return val; -} - -static CPUWriteMemoryFunc *apb_config_write[] = { - &apb_config_writel, - &apb_config_writel, - &apb_config_writel, -}; - -static CPUReadMemoryFunc *apb_config_read[] = { - &apb_config_readl, - &apb_config_readl, - &apb_config_readl, -}; - -static void pci_apb_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 1); -} - -static void pci_apb_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 2); -} - -static void pci_apb_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 4); -} - -static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 1); - return val; -} - -static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 2); - return val; -} - -static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_write[] = { - &pci_apb_writeb, - &pci_apb_writew, - &pci_apb_writel, -}; - -static CPUReadMemoryFunc *pci_apb_read[] = { - &pci_apb_readb, - &pci_apb_readw, - &pci_apb_readl, -}; - -static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outb(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outw(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outl(NULL, addr & 0xffff, val); -} - -static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inb(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inw(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inl(NULL, addr & 0xffff); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_iowrite[] = { - &pci_apb_iowriteb, - &pci_apb_iowritew, - &pci_apb_iowritel, -}; - -static CPUReadMemoryFunc *pci_apb_ioread[] = { - &pci_apb_ioreadb, - &pci_apb_ioreadw, - &pci_apb_ioreadl, -}; - -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - - /* Ultrasparc APB main bus */ - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, - pci_apb_config_write, s); - apb_config = cpu_register_io_memory(0, apb_config_read, - apb_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_apb_read, - pci_apb_write, s); - pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, - pci_apb_iowrite, s); - - cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); - cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); - cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); - cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom - - d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), - -1, NULL, NULL); - d->config[0x00] = 0x8e; // vendor_id : Sun - d->config[0x01] = 0x10; - d->config[0x02] = 0x00; // device_id - d->config[0x03] = 0xa0; - d->config[0x04] = 0x06; // command = bus master, pci mem - d->config[0x05] = 0x00; - d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error - d->config[0x07] = 0x03; // status = medium devsel - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x00; // programming i/f - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - return s; -} - /***********************************************************/ /* generic PCI irq support */ @@ -1547,34 +403,46 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base) void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { PCIBus *bus = pci_dev->bus; - bus->set_irq(pci_dev, irq_num, level); + bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level); } /***********************************************************/ /* monitor info on PCI */ +typedef struct { + uint16_t class; + const char *desc; +} pci_class_desc; + +static pci_class_desc pci_class_descriptions[] = +{ + { 0x0101, "IDE controller"}, + { 0x0200, "Ethernet controller"}, + { 0x0300, "VGA controller"}, + { 0x0600, "Host bridge"}, + { 0x0601, "ISA bridge"}, + { 0x0604, "PCI bridge"}, + { 0x0c03, "USB controller"}, + { 0, NULL} +}; + static void pci_info_device(PCIDevice *d) { int i, class; PCIIORegion *r; + pci_class_desc *desc; term_printf(" Bus %2d, device %3d, function %d:\n", d->bus->bus_num, d->devfn >> 3, d->devfn & 7); class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); term_printf(" "); - switch(class) { - case 0x0101: - term_printf("IDE controller"); - break; - case 0x0200: - term_printf("Ethernet controller"); - break; - case 0x0300: - term_printf("VGA controller"); - break; - default: + desc = pci_class_descriptions; + while (desc->desc && class != desc->class) + desc++; + if (desc->desc) { + term_printf("%s", desc->desc); + } else { term_printf("Class %04x", class); - break; } term_printf(": PCI device %04x:%04x\n", le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), @@ -1598,7 +466,7 @@ static void pci_info_device(PCIDevice *d) } } -void pci_info(void) +void pci_for_each_device(void (*fn)(PCIDevice *d)) { PCIBus *bus = first_bus; PCIDevice *d; @@ -1608,253 +476,14 @@ void pci_info(void) for(devfn = 0; devfn < 256; devfn++) { d = bus->devices[devfn]; if (d) - pci_info_device(d); + fn(d); } } } -/***********************************************************/ -/* XXX: the following should be moved to the PC BIOS */ - -static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) +void pci_info(void) { - return cpu_inb(NULL, addr); -} - -static void isa_outb(uint32_t val, uint32_t addr) -{ - cpu_outb(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) -{ - return cpu_inw(NULL, addr); -} - -static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) -{ - cpu_outw(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) -{ - return cpu_inl(NULL, addr); -} - -static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) -{ - cpu_outl(NULL, addr, val); -} - -static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | addr; - pci_data_write(s, 0, val, 4); -} - -static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - pci_data_write(s, addr & 3, val, 2); -} - -static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - pci_data_write(s, addr & 3, val, 1); -} - -static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | addr; - return pci_data_read(s, 0, 4); -} - -static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - return pci_data_read(s, addr & 3, 2); -} - -static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - return pci_data_read(s, addr & 3, 1); -} - -static uint32_t pci_bios_io_addr; -static uint32_t pci_bios_mem_addr; -/* host irqs corresponding to PCI irqs A-D */ -static uint8_t pci_irqs[4] = { 10, 11, 10, 11 }; - -static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) -{ - PCIIORegion *r; - uint16_t cmd; - uint32_t ofs; - - if ( region_num == PCI_ROM_SLOT ) { - ofs = 0x30; - }else{ - ofs = 0x10 + region_num * 4; - } - - pci_config_writel(d, ofs, addr); - r = &d->io_regions[region_num]; - - /* enable memory mappings */ - cmd = pci_config_readw(d, PCI_COMMAND); - if ( region_num == PCI_ROM_SLOT ) - cmd |= 2; - else if (r->type & PCI_ADDRESS_SPACE_IO) - cmd |= 1; - else - cmd |= 2; - pci_config_writew(d, PCI_COMMAND, cmd); -} - -static void pci_bios_init_device(PCIDevice *d) -{ - int class; - PCIIORegion *r; - uint32_t *paddr; - int i, pin, pic_irq, vendor_id, device_id; - - class = pci_config_readw(d, PCI_CLASS_DEVICE); - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - switch(class) { - case 0x0101: - if (vendor_id == 0x8086 && device_id == 0x7010) { - /* PIIX3 IDE */ - pci_config_writew(d, 0x40, 0x8000); // enable IDE0 - pci_config_writew(d, 0x42, 0x8000); // enable IDE1 - goto default_map; - } else { - /* IDE: we map it as in ISA mode */ - pci_set_io_region_addr(d, 0, 0x1f0); - pci_set_io_region_addr(d, 1, 0x3f4); - pci_set_io_region_addr(d, 2, 0x170); - pci_set_io_region_addr(d, 3, 0x374); - } - break; - case 0x0680: - if (vendor_id == 0x8086 && device_id == 0x7113) { - // PIIX4 ACPI PM - pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 - pci_config_writew(d, 0x22, 0x0000); - goto default_map; - } - break; - - case 0x0300: - if (vendor_id != 0x1234) - goto default_map; - /* VGA: map frame buffer to default Bochs VBE address */ - pci_set_io_region_addr(d, 0, 0xE0000000); - break; - - case 0x0800: - /* PIC */ - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - if (vendor_id == 0x1014) { - /* IBM */ - if (device_id == 0x0046 || device_id == 0xFFFF) { - /* MPIC & MPIC2 */ - pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); - } - } - break; - case 0xff00: - if (vendor_id == 0x0106b && - (device_id == 0x0017 || device_id == 0x0022)) { - /* macio bridge */ - pci_set_io_region_addr(d, 0, 0x80800000); - } - break; - default: - default_map: - /* default memory mappings */ - for(i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (r->size) { - if (r->type & PCI_ADDRESS_SPACE_IO) - paddr = &pci_bios_io_addr; - else - paddr = &pci_bios_mem_addr; - *paddr = (*paddr + r->size - 1) & ~(r->size - 1); - pci_set_io_region_addr(d, i, *paddr); - *paddr += r->size; - } - } - break; - } - - /* map the interrupt */ - pin = pci_config_readb(d, PCI_INTERRUPT_PIN); - if (pin != 0) { - pin = pci_slot_get_pirq(d, pin - 1); - pic_irq = pci_irqs[pin]; - pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); - } - if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) { - // PIIX4 ACPI PM - pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 - pci_config_writew(d, 0x22, 0x0000); - pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9 - pci_config_writew(d, 0x3d, 0x0001); - } -} - -/* - * This function initializes the PCI devices as a normal PCI BIOS - * would do. It is provided just in case the BIOS has no support for - * PCI. - */ -void pci_bios_init(void) -{ - PCIBus *bus; - PCIDevice *d; - int devfn, i, irq; - uint8_t elcr[2]; - - pci_bios_io_addr = 0xc000; - pci_bios_mem_addr = 0xf0000000; - - /* activate IRQ mappings */ - elcr[0] = 0x00; - elcr[1] = 0x00; - for(i = 0; i < 4; i++) { - irq = pci_irqs[i]; - /* set to trigger level */ - elcr[irq >> 3] |= (1 << (irq & 7)); - /* activate irq remapping in PIIX */ - pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); - } - isa_outb(elcr[0], 0x4d0); - isa_outb(elcr[1], 0x4d1); - - bus = first_bus; - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - d = bus->devices[devfn]; - if (d) - pci_bios_init_device(d); - } - } + pci_for_each_device(pci_info_device); } /* Initialize a PCI NIC. */ @@ -1864,6 +493,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd) pci_ne2000_init(bus, nd); } else if (strcmp(nd->model, "rtl8139") == 0) { pci_rtl8139_init(bus, nd); + } else if (strcmp(nd->model, "pcnet") == 0) { + pci_pcnet_init(bus, nd); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); diff --git a/tools/ioemu/hw/pci_host.h b/tools/ioemu/hw/pci_host.h new file mode 100644 index 0000000000..708dae25e2 --- /dev/null +++ b/tools/ioemu/hw/pci_host.h @@ -0,0 +1,93 @@ +/* + * QEMU Common PCI Host bridge configuration data space access routines. + * + * Copyright (c) 2006 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. + */ + +/* Worker routines for a PCI host controller that uses an {address,data} + register pair to access PCI configuration space. */ + +typedef struct { + uint32_t config_reg; + PCIBus *bus; +} PCIHostState; + +static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1); +} + +static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2); +} + +static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg, val, 4); +} + +static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr) +{ + PCIHostState *s = opaque; + if (!(s->config_reg & (1 << 31))) + return 0xff; + return pci_data_read(s->bus, s->config_reg | (addr & 3), 1); +} + +static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr) +{ + PCIHostState *s = opaque; + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr) +{ + PCIHostState *s = opaque; + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffffffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + diff --git a/tools/ioemu/hw/pcnet.c b/tools/ioemu/hw/pcnet.c new file mode 100644 index 0000000000..0845cdc3ee --- /dev/null +++ b/tools/ioemu/hw/pcnet.c @@ -0,0 +1,1789 @@ +/* + * QEMU AMD PC-Net II (Am79C970A) emulation + * + * Copyright (c) 2004 Antony T Curtis + * + * 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. + */ + +/* This software was written to be compatible with the specification: + * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet + * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 + */ + +#include "vl.h" + +//#define PCNET_DEBUG +//#define PCNET_DEBUG_IO +//#define PCNET_DEBUG_BCR +//#define PCNET_DEBUG_CSR +//#define PCNET_DEBUG_RMD +//#define PCNET_DEBUG_TMD +//#define PCNET_DEBUG_MATCH + + +#define PCNET_IOPORT_SIZE 0x20 +#define PCNET_PNPMMIO_SIZE 0x20 + + +typedef struct PCNetState_st PCNetState; + +struct PCNetState_st { + PCIDevice dev; + VLANClientState *vc; + NICInfo *nd; + QEMUTimer *poll_timer; + int mmio_io_addr, rap, isr, lnkst; + target_phys_addr_t rdra, tdra; + uint8_t prom[16]; + uint16_t csr[128]; + uint16_t bcr[32]; + uint64_t timer; + int xmit_pos, recv_pos; + uint8_t buffer[4096]; + int tx_busy; +}; + +/* XXX: using bitfields for target memory structures is almost surely + not portable, so it should be suppressed ASAP */ +#ifdef __GNUC__ +#define PACKED_FIELD(A) A __attribute__ ((packed)) +#else +#error FixMe +#endif + +struct qemu_ether_header { + uint8_t ether_dhost[6]; + uint8_t ether_shost[6]; + uint16_t ether_type; +}; + +/* BUS CONFIGURATION REGISTERS */ +#define BCR_MSRDA 0 +#define BCR_MSWRA 1 +#define BCR_MC 2 +#define BCR_LNKST 4 +#define BCR_LED1 5 +#define BCR_LED2 6 +#define BCR_LED3 7 +#define BCR_FDC 9 +#define BCR_BSBC 18 +#define BCR_EECAS 19 +#define BCR_SWS 20 +#define BCR_PLAT 22 + +#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) +#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) +#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) + +#define CSR_INIT(S) !!(((S)->csr[0])&0x0001) +#define CSR_STRT(S) !!(((S)->csr[0])&0x0002) +#define CSR_STOP(S) !!(((S)->csr[0])&0x0004) +#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008) +#define CSR_TXON(S) !!(((S)->csr[0])&0x0010) +#define CSR_RXON(S) !!(((S)->csr[0])&0x0020) +#define CSR_INEA(S) !!(((S)->csr[0])&0x0040) +#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) +#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) +#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) +#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000) +#define CSR_SPND(S) !!(((S)->csr[5])&0x0001) +#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000) +#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000) +#define CSR_DRX(S) !!(((S)->csr[15])&0x0001) +#define CSR_DTX(S) !!(((S)->csr[15])&0x0002) +#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) +#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) +#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) +#define CSR_PROM(S) !!(((S)->csr[15])&0x8000) + +#define CSR_CRBC(S) ((S)->csr[40]) +#define CSR_CRST(S) ((S)->csr[41]) +#define CSR_CXBC(S) ((S)->csr[42]) +#define CSR_CXST(S) ((S)->csr[43]) +#define CSR_NRBC(S) ((S)->csr[44]) +#define CSR_NRST(S) ((S)->csr[45]) +#define CSR_POLL(S) ((S)->csr[46]) +#define CSR_PINT(S) ((S)->csr[47]) +#define CSR_RCVRC(S) ((S)->csr[72]) +#define CSR_XMTRC(S) ((S)->csr[74]) +#define CSR_RCVRL(S) ((S)->csr[76]) +#define CSR_XMTRL(S) ((S)->csr[78]) +#define CSR_MISSC(S) ((S)->csr[112]) + +#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) +#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) +#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) +#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) +#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) +#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) +#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) +#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) +#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) +#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) +#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) +#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) +#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) +#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) + +#define PHYSADDR(S,A) \ + (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) + +struct pcnet_initblk16 { + uint16_t mode; + uint16_t padr1; + uint16_t padr2; + uint16_t padr3; + uint16_t ladrf1; + uint16_t ladrf2; + uint16_t ladrf3; + uint16_t ladrf4; + unsigned PACKED_FIELD(rdra:24); + unsigned PACKED_FIELD(res1:5); + unsigned PACKED_FIELD(rlen:3); + unsigned PACKED_FIELD(tdra:24); + unsigned PACKED_FIELD(res2:5); + unsigned PACKED_FIELD(tlen:3); +}; + +struct pcnet_initblk32 { + uint16_t mode; + unsigned PACKED_FIELD(res1:4); + unsigned PACKED_FIELD(rlen:4); + unsigned PACKED_FIELD(res2:4); + unsigned PACKED_FIELD(tlen:4); + uint16_t padr1; + uint16_t padr2; + uint16_t padr3; + uint16_t _res; + uint16_t ladrf1; + uint16_t ladrf2; + uint16_t ladrf3; + uint16_t ladrf4; + uint32_t rdra; + uint32_t tdra; +}; + +struct pcnet_TMD { + struct { + unsigned tbadr:32; + } tmd0; + struct { + unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1); + unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1); + unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); + } tmd1; + struct { + unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12); + unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1); + unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1); + } tmd2; + struct { + unsigned res:32; + } tmd3; +}; + +struct pcnet_RMD { + struct { + unsigned rbadr:32; + } rmd0; + struct { + unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4); + unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1); + unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1); + unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); + } rmd1; + struct { + unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4); + unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8); + } rmd2; + struct { + unsigned res:32; + } rmd3; +}; + + +#define PRINT_TMD(T) printf( \ + "TMD0 : TBADR=0x%08x\n" \ + "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ + "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ + " BPE=%d, BCNT=%d\n" \ + "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ + "LCA=%d, RTR=%d,\n" \ + " TDR=%d, TRC=%d\n", \ + (T)->tmd0.tbadr, \ + (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \ + (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \ + (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \ + 4096-(T)->tmd1.bcnt, \ + (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\ + (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \ + (T)->tmd2.tdr, (T)->tmd2.trc) + +#define PRINT_RMD(R) printf( \ + "RMD0 : RBADR=0x%08x\n" \ + "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ + "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ + "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ + "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ + (R)->rmd0.rbadr, \ + (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \ + (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \ + (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \ + (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \ + (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \ + (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ + (R)->rmd2.zeros) + +static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t xda[4]; + cpu_physical_memory_read(addr, + (void *)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | + ((xda[1]&0x00ff) << 16); + ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| + ((xda[1] & 0xff00) << 16); + ((uint32_t *)tmd)[2] = + (xda[3] & 0xffff) << 16; + ((uint32_t *)tmd)[3] = 0; + } + else + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_read(addr, (void *)tmd, 16); + else { + uint32_t xda[4]; + cpu_physical_memory_read(addr, + (void *)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = xda[2]; + ((uint32_t *)tmd)[1] = xda[1]; + ((uint32_t *)tmd)[2] = xda[0]; + ((uint32_t *)tmd)[3] = xda[3]; + } +} + +static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t xda[4]; + xda[0] = ((uint32_t *)tmd)[0] & 0xffff; + xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | + ((((uint32_t *)tmd)[1]>>16)&0xff00); + xda[2] = ((uint32_t *)tmd)[1] & 0xffff; + xda[3] = ((uint32_t *)tmd)[2] >> 16; + cpu_physical_memory_write(addr, + (void *)&xda[0], sizeof(xda)); + } + else { + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_write(addr, (void *)tmd, 16); + else { + uint32_t xda[4]; + xda[0] = ((uint32_t *)tmd)[2]; + xda[1] = ((uint32_t *)tmd)[1]; + xda[2] = ((uint32_t *)tmd)[0]; + xda[3] = ((uint32_t *)tmd)[3]; + cpu_physical_memory_write(addr, + (void *)&xda[0], sizeof(xda)); + } + } +} + +static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t rda[4]; + cpu_physical_memory_read(addr, + (void *)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| + ((rda[1] & 0x00ff) << 16); + ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| + ((rda[1] & 0xff00) << 16); + ((uint32_t *)rmd)[2] = rda[3] & 0xffff; + ((uint32_t *)rmd)[3] = 0; + } + else + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_read(addr, (void *)rmd, 16); + else { + uint32_t rda[4]; + cpu_physical_memory_read(addr, + (void *)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = rda[2]; + ((uint32_t *)rmd)[1] = rda[1]; + ((uint32_t *)rmd)[2] = rda[0]; + ((uint32_t *)rmd)[3] = rda[3]; + } +} + +static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t rda[4]; \ + rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \ + rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\ + ((((uint32_t *)rmd)[1]>>16)&0xff00);\ + rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \ + rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \ + cpu_physical_memory_write(addr, \ + (void *)&rda[0], sizeof(rda)); \ + } + else { + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_write(addr, (void *)rmd, 16); + else { + uint32_t rda[4]; + rda[0] = ((uint32_t *)rmd)[2]; + rda[1] = ((uint32_t *)rmd)[1]; + rda[2] = ((uint32_t *)rmd)[0]; + rda[3] = ((uint32_t *)rmd)[3]; + cpu_physical_memory_write(addr, + (void *)&rda[0], sizeof(rda)); + } + } +} + + +#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR) + +#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR) + +#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR) + +#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) + +#if 1 + +#define CHECK_RMD(ADDR,RES) do { \ + struct pcnet_RMD rmd; \ + RMDLOAD(&rmd,(ADDR)); \ + (RES) |= (rmd.rmd1.ones != 15) \ + || (rmd.rmd2.zeros != 0); \ +} while (0) + +#define CHECK_TMD(ADDR,RES) do { \ + struct pcnet_TMD tmd; \ + TMDLOAD(&tmd,(ADDR)); \ + (RES) |= (tmd.tmd1.ones != 15); \ +} while (0) + +#else + +#define CHECK_RMD(ADDR,RES) do { \ + switch (BCR_SWSTYLE(s)) { \ + case 0x00: \ + do { \ + uint16_t rda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&rda[0], sizeof(rda)); \ + (RES) |= (rda[2] & 0xf000)!=0xf000; \ + (RES) |= (rda[3] & 0xf000)!=0x0000; \ + } while (0); \ + break; \ + case 0x01: \ + case 0x02: \ + do { \ + uint32_t rda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&rda[0], sizeof(rda)); \ + (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ + (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ + } while (0); \ + break; \ + case 0x03: \ + do { \ + uint32_t rda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&rda[0], sizeof(rda)); \ + (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ + (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ + } while (0); \ + break; \ + } \ +} while (0) + +#define CHECK_TMD(ADDR,RES) do { \ + switch (BCR_SWSTYLE(s)) { \ + case 0x00: \ + do { \ + uint16_t xda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&xda[0], sizeof(xda)); \ + (RES) |= (xda[2] & 0xf000)!=0xf000;\ + } while (0); \ + break; \ + case 0x01: \ + case 0x02: \ + case 0x03: \ + do { \ + uint32_t xda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&xda[0], sizeof(xda)); \ + (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ + } while (0); \ + break; \ + } \ +} while (0) + +#endif + +#define PRINT_PKTHDR(BUF) do { \ + struct qemu_ether_header *hdr = (void *)(BUF); \ + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ + "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ + "type=0x%04x (bcast=%d)\n", \ + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ + hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ + hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ + be16_to_cpu(hdr->ether_type), \ + !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \ +} while (0) + +#define MULTICAST_FILTER_LEN 8 + +static inline uint32_t lnc_mchash(const uint8_t *ether_addr) +{ +#define LNC_POLYNOMIAL 0xEDB88320UL + uint32_t crc = 0xFFFFFFFF; + int idx, bit; + uint8_t data; + + for (idx = 0; idx < 6; idx++) { + for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); + data >>= 1; + } + } + return crc; +#undef LNC_POLYNOMIAL +} + +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) + +/* generated using the AUTODIN II polynomial + * x^32 + x^26 + x^23 + x^22 + x^16 + + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 + */ +static const uint32_t crctab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) +{ + struct qemu_ether_header *hdr = (void *)buf; + uint8_t padr[6] = { + s->csr[12] & 0xff, s->csr[12] >> 8, + s->csr[13] & 0xff, s->csr[13] >> 8, + s->csr[14] & 0xff, s->csr[14] >> 8 + }; + int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6); +#ifdef PCNET_DEBUG_MATCH + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " + "padr=%02x:%02x:%02x:%02x:%02x:%02x\n", + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], + padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]); + printf("padr_match result=%d\n", result); +#endif + return result; +} + +static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) +{ + static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct qemu_ether_header *hdr = (void *)buf; + int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6); +#ifdef PCNET_DEBUG_MATCH + printf("padr_bcast result=%d\n", result); +#endif + return result; +} + +static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) +{ + struct qemu_ether_header *hdr = (void *)buf; + if ((*(hdr->ether_dhost)&0x01) && + ((uint64_t *)&s->csr[8])[0] != 0LL) { + uint8_t ladr[8] = { + s->csr[8] & 0xff, s->csr[8] >> 8, + s->csr[9] & 0xff, s->csr[9] >> 8, + s->csr[10] & 0xff, s->csr[10] >> 8, + s->csr[11] & 0xff, s->csr[11] >> 8 + }; + int index = lnc_mchash(hdr->ether_dhost) >> 26; + return !!(ladr[index >> 3] & (1 << (index & 7))); + } + return 0; +} + +static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) +{ + while (idx < 1) idx += CSR_RCVRL(s); + return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); +} + +static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time) +{ + int64_t next_time = current_time + + muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), + ticks_per_sec, 33000000L); + if (next_time <= current_time) + next_time = current_time + 1; + return next_time; +} + +static void pcnet_poll(PCNetState *s); +static void pcnet_poll_timer(void *opaque); + +static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); +static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); +static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); +static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); + +static void pcnet_s_reset(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_s_reset\n"); +#endif + + s->lnkst = 0x40; + s->rdra = 0; + s->tdra = 0; + s->rap = 0; + + s->bcr[BCR_BSBC] &= ~0x0080; + + s->csr[0] = 0x0004; + s->csr[3] = 0x0000; + s->csr[4] = 0x0115; + s->csr[5] = 0x0000; + s->csr[6] = 0x0000; + s->csr[8] = 0; + s->csr[9] = 0; + s->csr[10] = 0; + s->csr[11] = 0; + s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]); + s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]); + s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]); + s->csr[15] &= 0x21c4; + s->csr[72] = 1; + s->csr[74] = 1; + s->csr[76] = 1; + s->csr[78] = 1; + s->csr[80] = 0x1410; + s->csr[88] = 0x1003; + s->csr[89] = 0x0262; + s->csr[94] = 0x0000; + s->csr[100] = 0x0200; + s->csr[103] = 0x0105; + s->csr[103] = 0x0105; + s->csr[112] = 0x0000; + s->csr[114] = 0x0000; + s->csr[122] = 0x0000; + s->csr[124] = 0x0000; + + s->tx_busy = 0; +} + +static void pcnet_update_irq(PCNetState *s) +{ + int isr = 0; + s->csr[0] &= ~0x0080; + +#if 1 + if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || + (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || + (((s->csr[5]>>1) & s->csr[5]) & 0x0048)) +#else + if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ || + (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ || + (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ || + (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ || + (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ || + (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ || + (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ || + (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ || + (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ || + (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ || + (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ || + (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) +#endif + { + + isr = CSR_INEA(s); + s->csr[0] |= 0x0080; + } + + if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ + s->csr[4] &= ~0x0080; + s->csr[4] |= 0x0040; + s->csr[0] |= 0x0080; + isr = 1; +#ifdef PCNET_DEBUG + printf("pcnet user int\n"); +#endif + } + +#if 1 + if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) +#else + if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ || + (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ ) +#endif + { + isr = 1; + s->csr[0] |= 0x0080; + } + + if (isr != s->isr) { +#ifdef PCNET_DEBUG + printf("pcnet: INTA=%d\n", isr); +#endif + } + pci_set_irq(&s->dev, 0, isr); + s->isr = isr; +} + +static void pcnet_init(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); +#endif + +#define PCNET_INIT() do { \ + cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \ + (uint8_t *)&initblk, sizeof(initblk)); \ + s->csr[15] = le16_to_cpu(initblk.mode); \ + CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ + CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ + s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ + s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \ + s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \ + s->csr[10] = le16_to_cpu(initblk.ladrf3); \ + s->csr[11] = le16_to_cpu(initblk.ladrf4); \ + s->csr[12] = le16_to_cpu(initblk.padr1); \ + s->csr[13] = le16_to_cpu(initblk.padr2); \ + s->csr[14] = le16_to_cpu(initblk.padr3); \ + s->rdra = PHYSADDR(s,initblk.rdra); \ + s->tdra = PHYSADDR(s,initblk.tdra); \ +} while (0) + + if (BCR_SSIZE32(s)) { + struct pcnet_initblk32 initblk; + PCNET_INIT(); +#ifdef PCNET_DEBUG + printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", + initblk.rlen, initblk.tlen); +#endif + } else { + struct pcnet_initblk16 initblk; + PCNET_INIT(); +#ifdef PCNET_DEBUG + printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", + initblk.rlen, initblk.tlen); +#endif + } + +#undef PCNET_INIT + + CSR_RCVRC(s) = CSR_RCVRL(s); + CSR_XMTRC(s) = CSR_XMTRL(s); + +#ifdef PCNET_DEBUG + printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", + BCR_SSIZE32(s), + s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); +#endif + + s->csr[0] |= 0x0101; + s->csr[0] &= ~0x0004; /* clear STOP bit */ +} + +static void pcnet_start(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_start\n"); +#endif + + if (!CSR_DTX(s)) + s->csr[0] |= 0x0010; /* set TXON */ + + if (!CSR_DRX(s)) + s->csr[0] |= 0x0020; /* set RXON */ + + s->csr[0] &= ~0x0004; /* clear STOP bit */ + s->csr[0] |= 0x0002; +} + +static void pcnet_stop(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_stop\n"); +#endif + s->csr[0] &= ~0x7feb; + s->csr[0] |= 0x0014; + s->csr[4] &= ~0x02c2; + s->csr[5] &= ~0x0011; + pcnet_poll_timer(s); +} + +static void pcnet_rdte_poll(PCNetState *s) +{ + s->csr[28] = s->csr[29] = 0; + if (s->rdra) { + int bad = 0; +#if 1 + target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); + target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); + target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); +#else + target_phys_addr_t crda = s->rdra + + (CSR_RCVRL(s) - CSR_RCVRC(s)) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; + target_phys_addr_t nrda = s->rdra + + (CSR_RCVRL(s) - nrdc) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; + target_phys_addr_t nnrd = s->rdra + + (CSR_RCVRL(s) - nnrc) * + (BCR_SWSTYLE(s) ? 16 : 8 ); +#endif + + CHECK_RMD(PHYSADDR(s,crda), bad); + if (!bad) { + CHECK_RMD(PHYSADDR(s,nrda), bad); + if (bad || (nrda == crda)) nrda = 0; + CHECK_RMD(PHYSADDR(s,nnrd), bad); + if (bad || (nnrd == crda)) nnrd = 0; + + s->csr[28] = crda & 0xffff; + s->csr[29] = crda >> 16; + s->csr[26] = nrda & 0xffff; + s->csr[27] = nrda >> 16; + s->csr[36] = nnrd & 0xffff; + s->csr[37] = nnrd >> 16; +#ifdef PCNET_DEBUG + if (bad) { + printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n", + PHYSADDR(s,crda)); + } + } else { + printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda)); +#endif + } + } + + if (CSR_CRDA(s)) { + struct pcnet_RMD rmd; + RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); + CSR_CRBC(s) = rmd.rmd1.bcnt; + CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; +#ifdef PCNET_DEBUG_RMD_X + printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n", + PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), + ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); + PRINT_RMD(&rmd); +#endif + } else { + CSR_CRBC(s) = CSR_CRST(s) = 0; + } + + if (CSR_NRDA(s)) { + struct pcnet_RMD rmd; + RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); + CSR_NRBC(s) = rmd.rmd1.bcnt; + CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; + } else { + CSR_NRBC(s) = CSR_NRST(s) = 0; + } + +} + +static int pcnet_tdte_poll(PCNetState *s) +{ + s->csr[34] = s->csr[35] = 0; + if (s->tdra) { + target_phys_addr_t cxda = s->tdra + + (CSR_XMTRL(s) - CSR_XMTRC(s)) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + int bad = 0; + CHECK_TMD(PHYSADDR(s, cxda),bad); + if (!bad) { + if (CSR_CXDA(s) != cxda) { + s->csr[60] = s->csr[34]; + s->csr[61] = s->csr[35]; + s->csr[62] = CSR_CXBC(s); + s->csr[63] = CSR_CXST(s); + } + s->csr[34] = cxda & 0xffff; + s->csr[35] = cxda >> 16; +#ifdef PCNET_DEBUG + } else { + printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda)); +#endif + } + } + + if (CSR_CXDA(s)) { + struct pcnet_TMD tmd; + + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + + CSR_CXBC(s) = tmd.tmd1.bcnt; + CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; + } else { + CSR_CXBC(s) = CSR_CXST(s) = 0; + } + + return !!(CSR_CXST(s) & 0x8000); +} + +static int pcnet_can_receive(void *opaque) +{ + PCNetState *s = opaque; + if (CSR_STOP(s) || CSR_SPND(s)) + return 0; + + if (s->recv_pos > 0) + return 0; + + return sizeof(s->buffer)-16; +} + +#define MIN_BUF_SIZE 60 + +static void pcnet_receive(void *opaque, const uint8_t *buf, int size) +{ + PCNetState *s = opaque; + int is_padr = 0, is_bcast = 0, is_ladr = 0; + uint8_t buf1[60]; + + if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) + return; + +#ifdef PCNET_DEBUG + printf("pcnet_receive size=%d\n", size); +#endif + + /* if too small buffer, then expand it */ + if (size < MIN_BUF_SIZE) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, MIN_BUF_SIZE - size); + buf = buf1; + size = MIN_BUF_SIZE; + } + + if (CSR_PROM(s) + || (is_padr=padr_match(s, buf, size)) + || (is_bcast=padr_bcast(s, buf, size)) + || (is_ladr=ladr_match(s, buf, size))) { + + pcnet_rdte_poll(s); + + if (!(CSR_CRST(s) & 0x8000) && s->rdra) { + struct pcnet_RMD rmd; + int rcvrc = CSR_RCVRC(s)-1,i; + target_phys_addr_t nrda; + for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { + if (rcvrc <= 1) + rcvrc = CSR_RCVRL(s); + nrda = s->rdra + + (CSR_RCVRL(s) - rcvrc) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + RMDLOAD(&rmd, PHYSADDR(s,nrda)); + if (rmd.rmd1.own) { +#ifdef PCNET_DEBUG_RMD + printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", + rcvrc, CSR_RCVRC(s)); +#endif + CSR_RCVRC(s) = rcvrc; + pcnet_rdte_poll(s); + break; + } + } + } + + if (!(CSR_CRST(s) & 0x8000)) { +#ifdef PCNET_DEBUG_RMD + printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); +#endif + s->csr[0] |= 0x1000; /* Set MISS flag */ + CSR_MISSC(s)++; + } else { + uint8_t *src = &s->buffer[8]; + target_phys_addr_t crda = CSR_CRDA(s); + struct pcnet_RMD rmd; + int pktcount = 0; + + memcpy(src, buf, size); + +#if 1 + /* no need to compute the CRC */ + src[size] = 0; + src[size + 1] = 0; + src[size + 2] = 0; + src[size + 3] = 0; + size += 4; +#else + /* XXX: avoid CRC generation */ + if (!CSR_ASTRP_RCV(s)) { + uint32_t fcs = ~0; + uint8_t *p = src; + + while (size < 46) { + src[size++] = 0; + } + + while (p != &src[size]) { + CRC(fcs, *p++); + } + ((uint32_t *)&src[size])[0] = htonl(fcs); + size += 4; /* FCS at end of packet */ + } else size += 4; +#endif + +#ifdef PCNET_DEBUG_MATCH + PRINT_PKTHDR(buf); +#endif + + RMDLOAD(&rmd, PHYSADDR(s,crda)); + /*if (!CSR_LAPPEN(s))*/ + rmd.rmd1.stp = 1; + +#define PCNET_RECV_STORE() do { \ + int count = MIN(4096 - rmd.rmd1.bcnt,size); \ + target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ + cpu_physical_memory_write(rbadr, src, count); \ + src += count; size -= count; \ + rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ + RMDSTORE(&rmd, PHYSADDR(s,crda)); \ + pktcount++; \ +} while (0) + + PCNET_RECV_STORE(); + if ((size > 0) && CSR_NRDA(s)) { + target_phys_addr_t nrda = CSR_NRDA(s); + RMDLOAD(&rmd, PHYSADDR(s,nrda)); + if (rmd.rmd1.own) { + crda = nrda; + PCNET_RECV_STORE(); + if ((size > 0) && (nrda=CSR_NNRD(s))) { + RMDLOAD(&rmd, PHYSADDR(s,nrda)); + if (rmd.rmd1.own) { + crda = nrda; + PCNET_RECV_STORE(); + } + } + } + } + +#undef PCNET_RECV_STORE + + RMDLOAD(&rmd, PHYSADDR(s,crda)); + if (size == 0) { + rmd.rmd1.enp = 1; + rmd.rmd1.pam = !CSR_PROM(s) && is_padr; + rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; + rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; + } else { + rmd.rmd1.oflo = 1; + rmd.rmd1.buff = 1; + rmd.rmd1.err = 1; + } + RMDSTORE(&rmd, PHYSADDR(s,crda)); + s->csr[0] |= 0x0400; + +#ifdef PCNET_DEBUG + printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", + CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); +#endif +#ifdef PCNET_DEBUG_RMD + PRINT_RMD(&rmd); +#endif + + while (pktcount--) { + if (CSR_RCVRC(s) <= 1) + CSR_RCVRC(s) = CSR_RCVRL(s); + else + CSR_RCVRC(s)--; + } + + pcnet_rdte_poll(s); + + } + } + + pcnet_poll(s); + pcnet_update_irq(s); +} + +static void pcnet_transmit(PCNetState *s) +{ + target_phys_addr_t xmit_cxda = 0; + int count = CSR_XMTRL(s)-1; + s->xmit_pos = -1; + + if (!CSR_TXON(s)) { + s->csr[0] &= ~0x0008; + return; + } + + s->tx_busy = 1; + + txagain: + if (pcnet_tdte_poll(s)) { + struct pcnet_TMD tmd; + + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + +#ifdef PCNET_DEBUG_TMD + printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); + PRINT_TMD(&tmd); +#endif + if (tmd.tmd1.stp) { + s->xmit_pos = 0; + if (!tmd.tmd1.enp) { + cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), + s->buffer, 4096 - tmd.tmd1.bcnt); + s->xmit_pos += 4096 - tmd.tmd1.bcnt; + } + xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); + } + if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { + cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), + s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); + s->xmit_pos += 4096 - tmd.tmd1.bcnt; +#ifdef PCNET_DEBUG + printf("pcnet_transmit size=%d\n", s->xmit_pos); +#endif + if (CSR_LOOP(s)) + pcnet_receive(s, s->buffer, s->xmit_pos); + else + qemu_send_packet(s->vc, s->buffer, s->xmit_pos); + + s->csr[0] &= ~0x0008; /* clear TDMD */ + s->csr[4] |= 0x0004; /* set TXSTRT */ + s->xmit_pos = -1; + } + + tmd.tmd1.own = 0; + TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) + s->csr[0] |= 0x0200; /* set TINT */ + + if (CSR_XMTRC(s)<=1) + CSR_XMTRC(s) = CSR_XMTRL(s); + else + CSR_XMTRC(s)--; + if (count--) + goto txagain; + + } else + if (s->xmit_pos >= 0) { + struct pcnet_TMD tmd; + TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); + tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; + tmd.tmd1.own = 0; + TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); + s->csr[0] |= 0x0200; /* set TINT */ + if (!CSR_DXSUFLO(s)) { + s->csr[0] &= ~0x0010; + } else + if (count--) + goto txagain; + } + + s->tx_busy = 0; +} + +static void pcnet_poll(PCNetState *s) +{ + if (CSR_RXON(s)) { + pcnet_rdte_poll(s); + } + + if (CSR_TDMD(s) || + (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) + { + /* prevent recursion */ + if (s->tx_busy) + return; + + pcnet_transmit(s); + } +} + +static void pcnet_poll_timer(void *opaque) +{ + PCNetState *s = opaque; + + qemu_del_timer(s->poll_timer); + + if (CSR_TDMD(s)) { + pcnet_transmit(s); + } + + pcnet_update_irq(s); + + if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { + uint64_t now = qemu_get_clock(vm_clock) * 33; + if (!s->timer || !now) + s->timer = now; + else { + uint64_t t = now - s->timer + CSR_POLL(s); + if (t > 0xffffLL) { + pcnet_poll(s); + CSR_POLL(s) = CSR_PINT(s); + } else + CSR_POLL(s) = t; + } + qemu_mod_timer(s->poll_timer, + pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); + } +} + + +static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) +{ + uint16_t val = new_value; +#ifdef PCNET_DEBUG_CSR + printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val); +#endif + switch (rap) { + case 0: + s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */ + + s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048); + + val = (val & 0x007f) | (s->csr[0] & 0x7f00); + + /* IFF STOP, STRT and INIT are set, clear STRT and INIT */ + if ((val&7) == 7) + val &= ~3; + + if (!CSR_STOP(s) && (val & 4)) + pcnet_stop(s); + + if (!CSR_INIT(s) && (val & 1)) + pcnet_init(s); + + if (!CSR_STRT(s) && (val & 2)) + pcnet_start(s); + + if (CSR_TDMD(s)) + pcnet_transmit(s); + + return; + case 1: + case 2: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 18: /* CRBAL */ + case 19: /* CRBAU */ + case 20: /* CXBAL */ + case 21: /* CXBAU */ + case 22: /* NRBAU */ + case 23: /* NRBAU */ + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: /* CRBC */ + case 41: + case 42: /* CXBC */ + case 43: + case 44: + case 45: + case 46: /* POLL */ + case 47: /* POLLINT */ + case 72: + case 74: + case 76: /* RCVRL */ + case 78: /* XMTRL */ + case 112: + if (CSR_STOP(s) || CSR_SPND(s)) + break; + return; + case 3: + break; + case 4: + s->csr[4] &= ~(val & 0x026a); + val &= ~0x026a; val |= s->csr[4] & 0x026a; + break; + case 5: + s->csr[5] &= ~(val & 0x0a90); + val &= ~0x0a90; val |= s->csr[5] & 0x0a90; + break; + case 16: + pcnet_csr_writew(s,1,val); + return; + case 17: + pcnet_csr_writew(s,2,val); + return; + case 58: + pcnet_bcr_writew(s,BCR_SWS,val); + break; + default: + return; + } + s->csr[rap] = val; +} + +static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap) +{ + uint32_t val; + switch (rap) { + case 0: + pcnet_update_irq(s); + val = s->csr[0]; + val |= (val & 0x7800) ? 0x8000 : 0; + break; + case 16: + return pcnet_csr_readw(s,1); + case 17: + return pcnet_csr_readw(s,2); + case 58: + return pcnet_bcr_readw(s,BCR_SWS); + case 88: + val = s->csr[89]; + val <<= 16; + val |= s->csr[88]; + break; + default: + val = s->csr[rap]; + } +#ifdef PCNET_DEBUG_CSR + printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val); +#endif + return val; +} + +static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) +{ + rap &= 127; +#ifdef PCNET_DEBUG_BCR + printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val); +#endif + switch (rap) { + case BCR_SWS: + if (!(CSR_STOP(s) || CSR_SPND(s))) + return; + val &= ~0x0300; + switch (val & 0x00ff) { + case 0: + val |= 0x0200; + break; + case 1: + val |= 0x0100; + break; + case 2: + case 3: + val |= 0x0300; + break; + default: + printf("Bad SWSTYLE=0x%02x\n", val & 0xff); + val = 0x0200; + break; + } +#ifdef PCNET_DEBUG + printf("BCR_SWS=0x%04x\n", val); +#endif + case BCR_LNKST: + case BCR_LED1: + case BCR_LED2: + case BCR_LED3: + case BCR_MC: + case BCR_FDC: + case BCR_BSBC: + case BCR_EECAS: + case BCR_PLAT: + s->bcr[rap] = val; + break; + default: + break; + } +} + +static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) +{ + uint32_t val; + rap &= 127; + switch (rap) { + case BCR_LNKST: + case BCR_LED1: + case BCR_LED2: + case BCR_LED3: + val = s->bcr[rap] & ~0x8000; + val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0; + break; + default: + val = rap < 32 ? s->bcr[rap] : 0; + break; + } +#ifdef PCNET_DEBUG_BCR + printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val); +#endif + return val; +} + +static void pcnet_h_reset(PCNetState *s) +{ + int i; + uint16_t checksum; + + /* Initialize the PROM */ + + memcpy(s->prom, s->nd->macaddr, 6); + s->prom[12] = s->prom[13] = 0x00; + s->prom[14] = s->prom[15] = 0x57; + + for (i = 0,checksum = 0; i < 16; i++) + checksum += s->prom[i]; + *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); + + + s->bcr[BCR_MSRDA] = 0x0005; + s->bcr[BCR_MSWRA] = 0x0005; + s->bcr[BCR_MC ] = 0x0002; + s->bcr[BCR_LNKST] = 0x00c0; + s->bcr[BCR_LED1 ] = 0x0084; + s->bcr[BCR_LED2 ] = 0x0088; + s->bcr[BCR_LED3 ] = 0x0090; + s->bcr[BCR_FDC ] = 0x0000; + s->bcr[BCR_BSBC ] = 0x9001; + s->bcr[BCR_EECAS] = 0x0002; + s->bcr[BCR_SWS ] = 0x0200; + s->bcr[BCR_PLAT ] = 0xff06; + + pcnet_s_reset(s); +} + +static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; +#ifdef PCNET_DEBUG + printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); +#endif + /* Check APROMWE bit to enable write access */ + if (pcnet_bcr_readw(s,2) & 0x80) + s->prom[addr & 15] = val; +} + +static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = s->prom[addr &= 15]; +#ifdef PCNET_DEBUG + printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); +#endif + return val; +} + +static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; + pcnet_poll_timer(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val); +#endif + if (!BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + pcnet_csr_writew(s, s->rap, val); + break; + case 0x02: + s->rap = val & 0x7f; + break; + case 0x06: + pcnet_bcr_writew(s, s->rap, val); + break; + } + } + pcnet_update_irq(s); +} + +static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = -1; + pcnet_poll_timer(s); + if (!BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + val = pcnet_csr_readw(s, s->rap); + break; + case 0x02: + val = s->rap; + break; + case 0x04: + pcnet_s_reset(s); + val = 0; + break; + case 0x06: + val = pcnet_bcr_readw(s, s->rap); + break; + } + } + pcnet_update_irq(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff); +#endif + return val; +} + +static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; + pcnet_poll_timer(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val); +#endif + if (BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + pcnet_csr_writew(s, s->rap, val & 0xffff); + break; + case 0x04: + s->rap = val & 0x7f; + break; + case 0x0c: + pcnet_bcr_writew(s, s->rap, val & 0xffff); + break; + } + } else + if ((addr & 0x0f) == 0) { + /* switch device to dword i/o mode */ + pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); +#ifdef PCNET_DEBUG_IO + printf("device switched into dword i/o mode\n"); +#endif + } + pcnet_update_irq(s); +} + +static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = -1; + pcnet_poll_timer(s); + if (BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + val = pcnet_csr_readw(s, s->rap); + break; + case 0x04: + val = s->rap; + break; + case 0x08: + pcnet_s_reset(s); + val = 0; + break; + case 0x0c: + val = pcnet_bcr_readw(s, s->rap); + break; + } + } + pcnet_update_irq(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val); +#endif + return val; +} + +static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCNetState *d = (PCNetState *)pci_dev; + +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size); +#endif + + register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); + register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); + + register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); + register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); + register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); + register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); +} + +static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val); +#endif + if (!(addr & 0x10)) + pcnet_aprom_writeb(d, addr & 0x0f, val); +} + +static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val = -1; + if (!(addr & 0x10)) + val = pcnet_aprom_readb(d, addr & 0x0f); +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff); +#endif + return val; +} + +static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val); +#endif + if (addr & 0x10) + pcnet_ioport_writew(d, addr & 0x0f, val); + else { + addr &= 0x0f; + pcnet_aprom_writeb(d, addr, val & 0xff); + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + } +} + +static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val = -1; + if (addr & 0x10) + val = pcnet_ioport_readw(d, addr & 0x0f); + else { + addr &= 0x0f; + val = pcnet_aprom_readb(d, addr+1); + val <<= 8; + val |= pcnet_aprom_readb(d, addr); + } +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff); +#endif + return val; +} + +static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val); +#endif + if (addr & 0x10) + pcnet_ioport_writel(d, addr & 0x0f, val); + else { + addr &= 0x0f; + pcnet_aprom_writeb(d, addr, val & 0xff); + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); + pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); + } +} + +static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val; + if (addr & 0x10) + val = pcnet_ioport_readl(d, addr & 0x0f); + else { + addr &= 0x0f; + val = pcnet_aprom_readb(d, addr+3); + val <<= 8; + val |= pcnet_aprom_readb(d, addr+2); + val <<= 8; + val |= pcnet_aprom_readb(d, addr+1); + val <<= 8; + val |= pcnet_aprom_readb(d, addr); + } +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val); +#endif + return val; +} + + +static CPUWriteMemoryFunc *pcnet_mmio_write[] = { + (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, + (CPUWriteMemoryFunc *)&pcnet_mmio_writew, + (CPUWriteMemoryFunc *)&pcnet_mmio_writel +}; + +static CPUReadMemoryFunc *pcnet_mmio_read[] = { + (CPUReadMemoryFunc *)&pcnet_mmio_readb, + (CPUReadMemoryFunc *)&pcnet_mmio_readw, + (CPUReadMemoryFunc *)&pcnet_mmio_readl +}; + +static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCNetState *d = (PCNetState *)pci_dev; + +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); +#endif + + cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr); +} + +void pci_pcnet_init(PCIBus *bus, NICInfo *nd) +{ + PCNetState *d; + uint8_t *pci_conf; + +#if 0 + printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", + sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); +#endif + + d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), + -1, NULL, NULL); + + pci_conf = d->dev.config; + + *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); + *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); + *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); + *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); + pci_conf[0x08] = 0x10; + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0b] = 0x02; + pci_conf[0x0e] = 0x00; // header_type + + *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); + *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); + + pci_conf[0x3d] = 1; // interrupt pin 0 + pci_conf[0x3e] = 0x06; + pci_conf[0x3f] = 0xff; + + /* Handler for memory-mapped I/O */ + d->mmio_io_addr = + cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); + + pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, + PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); + + pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, + PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); + + d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); + + d->nd = nd; + + d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, + pcnet_can_receive, d); + + snprintf(d->vc->info_str, sizeof(d->vc->info_str), + "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + d->nd->macaddr[0], + d->nd->macaddr[1], + d->nd->macaddr[2], + d->nd->macaddr[3], + d->nd->macaddr[4], + d->nd->macaddr[5]); + + pcnet_h_reset(d); +} diff --git a/tools/ioemu/hw/pcspk.c b/tools/ioemu/hw/pcspk.c index 2e30662a25..0d52b31b45 100644 --- a/tools/ioemu/hw/pcspk.c +++ b/tools/ioemu/hw/pcspk.c @@ -95,7 +95,7 @@ static void pcspk_callback(void *opaque, int free) int pcspk_audio_init(AudioState *audio) { PCSpkState *s = &pcspk_state; - audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8}; + audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; if (!audio) { AUD_log(s_spk, "No audio state\n"); @@ -103,7 +103,7 @@ int pcspk_audio_init(AudioState *audio) } AUD_register_card(audio, s_spk, &s->card); - s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 0); + s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as); if (!s->voice) { AUD_log(s_spk, "Could not open voice\n"); return -1; diff --git a/tools/ioemu/hw/pflash_cfi02.c b/tools/ioemu/hw/pflash_cfi02.c new file mode 100644 index 0000000000..ee2f63a1a0 --- /dev/null +++ b/tools/ioemu/hw/pflash_cfi02.c @@ -0,0 +1,624 @@ +/* + * CFI parallel flash with AMD command set emulation + * + * Copyright (c) 2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * For now, this code can emulate flashes of 1, 2 or 4 bytes width. + * Supported commands/modes are: + * - flash read + * - flash write + * - flash ID read + * - sector erase + * - chip erase + * - unlock bypass command + * - CFI queries + * + * It does not support flash interleaving. + * It does not implement boot blocs with reduced size + * It does not implement software data protection as found in many real chips + * It does not implement erase suspend/resume commands + * It does not implement multiple sectors erase + */ + +#include "vl.h" + +//#define PFLASH_DEBUG +#ifdef PFLASH_DEBUG +#define DPRINTF(fmt, args...) \ +do { \ + printf("PFLASH: " fmt , ##args); \ +} while (0) +#else +#define DPRINTF(fmt, args...) do { } while (0) +#endif + +struct pflash_t { + BlockDriverState *bs; + target_ulong base; + target_ulong sector_len; + target_ulong total_len; + int width; + int wcycle; /* if 0, the flash is read normally */ + int bypass; + int ro; + uint8_t cmd; + uint8_t status; + uint16_t ident[4]; + uint8_t cfi_len; + uint8_t cfi_table[0x52]; + QEMUTimer *timer; + ram_addr_t off; + int fl_mem; + void *storage; +}; + +static void pflash_timer (void *opaque) +{ + pflash_t *pfl = opaque; + + DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); + /* Reset flash */ + pfl->status ^= 0x80; + if (pfl->bypass) { + pfl->wcycle = 2; + } else { + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); + pfl->wcycle = 0; + } + pfl->cmd = 0; +} + +static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) +{ + target_ulong boff; + uint32_t ret; + uint8_t *p; + + DPRINTF("%s: offset %08x\n", __func__, offset); + ret = -1; + offset -= pfl->base; + boff = offset & 0xFF; + if (pfl->width == 2) + boff = boff >> 1; + else if (pfl->width == 4) + boff = boff >> 2; + switch (pfl->cmd) { + default: + /* This should never happen : reset state & treat it as a read*/ + DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); + pfl->wcycle = 0; + pfl->cmd = 0; + case 0x80: + /* We accept reads during second unlock sequence... */ + case 0x00: + flash_read: + /* Flash area read */ + p = pfl->storage; + switch (width) { + case 1: + ret = p[offset]; +// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret); + break; + case 2: +#if defined(TARGET_WORDS_BIGENDIAN) + ret = p[offset] << 8; + ret |= p[offset + 1]; +#else + ret = p[offset]; + ret |= p[offset + 1] << 8; +#endif +// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret); + break; + case 4: +#if defined(TARGET_WORDS_BIGENDIAN) + ret = p[offset] << 24; + ret |= p[offset + 1] << 16; + ret |= p[offset + 2] << 8; + ret |= p[offset + 3]; +#else + ret = p[offset]; + ret |= p[offset + 1] << 8; + ret |= p[offset + 1] << 8; + ret |= p[offset + 2] << 16; + ret |= p[offset + 3] << 24; +#endif +// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret); + break; + } + break; + case 0x90: + /* flash ID read */ + switch (boff) { + case 0x00: + case 0x01: + ret = pfl->ident[boff & 0x01]; + break; + case 0x02: + ret = 0x00; /* Pretend all sectors are unprotected */ + break; + case 0x0E: + case 0x0F: + if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1) + goto flash_read; + ret = pfl->ident[2 + (boff & 0x01)]; + break; + default: + goto flash_read; + } + DPRINTF("%s: ID %d %x\n", __func__, boff, ret); + break; + case 0xA0: + case 0x10: + case 0x30: + /* Status register read */ + ret = pfl->status; + DPRINTF("%s: status %x\n", __func__, ret); + /* Toggle bit 6 */ + pfl->status ^= 0x40; + break; + case 0x98: + /* CFI query mode */ + if (boff > pfl->cfi_len) + ret = 0; + else + ret = pfl->cfi_table[boff]; + break; + } + + return ret; +} + +/* update flash content on disk */ +static void pflash_update(pflash_t *pfl, int offset, + int size) +{ + int offset_end; + if (pfl->bs) { + offset_end = offset + size; + /* round to sectors */ + offset = offset >> 9; + offset_end = (offset_end + 511) >> 9; + bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), + offset_end - offset); + } +} + +static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, + int width) +{ + target_ulong boff; + uint8_t *p; + uint8_t cmd; + + /* WARNING: when the memory area is in ROMD mode, the offset is a + ram offset, not a physical address */ + if (pfl->wcycle == 0) + offset -= (target_ulong)(long)pfl->storage; + else + offset -= pfl->base; + + cmd = value; + DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width); + if (pfl->cmd != 0xA0 && cmd == 0xF0) { + DPRINTF("%s: flash reset asked (%02x %02x)\n", + __func__, pfl->cmd, cmd); + goto reset_flash; + } + /* Set the device in I/O access mode */ + cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); + boff = offset & (pfl->sector_len - 1); + if (pfl->width == 2) + boff = boff >> 1; + else if (pfl->width == 4) + boff = boff >> 2; + switch (pfl->wcycle) { + case 0: + /* We're in read mode */ + check_unlock0: + if (boff == 0x55 && cmd == 0x98) { + enter_CFI_mode: + /* Enter CFI query mode */ + pfl->wcycle = 7; + pfl->cmd = 0x98; + return; + } + if (boff != 0x555 || cmd != 0xAA) { + DPRINTF("%s: unlock0 failed %04x %02x %04x\n", + __func__, boff, cmd, 0x555); + goto reset_flash; + } + DPRINTF("%s: unlock sequence started\n", __func__); + break; + case 1: + /* We started an unlock sequence */ + check_unlock1: + if (boff != 0x2AA || cmd != 0x55) { + DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd); + goto reset_flash; + } + DPRINTF("%s: unlock sequence done\n", __func__); + break; + case 2: + /* We finished an unlock sequence */ + if (!pfl->bypass && boff != 0x555) { + DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd); + goto reset_flash; + } + switch (cmd) { + case 0x20: + pfl->bypass = 1; + goto do_bypass; + case 0x80: + case 0x90: + case 0xA0: + pfl->cmd = cmd; + DPRINTF("%s: starting command %02x\n", __func__, cmd); + break; + default: + DPRINTF("%s: unknown command %02x\n", __func__, cmd); + goto reset_flash; + } + break; + case 3: + switch (pfl->cmd) { + case 0x80: + /* We need another unlock sequence */ + goto check_unlock0; + case 0xA0: + DPRINTF("%s: write data offset %08x %08x %d\n", + __func__, offset, value, width); + p = pfl->storage; + switch (width) { + case 1: + p[offset] &= value; + pflash_update(pfl, offset, 1); + break; + case 2: +#if defined(TARGET_WORDS_BIGENDIAN) + p[offset] &= value >> 8; + p[offset + 1] &= value; +#else + p[offset] &= value; + p[offset + 1] &= value >> 8; +#endif + pflash_update(pfl, offset, 2); + break; + case 4: +#if defined(TARGET_WORDS_BIGENDIAN) + p[offset] &= value >> 24; + p[offset + 1] &= value >> 16; + p[offset + 2] &= value >> 8; + p[offset + 3] &= value; +#else + p[offset] &= value; + p[offset + 1] &= value >> 8; + p[offset + 2] &= value >> 16; + p[offset + 3] &= value >> 24; +#endif + pflash_update(pfl, offset, 4); + break; + } + pfl->status = 0x00 | ~(value & 0x80); + /* Let's pretend write is immediate */ + if (pfl->bypass) + goto do_bypass; + goto reset_flash; + case 0x90: + if (pfl->bypass && cmd == 0x00) { + /* Unlock bypass reset */ + goto reset_flash; + } + /* We can enter CFI query mode from autoselect mode */ + if (boff == 0x55 && cmd == 0x98) + goto enter_CFI_mode; + /* No break here */ + default: + DPRINTF("%s: invalid write for command %02x\n", + __func__, pfl->cmd); + goto reset_flash; + } + case 4: + switch (pfl->cmd) { + case 0xA0: + /* Ignore writes while flash data write is occuring */ + /* As we suppose write is immediate, this should never happen */ + return; + case 0x80: + goto check_unlock1; + default: + /* Should never happen */ + DPRINTF("%s: invalid command state %02x (wc 4)\n", + __func__, pfl->cmd); + goto reset_flash; + } + break; + case 5: + switch (cmd) { + case 0x10: + if (boff != 0x555) { + DPRINTF("%s: chip erase: invalid address %04x\n", + __func__, offset); + goto reset_flash; + } + /* Chip erase */ + DPRINTF("%s: start chip erase\n", __func__); + memset(pfl->storage, 0xFF, pfl->total_len); + pfl->status = 0x00; + pflash_update(pfl, 0, pfl->total_len); + /* Let's wait 5 seconds before chip erase is done */ + qemu_mod_timer(pfl->timer, + qemu_get_clock(vm_clock) + (ticks_per_sec * 5)); + break; + case 0x30: + /* Sector erase */ + p = pfl->storage; + offset &= ~(pfl->sector_len - 1); + DPRINTF("%s: start sector erase at %08x\n", __func__, offset); + memset(p + offset, 0xFF, pfl->sector_len); + pflash_update(pfl, offset, pfl->sector_len); + pfl->status = 0x00; + /* Let's wait 1/2 second before sector erase is done */ + qemu_mod_timer(pfl->timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 2)); + break; + default: + DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd); + goto reset_flash; + } + pfl->cmd = cmd; + break; + case 6: + switch (pfl->cmd) { + case 0x10: + /* Ignore writes during chip erase */ + return; + case 0x30: + /* Ignore writes during sector erase */ + return; + default: + /* Should never happen */ + DPRINTF("%s: invalid command state %02x (wc 6)\n", + __func__, pfl->cmd); + goto reset_flash; + } + break; + case 7: /* Special value for CFI queries */ + DPRINTF("%s: invalid write in CFI query mode\n", __func__); + goto reset_flash; + default: + /* Should never happen */ + DPRINTF("%s: invalid write state (wc 7)\n", __func__); + goto reset_flash; + } + pfl->wcycle++; + + return; + + /* Reset flash */ + reset_flash: + if (pfl->wcycle != 0) { + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); + } + pfl->bypass = 0; + pfl->wcycle = 0; + pfl->cmd = 0; + return; + + do_bypass: + pfl->wcycle = 2; + pfl->cmd = 0; + return; +} + + +static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr) +{ + return pflash_read(opaque, addr, 1); +} + +static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr) +{ + pflash_t *pfl = opaque; + + return pflash_read(pfl, addr, 2); +} + +static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr) +{ + pflash_t *pfl = opaque; + + return pflash_read(pfl, addr, 4); +} + +static void pflash_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_write(opaque, addr, value, 1); +} + +static void pflash_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_t *pfl = opaque; + + pflash_write(pfl, addr, value, 2); +} + +static void pflash_writel (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_t *pfl = opaque; + + pflash_write(pfl, addr, value, 4); +} + +static CPUWriteMemoryFunc *pflash_write_ops[] = { + &pflash_writeb, + &pflash_writew, + &pflash_writel, +}; + +static CPUReadMemoryFunc *pflash_read_ops[] = { + &pflash_readb, + &pflash_readw, + &pflash_readl, +}; + +/* Count trailing zeroes of a 32 bits quantity */ +static int ctz32 (uint32_t n) +{ + int ret; + + ret = 0; + if (!(n & 0xFFFF)) { + ret += 16; + n = n >> 16; + } + if (!(n & 0xFF)) { + ret += 8; + n = n >> 8; + } + if (!(n & 0xF)) { + ret += 4; + n = n >> 4; + } + if (!(n & 0x3)) { + ret += 2; + n = n >> 2; + } + if (!(n & 0x1)) { + ret++; + n = n >> 1; + } +#if 0 /* This is not necessary as n is never 0 */ + if (!n) + ret++; +#endif + + return ret; +} + +pflash_t *pflash_register (target_ulong base, ram_addr_t off, + BlockDriverState *bs, + target_ulong sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3) +{ + pflash_t *pfl; + target_long total_len; + + total_len = sector_len * nb_blocs; + /* XXX: to be fixed */ + if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && + total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024)) + return NULL; + pfl = qemu_mallocz(sizeof(pflash_t)); + if (pfl == NULL) + return NULL; + pfl->storage = phys_ram_base + off; + pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl); + pfl->off = off; + cpu_register_physical_memory(base, total_len, + off | pfl->fl_mem | IO_MEM_ROMD); + pfl->bs = bs; + if (pfl->bs) { + /* read the initial flash content */ + bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + } +#if 0 /* XXX: there should be a bit to set up read-only, + * the same way the hardware does (with WP pin). + */ + pfl->ro = 1; +#else + pfl->ro = 0; +#endif + pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl); + pfl->base = base; + pfl->sector_len = sector_len; + pfl->total_len = total_len; + pfl->width = width; + pfl->wcycle = 0; + pfl->cmd = 0; + pfl->status = 0; + pfl->ident[0] = id0; + pfl->ident[1] = id1; + pfl->ident[2] = id2; + pfl->ident[3] = id3; + /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ + pfl->cfi_len = 0x52; + /* Standard "QRY" string */ + pfl->cfi_table[0x10] = 'Q'; + pfl->cfi_table[0x11] = 'R'; + pfl->cfi_table[0x12] = 'Y'; + /* Command set (AMD/Fujitsu) */ + pfl->cfi_table[0x13] = 0x02; + pfl->cfi_table[0x14] = 0x00; + /* Primary extended table address (none) */ + pfl->cfi_table[0x15] = 0x00; + pfl->cfi_table[0x16] = 0x00; + /* Alternate command set (none) */ + pfl->cfi_table[0x17] = 0x00; + pfl->cfi_table[0x18] = 0x00; + /* Alternate extended table (none) */ + pfl->cfi_table[0x19] = 0x00; + pfl->cfi_table[0x1A] = 0x00; + /* Vcc min */ + pfl->cfi_table[0x1B] = 0x27; + /* Vcc max */ + pfl->cfi_table[0x1C] = 0x36; + /* Vpp min (no Vpp pin) */ + pfl->cfi_table[0x1D] = 0x00; + /* Vpp max (no Vpp pin) */ + pfl->cfi_table[0x1E] = 0x00; + /* Reserved */ + pfl->cfi_table[0x1F] = 0x07; + /* Timeout for min size buffer write (16 µs) */ + pfl->cfi_table[0x20] = 0x04; + /* Typical timeout for block erase (512 ms) */ + pfl->cfi_table[0x21] = 0x09; + /* Typical timeout for full chip erase (4096 ms) */ + pfl->cfi_table[0x22] = 0x0C; + /* Reserved */ + pfl->cfi_table[0x23] = 0x01; + /* Max timeout for buffer write */ + pfl->cfi_table[0x24] = 0x04; + /* Max timeout for block erase */ + pfl->cfi_table[0x25] = 0x0A; + /* Max timeout for chip erase */ + pfl->cfi_table[0x26] = 0x0D; + /* Device size */ + pfl->cfi_table[0x27] = ctz32(total_len) + 1; + /* Flash device interface (8 & 16 bits) */ + pfl->cfi_table[0x28] = 0x02; + pfl->cfi_table[0x29] = 0x00; + /* Max number of bytes in multi-bytes write */ + pfl->cfi_table[0x2A] = 0x05; + pfl->cfi_table[0x2B] = 0x00; + /* Number of erase block regions (uniform) */ + pfl->cfi_table[0x2C] = 0x01; + /* Erase block region 1 */ + pfl->cfi_table[0x2D] = nb_blocs - 1; + pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8; + pfl->cfi_table[0x2F] = sector_len >> 8; + pfl->cfi_table[0x30] = sector_len >> 16; + + return pfl; +} diff --git a/tools/ioemu/hw/piix4acpi.c b/tools/ioemu/hw/piix4acpi.c index 1e272dbff0..2f4bdf61d5 100644 --- a/tools/ioemu/hw/piix4acpi.c +++ b/tools/ioemu/hw/piix4acpi.c @@ -375,7 +375,7 @@ static void acpi_map(PCIDevice *pci_dev, int region_num, } /* PIIX4 acpi pci configuration space, func 3 */ -void pci_piix4_acpi_init(PCIBus *bus) +void pci_piix4_acpi_init(PCIBus *bus, int devfn) { PCIAcpiState *d; uint8_t *pci_conf; @@ -383,7 +383,7 @@ void pci_piix4_acpi_init(PCIBus *bus) /* register a function 3 of PIIX4 */ d = (PCIAcpiState *)pci_register_device( bus, "PIIX4 ACPI", sizeof(PCIAcpiState), - ((PCIDevice *)piix3_state)->devfn + 3, NULL, NULL); + devfn, NULL, NULL); acpi_state = d; pci_conf = d->dev.config; diff --git a/tools/ioemu/hw/piix_pci.c b/tools/ioemu/hw/piix_pci.c new file mode 100644 index 0000000000..8af1186372 --- /dev/null +++ b/tools/ioemu/hw/piix_pci.c @@ -0,0 +1,435 @@ +/* + * QEMU i440FX/PIIX3 PCI Bridge Emulation + * + * Copyright (c) 2006 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" +typedef uint32_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState I440FXState; + +static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val) +{ + I440FXState *s = opaque; + s->config_reg = val; +} + +static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) +{ + I440FXState *s = opaque; + return s->config_reg; +} + +static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level); + +PCIBus *i440fx_init(void) +{ + PCIBus *b; + PCIDevice *d; + I440FXState *s; + + s = qemu_mallocz(sizeof(I440FXState)); + b = pci_register_bus(piix3_set_irq, NULL, 0); + s->bus = b; + + register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); + register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s); + + register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); + register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); + register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); + register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); + register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); + register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); + + d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, + NULL, NULL); + + d->config[0x00] = 0x86; // vendor_id + d->config[0x01] = 0x80; + d->config[0x02] = 0x37; // device_id + d->config[0x03] = 0x12; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x00; // class_sub = host2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x00; // header_type + return b; +} + +/* PIIX3 PCI to ISA bridge */ + +static PCIDevice *piix3_dev; + +/* just used for simpler irq handling. */ +#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) + +static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; + +/* return the global irq number corresponding to a given device irq + pin. We could also use the bus number to have a more precise + mapping. */ +static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3) - 1; + return (irq_num + slot_addend) & 3; +} + +static inline int get_pci_irq_level(int irq_num) +{ + int pic_level; +#if (PCI_IRQ_WORDS == 2) + pic_level = ((pci_irq_levels[irq_num][0] | + pci_irq_levels[irq_num][1]) != 0); +#else + { + int i; + pic_level = 0; + for(i = 0; i < PCI_IRQ_WORDS; i++) { + if (pci_irq_levels[irq_num][i]) { + pic_level = 1; + break; + } + } + } +#endif + return pic_level; +} + +static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level) +{ + int irq_index, shift, pic_irq, pic_level; + uint32_t *p; + + irq_num = pci_slot_get_pirq(pci_dev, irq_num); + irq_index = pci_dev->irq_index; + p = &pci_irq_levels[irq_num][irq_index >> 5]; + shift = (irq_index & 0x1f); + *p = (*p & ~(1 << shift)) | (level << shift); + + /* now we change the pic irq level according to the piix irq mappings */ + /* XXX: optimize */ + pic_irq = piix3_dev->config[0x60 + irq_num]; + if (pic_irq < 16) { + /* the pic level is the logical OR of all the PCI irqs mapped + to it */ + pic_level = 0; + if (pic_irq == piix3_dev->config[0x60]) + pic_level |= get_pci_irq_level(0); + if (pic_irq == piix3_dev->config[0x61]) + pic_level |= get_pci_irq_level(1); + if (pic_irq == piix3_dev->config[0x62]) + pic_level |= get_pci_irq_level(2); + if (pic_irq == piix3_dev->config[0x63]) + pic_level |= get_pci_irq_level(3); + pic_set_irq(pic_irq, pic_level); + } +} + +static void piix3_reset(PCIDevice *d) +{ + uint8_t *pci_conf = d->config; + + pci_conf[0x04] = 0x07; // master, memory and I/O + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; +} + +int piix3_init(PCIBus *bus) +{ + PCIDevice *d; + uint8_t *pci_conf; + + d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), + -1, NULL, NULL); + register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); + + piix3_dev = d; + pci_conf = d->config; + + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + pci_conf[0x03] = 0x70; + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + piix3_reset(d); + return d->devfn; +} + +/***********************************************************/ +/* XXX: the following should be moved to the PC BIOS */ + +static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) +{ + return cpu_inb(NULL, addr); +} + +static void isa_outb(uint32_t val, uint32_t addr) +{ + cpu_outb(NULL, addr, val); +} + +static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) +{ + return cpu_inw(NULL, addr); +} + +static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) +{ + cpu_outw(NULL, addr, val); +} + +static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) +{ + return cpu_inl(NULL, addr); +} + +static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) +{ + cpu_outl(NULL, addr, val); +} + +static uint32_t pci_bios_io_addr; +static uint32_t pci_bios_mem_addr; +/* host irqs corresponding to PCI irqs A-D */ +static uint8_t pci_irqs[4] = { 10, 11, 10, 11 }; + +static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + pci_data_write(s, addr, val, 4); +} + +static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + pci_data_write(s, addr, val, 2); +} + +static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + pci_data_write(s, addr, val, 1); +} + +static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + return pci_data_read(s, addr, 4); +} + +static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + return pci_data_read(s, addr, 2); +} + +static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + return pci_data_read(s, addr, 1); +} + +static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) +{ + PCIIORegion *r; + uint16_t cmd; + uint32_t ofs; + + if ( region_num == PCI_ROM_SLOT ) { + ofs = 0x30; + }else{ + ofs = 0x10 + region_num * 4; + } + + pci_config_writel(d, ofs, addr); + r = &d->io_regions[region_num]; + + /* enable memory mappings */ + cmd = pci_config_readw(d, PCI_COMMAND); + if ( region_num == PCI_ROM_SLOT ) + cmd |= 2; + else if (r->type & PCI_ADDRESS_SPACE_IO) + cmd |= 1; + else + cmd |= 2; + pci_config_writew(d, PCI_COMMAND, cmd); +} + +static void pci_bios_init_device(PCIDevice *d) +{ + int class; + PCIIORegion *r; + uint32_t *paddr; + int i, pin, pic_irq, vendor_id, device_id; + + class = pci_config_readw(d, PCI_CLASS_DEVICE); + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + switch(class) { + case 0x0101: + if (vendor_id == 0x8086 && device_id == 0x7010) { + /* PIIX3 IDE */ + pci_config_writew(d, 0x40, 0x8000); // enable IDE0 + pci_config_writew(d, 0x42, 0x8000); // enable IDE1 + goto default_map; + } else { + /* IDE: we map it as in ISA mode */ + pci_set_io_region_addr(d, 0, 0x1f0); + pci_set_io_region_addr(d, 1, 0x3f4); + pci_set_io_region_addr(d, 2, 0x170); + pci_set_io_region_addr(d, 3, 0x374); + } + break; + case 0x0680: + if (vendor_id == 0x8086 && device_id == 0x7113) { + /* PIIX4 ACPI PM */ + pci_config_writew(d, 0x20, 0x0000); /* NO smb bus IO enable in PIIX4 */ + pci_config_writew(d, 0x22, 0x0000); + goto default_map; + } + break; + case 0x0300: + if (vendor_id != 0x1234) + goto default_map; + /* VGA: map frame buffer to default Bochs VBE address */ + pci_set_io_region_addr(d, 0, 0xE0000000); + break; + case 0x0800: + /* PIC */ + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + if (vendor_id == 0x1014) { + /* IBM */ + if (device_id == 0x0046 || device_id == 0xFFFF) { + /* MPIC & MPIC2 */ + pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); + } + } + break; + case 0xff00: + if (vendor_id == 0x0106b && + (device_id == 0x0017 || device_id == 0x0022)) { + /* macio bridge */ + pci_set_io_region_addr(d, 0, 0x80800000); + } + break; + default: + default_map: + /* default memory mappings */ + for(i = 0; i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + if (r->size) { + if (r->type & PCI_ADDRESS_SPACE_IO) + paddr = &pci_bios_io_addr; + else + paddr = &pci_bios_mem_addr; + *paddr = (*paddr + r->size - 1) & ~(r->size - 1); + pci_set_io_region_addr(d, i, *paddr); + *paddr += r->size; + } + } + break; + } + + /* map the interrupt */ + pin = pci_config_readb(d, PCI_INTERRUPT_PIN); + if (pin != 0) { + pin = pci_slot_get_pirq(d, pin - 1); + pic_irq = pci_irqs[pin]; + pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); + } + + if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) { + // PIIX4 ACPI PM + pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 + pci_config_writew(d, 0x22, 0x0000); + pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9 + pci_config_writew(d, 0x3d, 0x0001); + } +} + +/* + * This function initializes the PCI devices as a normal PCI BIOS + * would do. It is provided just in case the BIOS has no support for + * PCI. + */ +void pci_bios_init(void) +{ + int i, irq; + uint8_t elcr[2]; + + pci_bios_io_addr = 0xc000; + pci_bios_mem_addr = 0xf0000000; + + /* activate IRQ mappings */ + elcr[0] = 0x00; + elcr[1] = 0x00; + for(i = 0; i < 4; i++) { + irq = pci_irqs[i]; + /* set to trigger level */ + elcr[irq >> 3] |= (1 << (irq & 7)); + /* activate irq remapping in PIIX */ + pci_config_writeb(piix3_dev, 0x60 + i, irq); + } + isa_outb(elcr[0], 0x4d0); + isa_outb(elcr[1], 0x4d1); + + pci_for_each_device(pci_bios_init_device); +} + diff --git a/tools/ioemu/hw/pl050.c b/tools/ioemu/hw/pl050.c index a71ccf6149..20451e532e 100644 --- a/tools/ioemu/hw/pl050.c +++ b/tools/ioemu/hw/pl050.c @@ -1,5 +1,5 @@ /* - * Arm PrimeCell PL050 Kyeboard / Mouse Interface + * Arm PrimeCell PL050 Keyboard / Mouse Interface * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook diff --git a/tools/ioemu/hw/ppc_chrp.c b/tools/ioemu/hw/ppc_chrp.c index 33167cdf75..42d599588e 100644 --- a/tools/ioemu/hw/ppc_chrp.c +++ b/tools/ioemu/hw/ppc_chrp.c @@ -415,19 +415,18 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, if (is_heathrow) { isa_mem_base = 0x80000000; - pci_bus = pci_grackle_init(0xfec00000); /* Register 2 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); /* init basic PC hardware */ + pic = heathrow_pic_init(&heathrow_pic_mem_index); + set_irq = heathrow_pic_set_irq; + pci_bus = pci_grackle_init(0xfec00000, pic); vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = heathrow_pic_init(&heathrow_pic_mem_index); - set_irq = heathrow_pic_set_irq; - pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); @@ -462,7 +461,6 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, arch_name = "HEATHROW"; } else { isa_mem_base = 0x80000000; - pci_bus = pci_pmac_init(); /* Register 8 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); @@ -472,13 +470,13 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); + pic = openpic_init(NULL, &openpic_mem_index, 1, &env); + set_irq = openpic_set_irq; + pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = openpic_init(NULL, &openpic_mem_index, 1, &env); - set_irq = openpic_set_irq; - pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); @@ -508,7 +506,11 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, arch_name = "MAC99"; } - + + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; diff --git a/tools/ioemu/hw/ppc_prep.c b/tools/ioemu/hw/ppc_prep.c index 9df430775d..a4d7ddfe7e 100644 --- a/tools/ioemu/hw/ppc_prep.c +++ b/tools/ioemu/hw/ppc_prep.c @@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); #endif + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); if (nvram == NULL) return; diff --git a/tools/ioemu/hw/prep_pci.c b/tools/ioemu/hw/prep_pci.c new file mode 100644 index 0000000000..a31b74c80a --- /dev/null +++ b/tools/ioemu/hw/prep_pci.c @@ -0,0 +1,167 @@ +/* + * QEMU PREP PCI host + * + * Copyright (c) 2006 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" +typedef uint32_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState PREPPCIState; + +static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; + s->config_reg = val; +} + +static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr) +{ + PREPPCIState *s = opaque; + return s->config_reg; +} + +static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr) +{ + int i; + + for(i = 0; i < 11; i++) { + if ((addr & (1 << (11 + i))) != 0) + break; + } + return (addr & 0x7ff) | (i << 11); +} + +static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; + pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1); +} + +static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2); +} + +static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4); +} + +static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) +{ + PREPPCIState *s = opaque; + uint32_t val; + val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1); + return val; +} + +static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) +{ + PREPPCIState *s = opaque; + uint32_t val; + val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) +{ + PREPPCIState *s = opaque; + uint32_t val; + val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { + &PPC_PCIIO_writeb, + &PPC_PCIIO_writew, + &PPC_PCIIO_writel, +}; + +static CPUReadMemoryFunc *PPC_PCIIO_read[] = { + &PPC_PCIIO_readb, + &PPC_PCIIO_readw, + &PPC_PCIIO_readl, +}; + +static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + /* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ + pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_prep_init(void) +{ + PREPPCIState *s; + PCIDevice *d; + int PPC_io_memory; + + s = qemu_mallocz(sizeof(PREPPCIState)); + s->bus = pci_register_bus(prep_set_irq, NULL, 0); + + register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); + register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); + + register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); + register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); + register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); + register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); + register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); + register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); + + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, + PPC_PCIIO_write, s); + cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); + + /* PCI host bridge */ + d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", + sizeof(PCIDevice), 0, NULL, NULL); + d->config[0x00] = 0x57; // vendor_id : Motorola + d->config[0x01] = 0x10; + d->config[0x02] = 0x01; // device_id : Raven + d->config[0x03] = 0x48; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer + + return s->bus; +} + diff --git a/tools/ioemu/hw/rtl8139.c b/tools/ioemu/hw/rtl8139.c index 49c4c916b7..9c613a8f93 100644 --- a/tools/ioemu/hw/rtl8139.c +++ b/tools/ioemu/hw/rtl8139.c @@ -23,15 +23,33 @@ * Modifications: * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver) - * + * + * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver + * HW revision ID changes for FreeBSD driver + * + * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver + * Corrected packet transfer reassembly routine for 8139C+ mode + * Rearranged debugging print statements + * Implemented PCI timer interrupt (disabled by default) + * Implemented Tally Counters, increased VM load/save version + * Implemented IP/TCP/UDP checksum task offloading + * + * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading + * Fixed MTU=1500 for produced ethernet frames + * + * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing + * segmentation offloading + * Removed slirp.h dependency + * Added rx/tx buffer reset when enabling rx/tx operation */ #include "vl.h" - /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 +#define PCI_FREQUENCY 33000000L + /* debug RTL8139 card C+ mode only */ //#define DEBUG_RTL8139CP 1 @@ -39,6 +57,8 @@ ignored by most drivers, disabled by default */ //#define RTL8139_CALCULATE_RXCRC 1 +/* Uncomment to enable on-board timer interrupts */ +//#define RTL8139_ONBOARD_TIMER 1 #if defined(RTL8139_CALCULATE_RXCRC) /* For crc32 */ @@ -52,12 +72,19 @@ #define MOD2(input, size) \ ( ( input ) & ( size - 1 ) ) +#if defined (DEBUG_RTL8139) +# define DEBUG_PRINT(x) do { printf x ; } while (0) +#else +# define DEBUG_PRINT(x) +#endif + /* Symbolic offsets to registers. */ enum RTL8139_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */ + /* Dump Tally Conter control register(64bit). C+ mode only */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ RxBuf = 0x30, ChipCmd = 0x37, RxBufPtr = 0x38, @@ -115,8 +142,10 @@ enum ChipCmdBits { /* C+ mode */ enum CplusCmdBits { - CPlusRxEnb = 0x0002, - CPlusTxEnb = 0x0001, + CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */ + CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */ + CPlusRxEnb = 0x0002, + CPlusTxEnb = 0x0001, }; /* Interrupt register bits, using my own meaningful names. */ @@ -315,6 +344,11 @@ enum chip_flags { (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) #define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) +#define RTL8139_PCI_REVID_8139 0x10 +#define RTL8139_PCI_REVID_8139CPLUS 0x20 + +#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS + /* Size is 64 * 16bit words */ #define EEPROM_9346_ADDR_BITS 6 #define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS) @@ -356,11 +390,41 @@ typedef struct EEprom9346 uint8_t eedo; } EEprom9346; +typedef struct RTL8139TallyCounters +{ + /* Tally counters */ + uint64_t TxOk; + uint64_t RxOk; + uint64_t TxERR; + uint32_t RxERR; + uint16_t MissPkt; + uint16_t FAE; + uint32_t Tx1Col; + uint32_t TxMCol; + uint64_t RxOkPhy; + uint64_t RxOkBrd; + uint32_t RxOkMul; + uint16_t TxAbt; + uint16_t TxUndrn; +} RTL8139TallyCounters; + +/* Clears all tally counters */ +static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters); + +/* Writes tally counters to specified physical memory address */ +static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters); + +/* Loads values of tally counters from VM state file */ +static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters); + +/* Saves values of tally counters to VM state file */ +static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters); + typedef struct RTL8139State { uint8_t phys[8]; /* mac address */ uint8_t mult[8]; /* multicast mask array */ - uint32_t TxStatus[4]; /* TxStatus0 */ + uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */ uint32_t TxAddr[4]; /* TxAddr0 */ uint32_t RxBuf; /* Receive buffer */ uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */ @@ -414,14 +478,27 @@ typedef struct RTL8139State { uint32_t RxRingAddrHI; EEprom9346 eeprom; - + + uint32_t TCTR; + uint32_t TimerInt; + int64_t TCTR_base; + + /* Tally counters */ + RTL8139TallyCounters tally_counters; + + /* Non-persistent data */ + uint8_t *cplus_txbuffer; + int cplus_txbuffer_len; + int cplus_txbuffer_offset; + + /* PCI interrupt timer */ + QEMUTimer *timer; + } RTL8139State; void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom command 0x%02x\n", command); -#endif + DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); switch (command & Chip9346_op_mask) { @@ -432,10 +509,8 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) eeprom->eedo = 0; eeprom->tick = 0; eeprom->mode = Chip9346_data_read; -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output); -#endif + DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output)); } break; @@ -445,10 +520,8 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) eeprom->input = 0; eeprom->tick = 0; eeprom->mode = Chip9346_none; /* Chip9346_data_write */ -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom begin write to address 0x%02x\n", - eeprom->address); -#endif + DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n", + eeprom->address)); } break; default: @@ -456,19 +529,13 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) switch (command & Chip9346_op_ext_mask) { case Chip9346_op_write_enable: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write enabled\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom write enabled\n")); break; case Chip9346_op_write_all: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom begin write all\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom begin write all\n")); break; case Chip9346_op_write_disable: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom write disabled\n")); break; } break; @@ -481,9 +548,7 @@ void prom9346_shift_clock(EEprom9346 *eeprom) ++ eeprom->tick; -#if defined(DEBUG_RTL8139) - printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo); -#endif + DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo)); switch (eeprom->mode) { @@ -493,9 +558,7 @@ void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->mode = Chip9346_read_command; eeprom->tick = 0; eeprom->input = 0; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ synchronized, begin command read\n"); -#endif + DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n")); } break; @@ -512,14 +575,24 @@ void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->output <<= 1; if (eeprom->tick == 16) { +#if 1 + // the FreeBSD drivers (rl and re) don't explicitly toggle + // CS between reads (or does setting Cfg9346 to 0 count too?), + // so we need to enter wait-for-command state here + eeprom->mode = Chip9346_enter_command_mode; + eeprom->input = 0; + eeprom->tick = 0; + + DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n")); +#else + // original behaviour ++eeprom->address; eeprom->address &= EEPROM_9346_ADDR_MASK; eeprom->output = eeprom->contents[eeprom->address]; eeprom->tick = 0; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ read next address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output); + DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output)); #endif } break; @@ -528,10 +601,9 @@ void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 16) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->input); -#endif + DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->input)); + eeprom->contents[eeprom->address] = eeprom->input; eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ eeprom->tick = 0; @@ -548,10 +620,9 @@ void prom9346_shift_clock(EEprom9346 *eeprom) { eeprom->contents[i] = eeprom->input; } -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom filled with data=0x%04x\n", - eeprom->input); -#endif + DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n", + eeprom->input)); + eeprom->mode = Chip9346_enter_command_mode; eeprom->tick = 0; eeprom->input = 0; @@ -582,9 +653,8 @@ void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) eeprom->eesk = eesk; eeprom->eedi = eedi; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo); -#endif + DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", + eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo)); if (!old_eecs && eecs) { @@ -594,17 +664,12 @@ void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) eeprom->output = 0; eeprom->mode = Chip9346_enter_command_mode; -#if defined(DEBUG_RTL8139) - printf("=== eeprom: begin access, enter command mode\n"); -#endif - + DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n")); } if (!eecs) { -#if defined(DEBUG_RTL8139) - printf("=== eeprom: end access\n"); -#endif + DEBUG_PRINT(("=== eeprom: end access\n")); return; } @@ -619,10 +684,10 @@ static void rtl8139_update_irq(RTL8139State *s) { int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; -#if defined(DEBUG_RTL8139) - printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", - s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask); -#endif + + DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", + s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask)); + if (s->irq == 16) { /* PCI irq */ pci_set_irq(s->pci_dev, 0, (isr != 0)); @@ -691,9 +756,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) /* write packet data */ if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) { - #if defined(DEBUG_RTL8139) - printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped); - #endif + DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); if (size > wrapped) { @@ -751,7 +814,7 @@ static int rtl8139_can_receive(void *opaque) } } -static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt) { RTL8139State *s = opaque; @@ -761,16 +824,12 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: received len=%d\n", size); -#endif + DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); /* test if board clock is stopped */ if (!s->clock_enabled) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: stopped ==========================\n"); -#endif + DEBUG_PRINT(("RTL8139: stopped ==========================\n")); return; } @@ -778,42 +837,44 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (!rtl8139_receiver_enabled(s)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: receiver disabled ================\n"); -#endif + DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); return; } /* XXX: check this */ if (s->RxConfig & AcceptAllPhys) { /* promiscuous: receive all */ -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: packet received in promiscuous mode\n"); -#endif + DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n")); } else { if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->RxConfig & AcceptBroadcast)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: broadcast packet rejected\n"); -#endif + DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxBroadcast; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: broadcast packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: broadcast packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkBrd; + } else if (buf[0] & 0x01) { /* multicast */ if (!(s->RxConfig & AcceptMulticast)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast packet rejected\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } @@ -821,17 +882,21 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast address mismatch\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxMulticast; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkMul; + } else if (s->phys[0] == buf[0] && s->phys[1] == buf[1] && s->phys[2] == buf[2] && @@ -841,23 +906,28 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) /* match */ if (!(s->RxConfig & AcceptMyPhys)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: rejecting physical address matching packet\n"); -#endif + DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxPhysical; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: physical address matching packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkPhy; } else { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: unknown packet\n"); -#endif + DEBUG_PRINT((">>> RTL8139: unknown packet\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } } @@ -872,9 +942,7 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (rtl8139_cp_receiver_enabled(s)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: in C+ Rx mode ================\n"); -#endif + DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n")); /* begin C+ receiver mode */ @@ -897,10 +965,8 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); cplus_rx_ring_desc += 16 * descriptor; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = 0x%8lx\n", - descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n", + descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc)); uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; @@ -913,33 +979,41 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); rxbufHI = le32_to_cpu(val); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", + DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", descriptor, - rxdw0, rxdw1, rxbufLO, rxbufHI); -#endif + rxdw0, rxdw1, rxbufLO, rxbufHI)); if (!(rxdw0 & CP_RX_OWN)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; + + /* update tally counter */ + ++s->tally_counters.RxERR; + ++s->tally_counters.MissPkt; + rtl8139_update_irq(s); return; } uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; + /* TODO: scatter the packet over available receive ring descriptors space */ + if (size+4 > rx_space) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", - descriptor, rx_space, size); -#endif + DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", + descriptor, rx_space, size)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; + + /* update tally counter */ + ++s->tally_counters.RxERR; + ++s->tally_counters.MissPkt; + rtl8139_update_irq(s); return; } @@ -949,6 +1023,11 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) /* receive/copy to target memory */ cpu_physical_memory_write( rx_addr, buf, size ); + if (s->CpCmd & CPlusRxChkSum) + { + /* do some packet checksumming */ + } + /* write checksum */ #if defined (RTL8139_CALCULATE_RXCRC) val = cpu_to_le32(crc32(~0, buf, size)); @@ -1008,6 +1087,9 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) val = cpu_to_le32(rxdw1); cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + /* update tally counter */ + ++s->tally_counters.RxOk; + /* seek to next Rx descriptor */ if (rxdw0 & CP_RX_EOR) { @@ -1018,16 +1100,13 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) ++s->currCPlusRxDesc; } -#if defined(DEBUG_RTL8139) - printf("RTL8139: done C+ Rx mode ----------------\n"); -#endif + DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n")); } else { -#if defined(DEBUG_RTL8139) - printf("RTL8139: in ring Rx mode ================\n"); -#endif + DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n")); + /* begin ring receiver mode */ int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); @@ -1035,10 +1114,9 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (avail != 0 && size + 8 >= avail) { -#if defined(DEBUG_RTL8139) - printf("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); -#endif + DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; rtl8139_update_irq(s); @@ -1070,15 +1148,21 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) /* now we can signal we have received something */ -#if defined(DEBUG_RTL8139) - printf(" received: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); -#endif - + DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); } s->IntrStatus |= RxOK; - rtl8139_update_irq(s); + + if (do_interrupt) + { + rtl8139_update_irq(s); + } +} + +static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +{ + rtl8139_do_receive(opaque, buf, size, 1); } static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) @@ -1103,6 +1187,11 @@ static void rtl8139_reset(RTL8139State *s) /* prepare eeprom */ s->eeprom.contents[0] = 0x8129; +#if 1 + // PCI vendor and device ID should be mirrored here + s->eeprom.contents[1] = 0x10ec; + s->eeprom.contents[2] = 0x8139; +#endif memcpy(&s->eeprom.contents[7], s->macaddr, 6); /* mark all status registers as owned by host */ @@ -1129,7 +1218,7 @@ static void rtl8139_reset(RTL8139State *s) // s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk s->clock_enabled = 0; #else - s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 0, 0); // RTL-8139C HasLWake + s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake s->clock_enabled = 1; #endif @@ -1157,34 +1246,137 @@ static void rtl8139_reset(RTL8139State *s) s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ s->NWayExpansion = 0x0001; /* autonegotiation supported */ + + /* also reset timer and disable timer interrupt */ + s->TCTR = 0; + s->TimerInt = 0; + s->TCTR_base = 0; + + /* reset tally counters */ + RTL8139TallyCounters_clear(&s->tally_counters); +} + +void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) +{ + counters->TxOk = 0; + counters->RxOk = 0; + counters->TxERR = 0; + counters->RxERR = 0; + counters->MissPkt = 0; + counters->FAE = 0; + counters->Tx1Col = 0; + counters->TxMCol = 0; + counters->RxOkPhy = 0; + counters->RxOkBrd = 0; + counters->RxOkMul = 0; + counters->TxAbt = 0; + counters->TxUndrn = 0; +} + +static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters) +{ + uint16_t val16; + uint32_t val32; + uint64_t val64; + + val64 = cpu_to_le64(tally_counters->TxOk); + cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->RxOk); + cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->TxERR); + cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8); + + val32 = cpu_to_le32(tally_counters->RxERR); + cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4); + + val16 = cpu_to_le16(tally_counters->MissPkt); + cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2); + + val16 = cpu_to_le16(tally_counters->FAE); + cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2); + + val32 = cpu_to_le32(tally_counters->Tx1Col); + cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4); + + val32 = cpu_to_le32(tally_counters->TxMCol); + cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4); + + val64 = cpu_to_le64(tally_counters->RxOkPhy); + cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->RxOkBrd); + cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8); + + val32 = cpu_to_le32(tally_counters->RxOkMul); + cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4); + + val16 = cpu_to_le16(tally_counters->TxAbt); + cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2); + + val16 = cpu_to_le16(tally_counters->TxUndrn); + cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2); +} + +/* Loads values of tally counters from VM state file */ +static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters) +{ + qemu_get_be64s(f, &tally_counters->TxOk); + qemu_get_be64s(f, &tally_counters->RxOk); + qemu_get_be64s(f, &tally_counters->TxERR); + qemu_get_be32s(f, &tally_counters->RxERR); + qemu_get_be16s(f, &tally_counters->MissPkt); + qemu_get_be16s(f, &tally_counters->FAE); + qemu_get_be32s(f, &tally_counters->Tx1Col); + qemu_get_be32s(f, &tally_counters->TxMCol); + qemu_get_be64s(f, &tally_counters->RxOkPhy); + qemu_get_be64s(f, &tally_counters->RxOkBrd); + qemu_get_be32s(f, &tally_counters->RxOkMul); + qemu_get_be16s(f, &tally_counters->TxAbt); + qemu_get_be16s(f, &tally_counters->TxUndrn); +} + +/* Saves values of tally counters to VM state file */ +static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters) +{ + qemu_put_be64s(f, &tally_counters->TxOk); + qemu_put_be64s(f, &tally_counters->RxOk); + qemu_put_be64s(f, &tally_counters->TxERR); + qemu_put_be32s(f, &tally_counters->RxERR); + qemu_put_be16s(f, &tally_counters->MissPkt); + qemu_put_be16s(f, &tally_counters->FAE); + qemu_put_be32s(f, &tally_counters->Tx1Col); + qemu_put_be32s(f, &tally_counters->TxMCol); + qemu_put_be64s(f, &tally_counters->RxOkPhy); + qemu_put_be64s(f, &tally_counters->RxOkBrd); + qemu_put_be32s(f, &tally_counters->RxOkMul); + qemu_put_be16s(f, &tally_counters->TxAbt); + qemu_put_be16s(f, &tally_counters->TxUndrn); } static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val)); if (val & CmdReset) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd reset\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd reset\n")); rtl8139_reset(s); } if (val & CmdRxEnb) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd enable receiver\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); + + s->currCPlusRxDesc = 0; } if (val & CmdTxEnb) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd enable transmitter\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); + + s->currCPlusTxDesc = 0; } /* mask unwriteable bits */ @@ -1202,15 +1394,11 @@ static int rtl8139_RxBufferEmpty(RTL8139State *s) if (unread != 0) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: receiver buffer data available 0x%04x\n", unread); -#endif + DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread)); return 0; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: receiver buffer is empty\n"); -#endif + DEBUG_PRINT(("RTL8139: receiver buffer is empty\n")); return 1; } @@ -1222,9 +1410,7 @@ static uint32_t rtl8139_ChipCmd_read(RTL8139State *s) if (rtl8139_RxBufferEmpty(s)) ret |= RxBufEmpty; -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret)); return ret; } @@ -1233,9 +1419,7 @@ static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val) { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ command register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff84, s->CpCmd); @@ -1247,9 +1431,21 @@ static uint32_t rtl8139_CpCmd_read(RTL8139State *s) { uint32_t ret = s->CpCmd; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ command register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret)); + + return ret; +} + +static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val) +{ + DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val)); +} + +static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s) +{ + uint32_t ret = 0; + + DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret)); return ret; } @@ -1261,9 +1457,7 @@ int rtl8139_config_writeable(RTL8139State *s) return 1; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: Configuration registers are write-protected\n"); -#endif + DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n")); return 0; } @@ -1272,9 +1466,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ uint32 mask = 0x4cff; @@ -1296,9 +1488,7 @@ static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s) { uint32_t ret = s->BasicModeCtrl; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret)); return ret; } @@ -1307,9 +1497,7 @@ static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val) { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff3f, s->BasicModeStatus); @@ -1321,9 +1509,7 @@ static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s) { uint32_t ret = s->BasicModeStatus; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret)); return ret; } @@ -1332,9 +1518,7 @@ static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Cfg9346 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x31, s->Cfg9346); @@ -1377,9 +1561,7 @@ static uint32_t rtl8139_Cfg9346_read(RTL8139State *s) } } -#ifdef DEBUG_RTL8139 - printf("RTL8139: Cfg9346 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret)); return ret; } @@ -1388,9 +1570,7 @@ static void rtl8139_Config0_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config0 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1405,9 +1585,7 @@ static uint32_t rtl8139_Config0_read(RTL8139State *s) { uint32_t ret = s->Config0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config0 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret)); return ret; } @@ -1416,9 +1594,7 @@ static void rtl8139_Config1_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config1 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1433,9 +1609,7 @@ static uint32_t rtl8139_Config1_read(RTL8139State *s) { uint32_t ret = s->Config1; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config1 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret)); return ret; } @@ -1444,9 +1618,7 @@ static void rtl8139_Config3_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config3 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1461,9 +1633,7 @@ static uint32_t rtl8139_Config3_read(RTL8139State *s) { uint32_t ret = s->Config3; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config3 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret)); return ret; } @@ -1472,9 +1642,7 @@ static void rtl8139_Config4_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config4 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1489,9 +1657,7 @@ static uint32_t rtl8139_Config4_read(RTL8139State *s) { uint32_t ret = s->Config4; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config4 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret)); return ret; } @@ -1500,9 +1666,7 @@ static void rtl8139_Config5_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config5 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x80, s->Config5); @@ -1514,9 +1678,7 @@ static uint32_t rtl8139_Config5_read(RTL8139State *s) { uint32_t ret = s->Config5; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config5 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret)); return ret; } @@ -1525,15 +1687,11 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val)); return; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val)); val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig); @@ -1542,31 +1700,26 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C TxConfig via write(b) val=0x%02x\n", val); -#endif - uint32_t tc = s->TxConfig; - tc &= 0xFFFFFF00; - tc |= (val & 0x000000FF); - rtl8139_TxConfig_write(s, tc); + DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val)); + + uint32_t tc = s->TxConfig; + tc &= 0xFFFFFF00; + tc |= (val & 0x000000FF); + rtl8139_TxConfig_write(s, tc); } static uint32_t rtl8139_TxConfig_read(RTL8139State *s) { uint32_t ret = s->TxConfig; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxConfig read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret)); return ret; } static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf0fc0040, s->RxConfig); @@ -1576,61 +1729,70 @@ static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) /* reset buffer size and read/write pointers */ rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3)); -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize); -#endif + DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize)); } static uint32_t rtl8139_RxConfig_read(RTL8139State *s) { uint32_t ret = s->RxConfig; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret)); return ret; } +static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt) +{ + if (!size) + { + DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n")); + return; + } + + if (TxLoopBack == (s->TxConfig & TxLoopBack)) + { + DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); + rtl8139_do_receive(s, buf, size, do_interrupt); + } + else + { + qemu_send_packet(s->vc, buf, size); + } +} + static int rtl8139_transmit_one(RTL8139State *s, int descriptor) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", + descriptor)); return 0; } if (s->TxStatus[descriptor] & TxHostOwns) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", descriptor, s->TxStatus[descriptor]); -#endif + DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", + descriptor, s->TxStatus[descriptor])); return 0; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmitting from descriptor %d\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor)); int txsize = s->TxStatus[descriptor] & 0x1fff; uint8_t txbuffer[0x2000]; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); -#endif - cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); + DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", + txsize, s->TxAddr[descriptor])); - qemu_send_packet(s->vc, txbuffer, txsize); + cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); /* Mark descriptor as transferred */ s->TxStatus[descriptor] |= TxHostOwns; s->TxStatus[descriptor] |= TxStatOK; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor); -#endif + rtl8139_transfer_frame(s, txbuffer, txsize, 0); + + DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); /* update interrupt */ s->IntrStatus |= TxOK; @@ -1639,21 +1801,104 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) return 1; } +/* structures and macros for task offloading */ +typedef struct ip_header +{ + uint8_t ip_ver_len; /* version and header length */ + uint8_t ip_tos; /* type of service */ + uint16_t ip_len; /* total length */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset field */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + uint32_t ip_src,ip_dst; /* source and dest address */ +} ip_header; + +#define IP_HEADER_VERSION_4 4 +#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf) +#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2) + +typedef struct tcp_header +{ + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgement number */ + uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */ + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +} tcp_header; + +typedef struct udp_header +{ + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +} udp_header; + +typedef struct ip_pseudo_header +{ + uint32_t ip_src; + uint32_t ip_dst; + uint8_t zeros; + uint8_t ip_proto; + uint16_t ip_payload; +} ip_pseudo_header; + +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 + +#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) +#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) +#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) + +#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) + +#define TCP_FLAG_FIN 0x01 +#define TCP_FLAG_PUSH 0x08 + +/* produces ones' complement sum of data */ +static uint16_t ones_complement_sum(uint8_t *data, size_t len) +{ + uint32_t result = 0; + + for (; len > 1; data+=2, len-=2) + { + result += *(uint16_t*)data; + } + + /* add the remainder byte */ + if (len) + { + uint8_t odd[2] = {*data, 0}; + result += *(uint16_t*)odd; + } + + while (result>>16) + result = (result & 0xffff) + (result >> 16); + + return result; +} + +static uint16_t ip_checksum(void *data, size_t len) +{ + return ~ones_complement_sum((uint8_t*)data, len); +} + static int rtl8139_cplus_transmit_one(RTL8139State *s) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode: transmitter disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n")); return 0; } if (!rtl8139_cp_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode: C+ transmitter disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n")); return 0 ; } @@ -1665,10 +1910,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* Normal priority ring */ cplus_tx_ring_desc += 16 * descriptor; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", - descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", + descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; @@ -1681,11 +1924,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); txbufHI = le32_to_cpu(val); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", + DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor, - txdw0, txdw1, txbufLO, txbufHI); -#endif + txdw0, txdw1, txbufLO, txbufHI)); /* w0 ownership flag */ #define CP_TX_OWN (1<<31) @@ -1697,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) #define CP_TX_LS (1<<28) /* large send packet flag */ #define CP_TX_LGSEN (1<<27) +/* large send MSS mask, bits 16...25 */ +#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) + /* IP checksum offload flag */ #define CP_TX_IPCS (1<<18) /* UDP checksum offload flag */ @@ -1728,28 +1972,73 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if (!(txdw0 & CP_TX_OWN)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor)); return 0 ; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor)); + + if (txdw0 & CP_TX_FS) + { + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor)); + + /* reset internal buffer offset */ + s->cplus_txbuffer_offset = 0; + } int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK; target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); - uint8_t txbuffer[CP_TX_BUFFER_SIZE]; + /* make sure we have enough space to assemble the packet */ + if (!s->cplus_txbuffer) + { + s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; + s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); + s->cplus_txbuffer_offset = 0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at 0x%08x\n", txsize, tx_addr); -#endif - cpu_physical_memory_read(tx_addr, txbuffer, txsize); + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); + } - /* transmit the packet */ - qemu_send_packet(s->vc, txbuffer, txsize); + while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) + { + s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; + s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); + } + + if (!s->cplus_txbuffer) + { + /* out of memory */ + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len)); + + /* update tally counter */ + ++s->tally_counters.TxERR; + ++s->tally_counters.TxAbt; + + return 0; + } + + /* append more data to the packet */ + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n", + txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset)); + + cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); + s->cplus_txbuffer_offset += txsize; + + /* seek to next Rx descriptor */ + if (txdw0 & CP_TX_EOR) + { + s->currCPlusTxDesc = 0; + } + else + { + ++s->currCPlusTxDesc; + if (s->currCPlusTxDesc >= 64) + s->currCPlusTxDesc = 0; + } /* transfer ownership to target */ txdw0 &= ~CP_RX_OWN; @@ -1767,19 +2056,266 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) // val = cpu_to_le32(txdw1); // cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4); - /* seek to next Rx descriptor */ - if (txdw0 & CP_TX_EOR) + /* Now decide if descriptor being processed is holding the last segment of packet */ + if (txdw0 & CP_TX_LS) { - s->currCPlusTxDesc = 0; + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor)); + + /* can transfer fully assembled packet */ + + uint8_t *saved_buffer = s->cplus_txbuffer; + int saved_size = s->cplus_txbuffer_offset; + int saved_buffer_len = s->cplus_txbuffer_len; + + /* reset the card space to protect from recursive call */ + s->cplus_txbuffer = NULL; + s->cplus_txbuffer_offset = 0; + s->cplus_txbuffer_len = 0; + + if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); + + #define ETH_P_IP 0x0800 /* Internet Protocol packet */ + #define ETH_HLEN 14 + #define ETH_MTU 1500 + + /* ip packet header */ + ip_header *ip = 0; + int hlen = 0; + uint8_t ip_protocol = 0; + uint16_t ip_data_len = 0; + + uint8_t *eth_payload_data = 0; + size_t eth_payload_len = 0; + + int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); + if (proto == ETH_P_IP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); + + /* not aligned */ + eth_payload_data = saved_buffer + ETH_HLEN; + eth_payload_len = saved_size - ETH_HLEN; + + ip = (ip_header*)eth_payload_data; + + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4)); + ip = NULL; + } else { + hlen = IP_HEADER_LENGTH(ip); + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; + } + } + + if (ip) + { + if (txdw0 & CP_TX_IPCS) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); + + if (hleneth_payload_len) {/* min header length */ + /* bad packet header len */ + /* or packet too short */ + } + else + { + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(ip, hlen); + DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + } + } + + if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) + { +#if defined (DEBUG_RTL8139) + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; +#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", + ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss)); + + int tcp_send_offset = 0; + int send_count = 0; + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + + /* save IP header template; data area is used in tcp checksum calculation */ + memcpy(saved_ip_header, eth_payload_data, hlen); + + /* a placeholder for checksum calculation routine in tcp case */ + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* pointer to TCP header */ + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + + /* ETH_MTU = ip header len + tcp header len + payload */ + int tcp_data_len = ip_data_len - tcp_hlen; + int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n", + ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size)); + + /* note the cycle below overwrites IP header data, + but restores it from saved_ip_header before sending packet */ + + int is_last_frame = 0; + + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) + { + uint16_t chunk_size = tcp_chunk_size; + + /* check if this is the last frame */ + if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + { + is_last_frame = 1; + chunk_size = tcp_data_len - tcp_send_offset; + } + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); + + if (tcp_send_offset) + { + memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); + } + + /* keep PUSH and FIN flags only for the last frame */ + if (!is_last_frame) + { + TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); + } + + /* recalculate TCP checksum */ + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); + + p_tcp_hdr->th_sum = tcp_checksum; + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); + + /* set IP data length and recalculate IP checksum */ + ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); + + /* increment IP id for subsequent frames */ + ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(eth_payload_data, hlen); + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + + int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); + rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); + + /* add transferred count to TCP sequence number */ + p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); + ++send_count; + } + + /* Stop sending this frame */ + saved_size = 0; + } + else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, eth_payload_data, hlen); + + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); + + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); + + p_tcp_hdr->th_sum = tcp_checksum; + } + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); + + ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_udpip_hdr->zeros = 0; + p_udpip_hdr->ip_proto = IP_PROTO_UDP; + p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + + p_udp_hdr->uh_sum = 0; + + int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); + + p_udp_hdr->uh_sum = udp_checksum; + } + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); + } + } + } + + /* update tally counter */ + ++s->tally_counters.TxOk; + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); + + rtl8139_transfer_frame(s, saved_buffer, saved_size, 1); + + /* restore card space if there was no recursion and reset offset */ + if (!s->cplus_txbuffer) + { + s->cplus_txbuffer = saved_buffer; + s->cplus_txbuffer_len = saved_buffer_len; + s->cplus_txbuffer_offset = 0; + } + else + { + free(saved_buffer); + } } else { - ++s->currCPlusTxDesc; + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n")); } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode transmitted %d bytes from descriptor %d\n", txsize, descriptor); -#endif return 1; } @@ -1795,9 +2331,8 @@ static void rtl8139_cplus_transmit(RTL8139State *s) /* Mark transfer completed */ if (!txcount) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", s->currCPlusTxDesc); -#endif + DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", + s->currCPlusTxDesc)); } else { @@ -1822,9 +2357,7 @@ static void rtl8139_transmit(RTL8139State *s) /* Mark transfer completed */ if (!txcount) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc); -#endif + DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc)); } } @@ -1832,9 +2365,31 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 { int descriptor = txRegOffset/4; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor); -#endif + + /* handle C+ transmit mode register configuration */ + + if (rtl8139_cp_transmitter_enabled(s)) + { + DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); + + /* handle Dump Tally Counters command */ + s->TxStatus[descriptor] = val; + + if (descriptor == 0 && (val & 0x8)) + { + target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); + + /* dump tally counters to specified memory location */ + RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters); + + /* mark dump completed */ + s->TxStatus[0] &= ~0x8; + } + + return; + } + + DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); /* mask only reserved bits */ val &= ~0xff00c000; /* these bits are reset on write */ @@ -1850,9 +2405,7 @@ static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset) { uint32_t ret = s->TxStatus[txRegOffset/4]; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret); -#endif + DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret)); return ret; } @@ -1884,9 +2437,7 @@ static uint16_t rtl8139_TSAD_read(RTL8139State *s) |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TSAD read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); return ret; } @@ -1895,18 +2446,14 @@ static uint16_t rtl8139_CSCR_read(RTL8139State *s) { uint16_t ret = s->CSCR; -#ifdef DEBUG_RTL8139 - printf("RTL8139: CSCR read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret)); return ret; } static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val); -#endif + DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); } @@ -1915,26 +2462,20 @@ static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) { uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]); -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret); -#endif + DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret)); return ret; } static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBufPtr write val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val)); /* this value is off by 16 */ s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize); -#if defined(DEBUG_RTL8139) - printf(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); -#endif + DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); } static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) @@ -1942,18 +2483,24 @@ static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) /* this value is off by 16 */ uint32_t ret = s->RxBufPtr - 0x10; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBufPtr read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret)); + + return ret; +} + +static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s) +{ + /* this value is NOT off by 16 */ + uint32_t ret = s->RxBufAddr; + + DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret)); return ret; } static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBuf write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val)); s->RxBuf = val; @@ -1964,18 +2511,14 @@ static uint32_t rtl8139_RxBuf_read(RTL8139State *s) { uint32_t ret = s->RxBuf; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBuf read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret)); return ret; } static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrMask write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x1e00, s->IntrMask); @@ -1989,18 +2532,14 @@ static uint32_t rtl8139_IntrMask_read(RTL8139State *s) { uint32_t ret = s->IntrMask; -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrMask read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret)); return ret; } static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrStatus write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val)); #if 0 @@ -2027,9 +2566,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) { uint32_t ret = s->IntrStatus; -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrStatus read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret)); #if 0 @@ -2045,9 +2582,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: MultiIntr write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf000, s->MultiIntr); @@ -2059,9 +2594,7 @@ static uint32_t rtl8139_MultiIntr_read(RTL8139State *s) { uint32_t ret = s->MultiIntr; -#ifdef DEBUG_RTL8139 - printf("RTL8139: MultiIntr read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret)); return ret; } @@ -2109,15 +2642,11 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) break; case MediaStatus: /* ignore */ -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val)); break; case HltClk: -#ifdef DEBUG_RTL8139 - printf("RTL8139: HltClk write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val)); if (val == 'R') { s->clock_enabled = 1; @@ -2129,37 +2658,27 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) break; case TxThresh: -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxThresh write(b) val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val)); s->TxThresh = val; break; case TxPoll: -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll write(b) val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val)); if (val & (1 << 7)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll high priority transmission (not implemented)\n"); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n")); //rtl8139_cplus_transmit(s); } if (val & (1 << 6)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll normal priority transmission\n"); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n")); rtl8139_cplus_transmit(s); } break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val)); break; } } @@ -2195,20 +2714,14 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) rtl8139_BasicModeStatus_write(s, val); break; case NWayAdvert: -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayAdvert write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val)); s->NWayAdvert = val; break; case NWayLPAR: -#ifdef DEBUG_RTL8139 - printf("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val)); break; case NWayExpansion: -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayExpansion write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val)); s->NWayExpansion = val; break; @@ -2216,10 +2729,12 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) rtl8139_CpCmd_write(s, val); break; + case IntrMitigate: + rtl8139_IntrMitigate_write(s, val); + break; + default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); #ifdef TARGET_WORDS_BIGENDIAN rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); @@ -2241,9 +2756,7 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) switch (addr) { case RxMissed: -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxMissed clearing on write\n"); -#endif + DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n")); s->RxMissed = 0; break; @@ -2268,23 +2781,28 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) break; case RxRingAddrLO: -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing low bits write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val)); s->RxRingAddrLO = val; break; case RxRingAddrHI: -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing high bits write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val)); s->RxRingAddrHI = val; break; + case Timer: + DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n")); + s->TCTR = 0; + s->TCTR_base = qemu_get_clock(vm_clock); + break; + + case FlashReg: + DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val)); + s->TimerInt = val; + break; + default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); #ifdef TARGET_WORDS_BIGENDIAN rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); @@ -2342,43 +2860,31 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) case MediaStatus: ret = 0xd0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: MediaStatus read 0x%x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret)); break; case HltClk: ret = s->clock_enabled; -#ifdef DEBUG_RTL8139 - printf("RTL8139: HltClk read 0x%x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret)); break; case PCIRevisionID: - ret = 0x10; -#ifdef DEBUG_RTL8139 - printf("RTL8139: PCI Revision ID read 0x%x\n", ret); -#endif + ret = RTL8139_PCI_REVID; + DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret)); break; case TxThresh: ret = s->TxThresh; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret)); break; case 0x43: /* Part of TxConfig register. Windows driver tries to read it */ ret = s->TxConfig >> 24; -#ifdef DEBUG_RTL8139 - printf("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret)); break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented read(b) addr=0x%x\n", addr); -#endif + DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr)); ret = 0; break; } @@ -2411,6 +2917,10 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) ret = rtl8139_RxBufPtr_read(s); break; + case RxBufAddr: + ret = rtl8139_RxBufAddr_read(s); + break; + case BasicModeCtrl: ret = rtl8139_BasicModeCtrl_read(s); break; @@ -2419,27 +2929,25 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) break; case NWayAdvert: ret = s->NWayAdvert; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret)); break; case NWayLPAR: ret = s->NWayLPAR; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret)); break; case NWayExpansion: ret = s->NWayExpansion; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret)); break; case CpCmd: ret = rtl8139_CpCmd_read(s); break; + case IntrMitigate: + ret = rtl8139_IntrMitigate_read(s); + break; + case TxSummary: ret = rtl8139_TSAD_read(s); break; @@ -2449,9 +2957,7 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr); -#endif + DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); #ifdef TARGET_WORDS_BIGENDIAN ret = rtl8139_io_readb(opaque, addr) << 8; @@ -2461,9 +2967,7 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) ret |= rtl8139_io_readb(opaque, addr + 1) << 8; #endif -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret); -#endif + DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); break; } @@ -2482,9 +2986,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) case RxMissed: ret = s->RxMissed; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxMissed read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret)); break; case TxConfig: @@ -2509,22 +3011,26 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) case RxRingAddrLO: ret = s->RxRingAddrLO; -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret)); break; case RxRingAddrHI: ret = s->RxRingAddrHI; -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret)); + break; + + case Timer: + ret = s->TCTR; + DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret)); + break; + + case FlashReg: + ret = s->TimerInt; + DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret)); break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr); -#endif + DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); #ifdef TARGET_WORDS_BIGENDIAN ret = rtl8139_io_readb(opaque, addr) << 24; @@ -2538,9 +3044,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) ret |= rtl8139_io_readb(opaque, addr + 3) << 24; #endif -#ifdef DEBUG_RTL8139 - printf("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret); -#endif + DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); break; } @@ -2688,6 +3192,12 @@ static void rtl8139_save(QEMUFile* f,void* opaque) qemu_put_8s(f, &s->eeprom.eesk); qemu_put_8s(f, &s->eeprom.eedi); qemu_put_8s(f, &s->eeprom.eedo); + + qemu_put_be32s(f, &s->TCTR); + qemu_put_be32s(f, &s->TimerInt); + qemu_put_be64s(f, &s->TCTR_base); + + RTL8139TallyCounters_save(f, &s->tally_counters); } static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) @@ -2695,9 +3205,11 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) RTL8139State* s=(RTL8139State*)opaque; int i; - if (version_id != 1) + /* just 2 versions for now */ + if (version_id > 2) return -EINVAL; + /* saved since version 1 */ qemu_get_buffer(f, s->phys, 6); qemu_get_buffer(f, s->mult, 8); @@ -2769,6 +3281,25 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) qemu_get_8s(f, &s->eeprom.eedi); qemu_get_8s(f, &s->eeprom.eedo); + /* saved since version 2 */ + if (version_id >= 2) + { + qemu_get_be32s(f, &s->TCTR); + qemu_get_be32s(f, &s->TimerInt); + qemu_get_be64s(f, &s->TCTR_base); + + RTL8139TallyCounters_load(f, &s->tally_counters); + } + else + { + /* not saved, use default */ + s->TCTR = 0; + s->TimerInt = 0; + s->TCTR_base = 0; + + RTL8139TallyCounters_clear(&s->tally_counters); + } + return 0; } @@ -2817,6 +3348,59 @@ static CPUWriteMemoryFunc *rtl8139_mmio_write[3] = { rtl8139_mmio_writel, }; +static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time) +{ + int64_t next_time = current_time + + muldiv64(1, ticks_per_sec, PCI_FREQUENCY); + if (next_time <= current_time) + next_time = current_time + 1; + return next_time; +} + +#if RTL8139_ONBOARD_TIMER +static void rtl8139_timer(void *opaque) +{ + RTL8139State *s = opaque; + + int is_timeout = 0; + + int64_t curr_time; + uint32_t curr_tick; + + if (!s->clock_enabled) + { + DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n")); + return; + } + + curr_time = qemu_get_clock(vm_clock); + + curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec); + + if (s->TimerInt && curr_tick >= s->TimerInt) + { + if (s->TCTR < s->TimerInt || curr_tick < s->TCTR) + { + is_timeout = 1; + } + } + + s->TCTR = curr_tick; + +// DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR)); + + if (is_timeout) + { + DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR)); + s->IntrStatus |= PCSTimeout; + rtl8139_update_irq(s); + } + + qemu_mod_timer(s->timer, + rtl8139_get_next_tctr_time(s,curr_time)); +} +#endif /* RTL8139_ONBOARD_TIMER */ + void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) { PCIRTL8139State *d; @@ -2833,7 +3417,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) pci_conf[0x02] = 0x39; pci_conf[0x03] = 0x81; pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */ - pci_conf[0x08] = 0x20; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */ + pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */ pci_conf[0x0a] = 0x00; /* ethernet network controller */ pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; /* header_type */ @@ -2867,9 +3451,21 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) s->macaddr[3], s->macaddr[4], s->macaddr[5]); + + s->cplus_txbuffer = NULL; + s->cplus_txbuffer_len = 0; + s->cplus_txbuffer_offset = 0; /* XXX: instance number ? */ - register_savevm("rtl8139", 0, 1, rtl8139_save, rtl8139_load, s); + register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s); register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, &d->dev); + +#if RTL8139_ONBOARD_TIMER + s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); + + qemu_mod_timer(s->timer, + rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock))); +#endif /* RTL8139_ONBOARD_TIMER */ } + diff --git a/tools/ioemu/hw/sb16.c b/tools/ioemu/hw/sb16.c index f7b12e6116..04325ac031 100644 --- a/tools/ioemu/hw/sb16.c +++ b/tools/ioemu/hw/sb16.c @@ -193,6 +193,31 @@ static void aux_timer (void *opaque) #define DMA8_AUTO 1 #define DMA8_HIGH 2 +static void continue_dma8 (SB16State *s) +{ + if (s->freq > 0) { + audsettings_t as; + + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + as.endianness = 0; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "sb16", + s, + SB_audio_callback, + &as + ); + } + + control (s, 1); +} + static void dma_cmd8 (SB16State *s, int mask, int dma_len) { s->fmt = AUD_FMT_U8; @@ -201,7 +226,8 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->fmt_signed = 0; s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; if (-1 == s->time_const) { - s->freq = 11025; + if (s->freq <= 0) + s->freq = 11025; } else { int tmp = (256 - s->time_const); @@ -239,27 +265,7 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, s->block_size, s->dma_auto, s->fifo, s->highspeed); - if (s->freq) { - audsettings_t as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as, - 0 /* little endian */ - ); - } - - control (s, 1); + continue_dma8 (s); speaker (s, 1); } @@ -342,6 +348,7 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -349,8 +356,7 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } @@ -437,7 +443,7 @@ static void command (SB16State *s, uint8_t cmd) break; case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ - control (s, 1); + dma_cmd8 (s, DMA8_AUTO, -1); break; case 0x20: /* Direct ADC, Juice/PL */ @@ -531,7 +537,9 @@ static void command (SB16State *s, uint8_t cmd) break; case 0xd4: /* continue DMA operation. 8bit */ - control (s, 1); + /* KQ6 (or maybe Sierras audblst.drv in general) resets + the frequency between halt/continue */ + continue_dma8 (s); break; case 0xd5: /* halt DMA operation. 16bit */ @@ -765,7 +773,7 @@ static void complete (SB16State *s) ); } } - ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks); + ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks); } break; @@ -818,6 +826,33 @@ static void complete (SB16State *s) return; } +static void legacy_reset (SB16State *s) +{ + audsettings_t as; + + s->freq = 11025; + s->fmt_signed = 0; + s->fmt_bits = 8; + s->fmt_stereo = 0; + + as.freq = s->freq; + as.nchannels = 1; + as.fmt = AUD_FMT_U8; + as.endianness = 0; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "sb16", + s, + SB_audio_callback, + &as + ); + + /* Not sure about that... */ + /* AUD_set_active_out (s->voice, 1); */ +} + static void reset (SB16State *s) { pic_set_irq (s->irq, 0); @@ -841,6 +876,7 @@ static void reset (SB16State *s) dsp_out_data(s, 0xaa); speaker (s, 0); control (s, 0); + legacy_reset (s); } static IO_WRITE_PROTO (dsp_write) @@ -1335,6 +1371,7 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -1342,8 +1379,7 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } diff --git a/tools/ioemu/hw/scsi-disk.c b/tools/ioemu/hw/scsi-disk.c new file mode 100644 index 0000000000..decab1f42b --- /dev/null +++ b/tools/ioemu/hw/scsi-disk.c @@ -0,0 +1,478 @@ +/* + * SCSI Device emulation + * + * Copyright (c) 2006 CodeSourcery. + * Based on code by Fabrice Bellard + * + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +//#define DEBUG_SCSI + +#ifdef DEBUG_SCSI +#define DPRINTF(fmt, args...) \ +do { printf("scsi-disk: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define BADF(fmt, args...) \ +do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) + +#include "vl.h" + +#define SENSE_NO_SENSE 0 +#define SENSE_ILLEGAL_REQUEST 5 + +struct SCSIDevice +{ + int command; + uint32_t tag; + BlockDriverState *bdrv; + /* The qemu block layer uses a fixed 512 byte sector size. + This is the number of 512 byte blocks in a single scsi sector. */ + int cluster_size; + /* When transfering data buf_pos and buf_len contain a partially + transferred block of data (or response to a command), and + sector/sector_count identify any remaining sectors. + Both sector and sector_count are in terms of qemu 512 byte blocks. */ + /* ??? We should probably keep track of whether the data trasfer is + a read or a write. Currently we rely on the host getting it right. */ + int sector; + int sector_count; + int buf_pos; + int buf_len; + int sense; + char buf[512]; + scsi_completionfn completion; + void *opaque; +}; + +static void scsi_command_complete(SCSIDevice *s, int sense) +{ + s->sense = sense; + s->completion(s->opaque, s->tag, sense); +} + +/* Read data from a scsi device. Returns nonzero on failure. */ +int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) +{ + uint32_t n; + + DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count); + if (s->buf_len == 0 && s->sector_count == 0) + return 1; + + if (s->buf_len) { + n = s->buf_len; + if (n > len) + n = len; + memcpy(data, s->buf + s->buf_pos, n); + s->buf_pos += n; + s->buf_len -= n; + data += n; + len -= n; + if (s->buf_len == 0) + s->buf_pos = 0; + } + + n = len / 512; + if (n > s->sector_count) + n = s->sector_count; + + if (n != 0) { + bdrv_read(s->bdrv, s->sector, data, n); + data += n * 512; + len -= n * 512; + s->sector += n; + s->sector_count -= n; + } + + if (len && s->sector_count) { + bdrv_read(s->bdrv, s->sector, s->buf, 1); + s->sector++; + s->sector_count--; + s->buf_pos = 0; + s->buf_len = 512; + /* Recurse to complete the partial read. */ + return scsi_read_data(s, data, len); + } + + if (len != 0) + return 1; + + if (s->buf_len == 0 && s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + + return 0; +} + +/* Read data to a scsi device. Returns nonzero on failure. */ +int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) +{ + uint32_t n; + + DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count); + if (s->buf_pos != 0) { + BADF("Bad state on write\n"); + return 1; + } + + if (s->sector_count == 0) + return 1; + + if (s->buf_len != 0 || len < 512) { + n = 512 - s->buf_len; + if (n > len) + n = len; + + memcpy(s->buf + s->buf_len, data, n); + data += n; + s->buf_len += n; + len -= n; + if (s->buf_len == 512) { + /* A full sector has been accumulated. Write it to disk. */ + bdrv_write(s->bdrv, s->sector, s->buf, 1); + s->buf_len = 0; + s->sector++; + s->sector_count--; + } + } + + n = len / 512; + if (n > s->sector_count) + n = s->sector_count; + + if (n != 0) { + bdrv_write(s->bdrv, s->sector, data, n); + data += n * 512; + len -= n * 512; + s->sector += n; + s->sector_count -= n; + } + + if (len >= 512) + return 1; + + if (len && s->sector_count) { + /* Recurse to complete the partial write. */ + return scsi_write_data(s, data, len); + } + + if (len != 0) + return 1; + + if (s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + + return 0; +} + +/* Execute a scsi command. Returns the length of the data expected by the + command. This will be Positive for data transfers from the device + (eg. disk reads), negative for transfers to the device (eg. disk writes), + and zero if the command does not transfer any data. */ + +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) +{ + int64_t nb_sectors; + uint32_t lba; + uint32_t len; + int cmdlen; + int is_write; + + s->command = buf[0]; + s->tag = tag; + s->sector_count = 0; + s->buf_pos = 0; + s->buf_len = 0; + is_write = 0; + DPRINTF("Command: 0x%02x", buf[0]); + switch (s->command >> 5) { + case 0: + lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); + len = buf[4]; + cmdlen = 6; + break; + case 1: + case 2: + lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); + len = buf[8] | (buf[7] << 8); + cmdlen = 10; + break; + case 4: + lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); + len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); + cmdlen = 16; + break; + case 5: + lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); + len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); + cmdlen = 12; + break; + default: + BADF("Unsupported command length, command %x\n", s->command); + goto fail; + } +#ifdef DEBUG_SCSI + { + int i; + for (i = 1; i < cmdlen; i++) { + printf(" 0x%02x", buf[i]); + } + printf("\n"); + } +#endif + if (lun || buf[1] >> 5) { + /* Only LUN 0 supported. */ + DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); + goto fail; + } + switch (s->command) { + case 0x0: + DPRINTF("Test Unit Ready\n"); + break; + case 0x03: + DPRINTF("Request Sense (len %d)\n", len); + if (len < 4) + goto fail; + memset(buf, 0, 4); + s->buf[0] = 0xf0; + s->buf[1] = 0; + s->buf[2] = s->sense; + s->buf_len = 4; + break; + case 0x12: + DPRINTF("Inquiry (len %d)\n", len); + if (len < 36) { + BADF("Inquiry buffer too small (%d)\n", len); + } + memset(s->buf, 0, 36); + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + s->buf[0] = 5; + s->buf[1] = 0x80; + memcpy(&s->buf[16], "QEMU CD-ROM ", 16); + } else { + s->buf[0] = 0; + memcpy(&s->buf[16], "QEMU HARDDISK ", 16); + } + memcpy(&s->buf[8], "QEMU ", 8); + memcpy(&s->buf[32], QEMU_VERSION, 4); + /* Identify device as SCSI-3 rev 1. + Some later commands are also implemented. */ + s->buf[2] = 3; + s->buf[3] = 2; /* Format 2 */ + s->buf[4] = 32; + s->buf_len = 36; + break; + case 0x16: + DPRINTF("Reserve(6)\n"); + if (buf[1] & 1) + goto fail; + break; + case 0x17: + DPRINTF("Release(6)\n"); + if (buf[1] & 1) + goto fail; + break; + case 0x1a: + case 0x5a: + { + char *p; + int page; + + page = buf[2] & 0x3f; + DPRINTF("Mode Sense (page %d, len %d)\n", page, len); + p = s->buf; + memset(p, 0, 4); + s->buf[1] = 0; /* Default media type. */ + s->buf[3] = 0; /* Block descriptor length. */ + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + s->buf[2] = 0x80; /* Readonly. */ + } + p += 4; + if ((page == 8 || page == 0x3f)) { + /* Caching page. */ + p[0] = 8; + p[1] = 0x12; + p[2] = 4; /* WCE */ + p += 19; + } + if ((page == 0x3f || page == 0x2a) + && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) { + /* CD Capabilities and Mechanical Status page. */ + p[0] = 0x2a; + p[1] = 0x14; + p[2] = 3; // CD-R & CD-RW read + p[3] = 0; // Writing not supported + p[4] = 0x7f; /* Audio, composite, digital out, + mode 2 form 1&2, multi session */ + p[5] = 0xff; /* CD DA, DA accurate, RW supported, + RW corrected, C2 errors, ISRC, + UPC, Bar code */ + p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0); + /* Locking supported, jumper present, eject, tray */ + p[7] = 0; /* no volume & mute control, no + changer */ + p[8] = (50 * 176) >> 8; // 50x read speed + p[9] = (50 * 176) & 0xff; + p[10] = 0 >> 8; // No volume + p[11] = 0 & 0xff; + p[12] = 2048 >> 8; // 2M buffer + p[13] = 2048 & 0xff; + p[14] = (16 * 176) >> 8; // 16x read speed current + p[15] = (16 * 176) & 0xff; + p[18] = (16 * 176) >> 8; // 16x write speed + p[19] = (16 * 176) & 0xff; + p[20] = (16 * 176) >> 8; // 16x write speed current + p[21] = (16 * 176) & 0xff; + p += 21; + } + s->buf_len = p - s->buf; + s->buf[0] = s->buf_len - 4; + if (s->buf_len > len) + s->buf_len = len; + } + break; + case 0x1b: + DPRINTF("Start Stop Unit\n"); + break; + case 0x1e: + DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); + bdrv_set_locked(s->bdrv, buf[4] & 1); + break; + case 0x25: + DPRINTF("Read Capacity\n"); + /* The normal LEN field for this command is zero. */ + memset(s->buf, 0, 8); + bdrv_get_geometry(s->bdrv, &nb_sectors); + s->buf[0] = (nb_sectors >> 24) & 0xff; + s->buf[1] = (nb_sectors >> 16) & 0xff; + s->buf[2] = (nb_sectors >> 8) & 0xff; + s->buf[3] = nb_sectors & 0xff; + s->buf[4] = 0; + s->buf[5] = 0; + s->buf[6] = s->cluster_size * 2; + s->buf[7] = 0; + s->buf_len = 8; + break; + case 0x08: + case 0x28: + DPRINTF("Read (sector %d, count %d)\n", lba, len); + s->sector = lba * s->cluster_size; + s->sector_count = len * s->cluster_size; + break; + case 0x0a: + case 0x2a: + DPRINTF("Write (sector %d, count %d)\n", lba, len); + s->sector = lba * s->cluster_size; + s->sector_count = len * s->cluster_size; + is_write = 1; + break; + case 0x35: + DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len); + bdrv_flush(s->bdrv); + break; + case 0x43: + { + int start_track, format, msf, toclen; + + msf = buf[1] & 2; + format = buf[2] & 0xf; + start_track = buf[6]; + bdrv_get_geometry(s->bdrv, &nb_sectors); + DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); + switch(format) { + case 0: + toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); + break; + case 1: + /* multi session : only a single session defined */ + toclen = 12; + memset(s->buf, 0, 12); + s->buf[1] = 0x0a; + s->buf[2] = 0x01; + s->buf[3] = 0x01; + break; + case 2: + toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); + break; + default: + goto error_cmd; + } + if (toclen > 0) { + if (len > toclen) + len = toclen; + s->buf_len = len; + break; + } + error_cmd: + DPRINTF("Read TOC error\n"); + goto fail; + } + case 0x46: + DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); + memset(s->buf, 0, 8); + /* ??? This shoud probably return much more information. For now + just return the basic header indicating the CD-ROM profile. */ + s->buf[7] = 8; // CD-ROM + s->buf_len = 8; + break; + case 0x56: + DPRINTF("Reserve(10)\n"); + if (buf[1] & 3) + goto fail; + break; + case 0x57: + DPRINTF("Release(10)\n"); + if (buf[1] & 3) + goto fail; + break; + case 0xa0: + DPRINTF("Report LUNs (len %d)\n", len); + if (len < 16) + goto fail; + memset(s->buf, 0, 16); + s->buf[3] = 8; + s->buf_len = 16; + break; + default: + DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); + fail: + scsi_command_complete(s, SENSE_ILLEGAL_REQUEST); + return 0; + } + if (s->sector_count == 0 && s->buf_len == 0) { + scsi_command_complete(s, SENSE_NO_SENSE); + } + len = s->sector_count * 512 + s->buf_len; + return is_write ? -len : len; +} + +void scsi_disk_destroy(SCSIDevice *s) +{ + bdrv_close(s->bdrv); + qemu_free(s); +} + +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + scsi_completionfn completion, + void *opaque) +{ + SCSIDevice *s; + + s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); + s->bdrv = bdrv; + s->completion = completion; + s->opaque = opaque; + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + s->cluster_size = 4; + } else { + s->cluster_size = 1; + } + + return s; +} + diff --git a/tools/ioemu/hw/sh7750.c b/tools/ioemu/hw/sh7750.c index 041e3eed1b..21f9bc0aee 100644 --- a/tools/ioemu/hw/sh7750.c +++ b/tools/ioemu/hw/sh7750.c @@ -124,7 +124,7 @@ static void start_timer0(SH7750State * s) s->periph_freq); if (next == now) next = now + 1; - fprintf(stderr, "now=%016llx, next=%016llx\n", now, next); + fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); fprintf(stderr, "timer will underflow in %f seconds\n", (float) (next - now) / (float) ticks_per_sec); diff --git a/tools/ioemu/hw/slavio_intctl.c b/tools/ioemu/hw/slavio_intctl.c index e43151fad8..288fb50f0a 100644 --- a/tools/ioemu/hw/slavio_intctl.c +++ b/tools/ioemu/hw/slavio_intctl.c @@ -203,7 +203,7 @@ void slavio_irq_info(void *opaque) for (i = 0; i < 32; i++) { count = s->irq_count[i]; if (count > 0) - term_printf("%2d: %lld\n", i, count); + term_printf("%2d: %" PRId64 "\n", i, count); } #endif } diff --git a/tools/ioemu/hw/slavio_timer.c b/tools/ioemu/hw/slavio_timer.c index d75a76a636..976f0d4db4 100644 --- a/tools/ioemu/hw/slavio_timer.c +++ b/tools/ioemu/hw/slavio_timer.c @@ -100,7 +100,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) // Convert remaining counter ticks to CPU ticks s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); - DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); + DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); if (s->mode != 1) pic_set_irq_cpu(s->irq, out, s->cpu); diff --git a/tools/ioemu/hw/sun4m.c b/tools/ioemu/hw/sun4m.c index 3619005d71..203732f216 100644 --- a/tools/ioemu/hw/sun4m.c +++ b/tools/ioemu/hw/sun4m.c @@ -28,8 +28,7 @@ #define INITRD_LOAD_ADDR 0x00800000 #define PROM_SIZE_MAX (256 * 1024) #define PROM_ADDR 0xffd00000 -#define PROM_FILENAMEB "proll.bin" -#define PROM_FILENAMEE "proll.elf" +#define PROM_FILENAME "openbios-sparc32" #define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 @@ -183,6 +182,11 @@ void pic_set_irq(int irq, int level) slavio_pic_set_irq(slavio_intctl, irq, level); } +void pic_set_irq_new(void *opaque, int irq, int level) +{ + pic_set_irq(irq, level); +} + void pic_set_irq_cpu(int irq, int level, unsigned int cpu) { slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); @@ -268,12 +272,8 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL); - if (ret < 0) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_image(buf, phys_ram_base + prom_offset); - } if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); diff --git a/tools/ioemu/hw/sun4u.c b/tools/ioemu/hw/sun4u.c index 208d3dd63a..6d413691db 100644 --- a/tools/ioemu/hw/sun4u.c +++ b/tools/ioemu/hw/sun4u.c @@ -27,13 +27,12 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 -#define PROM_SIZE_MAX (256 * 1024) +#define PROM_SIZE_MAX (512 * 1024) #define PROM_ADDR 0x1fff0000000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL #define VGA_BASE (APB_MEM_BASE + 0x400000ULL) -#define PROM_FILENAMEB "proll-sparc64.bin" -#define PROM_FILENAMEE "proll-sparc64.elf" +#define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 /* TSC handling */ @@ -282,12 +281,8 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL); - if (ret < 0) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_image(buf, phys_ram_base + prom_offset); - } if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -329,12 +324,9 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } } } - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); isa_mem_base = VGA_BASE; - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); - cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size); - //pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); + pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff --git a/tools/ioemu/hw/unin_pci.c b/tools/ioemu/hw/unin_pci.c new file mode 100644 index 0000000000..a7e3600047 --- /dev/null +++ b/tools/ioemu/hw/unin_pci.c @@ -0,0 +1,261 @@ +/* + * QEMU Uninorth PCI host (for all Mac99 and newer machines) + * + * Copyright (c) 2006 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState UNINState; + +static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + UNINState *s = opaque; + int i; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + for (i = 11; i < 32; i++) { + if ((val & (1 << i)) != 0) + break; + } +#if 0 + s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); +#else + s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); +#endif +} + +static uint32_t pci_unin_main_config_readl (void *opaque, + target_phys_addr_t addr) +{ + UNINState *s = opaque; + uint32_t val; + int devfn; + + devfn = (s->config_reg >> 8) & 0xFF; + val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { + &pci_unin_main_config_writel, + &pci_unin_main_config_writel, + &pci_unin_main_config_writel, +}; + +static CPUReadMemoryFunc *pci_unin_main_config_read[] = { + &pci_unin_main_config_readl, + &pci_unin_main_config_readl, + &pci_unin_main_config_readl, +}; + +static CPUWriteMemoryFunc *pci_unin_main_write[] = { + &pci_host_data_writeb, + &pci_host_data_writew, + &pci_host_data_writel, +}; + +static CPUReadMemoryFunc *pci_unin_main_read[] = { + &pci_host_data_readb, + &pci_host_data_readw, + &pci_host_data_readl, +}; + +#if 0 + +static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + UNINState *s = opaque; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + s->config_reg = 0x80000000 | (val & ~0x00000001); +} + +static uint32_t pci_unin_config_readl (void *opaque, + target_phys_addr_t addr) +{ + UNINState *s = opaque; + uint32_t val; + + val = (s->config_reg | 0x00000001) & ~0x80000000; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_config_write[] = { + &pci_unin_config_writel, + &pci_unin_config_writel, + &pci_unin_config_writel, +}; + +static CPUReadMemoryFunc *pci_unin_config_read[] = { + &pci_unin_config_readl, + &pci_unin_config_readl, + &pci_unin_config_readl, +}; + +static CPUWriteMemoryFunc *pci_unin_write[] = { + &pci_host_pci_writeb, + &pci_host_pci_writew, + &pci_host_pci_writel, +}; + +static CPUReadMemoryFunc *pci_unin_read[] = { + &pci_host_pci_readb, + &pci_host_pci_readw, + &pci_host_pci_readl, +}; +#endif + +static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_pmac_init(void *pic) +{ + UNINState *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data; + + /* Use values found on a real PowerMac */ + /* Uninorth main bus */ + s = qemu_mallocz(sizeof(UNINState)); + s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3); + + pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, + pci_unin_main_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, + pci_unin_main_write, s); + cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); + d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice), + 11 << 3, NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x1F; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer + +#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly + /* pci-to-pci bridge */ + d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, + NULL, NULL); + d->config[0x00] = 0x11; // vendor_id : TI + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x05; // revision + d->config[0x0A] = 0x04; // class_sub = pci2pci + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x20; // latency_timer + d->config[0x0E] = 0x01; // header_type + + d->config[0x18] = 0x01; // primary_bus + d->config[0x19] = 0x02; // secondary_bus + d->config[0x1A] = 0x02; // subordinate_bus + d->config[0x1B] = 0x20; // secondary_latency_timer + d->config[0x1C] = 0x11; // io_base + d->config[0x1D] = 0x01; // io_limit + d->config[0x20] = 0x00; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x00; // memory_limit + d->config[0x23] = 0x80; + d->config[0x24] = 0x01; // prefetchable_memory_base + d->config[0x25] = 0x80; + d->config[0x26] = 0xF1; // prefectchable_memory_limit + d->config[0x27] = 0x7F; + // d->config[0x34] = 0xdc // capabilities_pointer +#endif +#if 0 // XXX: not needed for now + /* Uninorth AGP bus */ + s = &pci_bridge[1]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_unin_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_unin_write, s); + cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, + NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x20; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + // d->config[0x34] = 0x80; // capabilities_pointer +#endif + +#if 0 // XXX: not needed for now + /* Uninorth internal bus */ + s = &pci_bridge[2]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_unin_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_unin_write, s); + cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north internal", sizeof(PCIDevice), + 3, 11 << 3, NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x1E; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer +#endif + return s->bus; +} + diff --git a/tools/ioemu/hw/usb-hid.c b/tools/ioemu/hw/usb-hid.c index 17160ebe32..8fc0b744b7 100644 --- a/tools/ioemu/hw/usb-hid.c +++ b/tools/ioemu/hw/usb-hid.c @@ -500,6 +500,14 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, return ret; } +static void usb_mouse_handle_destroy(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + qemu_add_mouse_event_handler(NULL, NULL, 0); + qemu_free(s); +} + USBDevice *usb_tablet_init(void) { USBMouseState *s; @@ -513,8 +521,11 @@ USBDevice *usb_tablet_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_TABLET; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); + return (USBDevice *)s; } @@ -531,7 +542,10 @@ USBDevice *usb_mouse_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_MOUSE; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + return (USBDevice *)s; } diff --git a/tools/ioemu/hw/usb-hub.c b/tools/ioemu/hw/usb-hub.c index fd916128cf..8350931be6 100644 --- a/tools/ioemu/hw/usb-hub.c +++ b/tools/ioemu/hw/usb-hub.c @@ -152,7 +152,7 @@ static const uint8_t qemu_hub_config_descriptor[] = { static const uint8_t qemu_hub_hub_descriptor[] = { - 0x09, /* u8 bLength; */ + 0x00, /* u8 bLength; patched in later */ 0x29, /* u8 bDescriptorType; Hub-descriptor */ 0x00, /* u8 bNbrPorts; (patched later) */ 0x0a, /* u16 wHubCharacteristics; */ @@ -179,6 +179,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) else port->wPortStatus &= ~PORT_STAT_LOW_SPEED; port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); } else { dev = port->port.dev; if (dev) { @@ -188,6 +191,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); port->port.dev = NULL; } } @@ -417,6 +423,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + data[0] = ret; break; } default: @@ -516,7 +523,14 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); } -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) +static void usb_hub_handle_destroy(USBDevice *dev) +{ + USBHubState *s = (USBHubState *)dev; + + qemu_free(s); +} + +USBDevice *usb_hub_init(int nb_ports) { USBHubState *s; USBHubPort *port; @@ -534,16 +548,16 @@ USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) s->dev.handle_reset = usb_hub_handle_reset; s->dev.handle_control = usb_hub_handle_control; s->dev.handle_data = usb_hub_handle_data; + s->dev.handle_destroy = usb_hub_handle_destroy; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub"); s->nb_ports = nb_ports; for(i = 0; i < s->nb_ports; i++) { port = &s->ports[i]; + qemu_register_usb_port(&port->port, s, i, usb_hub_attach); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; - port->port.attach = usb_hub_attach; - port->port.opaque = s; - port->port.index = i; - usb_ports[i] = &port->port; } return (USBDevice *)s; } diff --git a/tools/ioemu/hw/usb-msd.c b/tools/ioemu/hw/usb-msd.c new file mode 100644 index 0000000000..ff2047d4b2 --- /dev/null +++ b/tools/ioemu/hw/usb-msd.c @@ -0,0 +1,402 @@ +/* + * USB Mass Storage Device emulation + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +#include "vl.h" + +//#define DEBUG_MSD + +#ifdef DEBUG_MSD +#define DPRINTF(fmt, args...) \ +do { printf("usb-msd: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +/* USB requests. */ +#define MassStorageReset 0xff +#define GetMaxLun 0xfe + +enum USBMSDMode { + USB_MSDM_CBW, /* Command Block. */ + USB_MSDM_DATAOUT, /* Tranfer data to device. */ + USB_MSDM_DATAIN, /* Transfer data from device. */ + USB_MSDM_CSW /* Command Status. */ +}; + +typedef struct { + USBDevice dev; + enum USBMSDMode mode; + uint32_t data_len; + uint32_t tag; + SCSIDevice *scsi_dev; + int result; +} MSDState; + +static const uint8_t qemu_msd_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + /* Vendor and product id are arbitrary. */ + 0x00, 0x00, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x03, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_msd_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x20, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* u8 MaxPower; */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0x08, /* u8 if_bInterfaceClass; MASS STORAGE */ + 0x06, /* u8 if_bInterfaceSubClass; SCSI */ + 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ + 0x00, /* u8 if_iInterface; */ + + /* Bulk-In endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00, /* u8 ep_bInterval; */ + + /* Bulk-Out endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00 /* u8 ep_bInterval; */ +}; + +static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) +{ + MSDState *s = (MSDState *)opaque; + + DPRINTF("Command complete\n"); + s->result = fail; + s->mode = USB_MSDM_CSW; +} + +static void usb_msd_handle_reset(USBDevice *dev) +{ + MSDState *s = (MSDState *)dev; + + DPRINTF("Reset\n"); + s->mode = USB_MSDM_CBW; +} + +static int usb_msd_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + MSDState *s = (MSDState *)dev; + int ret = 0; + + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_msd_dev_descriptor, + sizeof(qemu_msd_dev_descriptor)); + ret = sizeof(qemu_msd_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_msd_config_descriptor, + sizeof(qemu_msd_config_descriptor)); + ret = sizeof(qemu_msd_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB HARDDRIVE"); + break; + case 3: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == 0 && index != 0x81) { /* clear ep halt */ + goto fail; + } + ret = 0; + break; + /* Class specific requests. */ + case MassStorageReset: + /* Reset state ready for the next CBW. */ + s->mode = USB_MSDM_CBW; + ret = 0; + break; + case GetMaxLun: + data[0] = 0; + ret = 1; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +struct usb_msd_cbw { + uint32_t sig; + uint32_t tag; + uint32_t data_len; + uint8_t flags; + uint8_t lun; + uint8_t cmd_len; + uint8_t cmd[16]; +}; + +struct usb_msd_csw { + uint32_t sig; + uint32_t tag; + uint32_t residue; + uint8_t status; +}; + +static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, + uint8_t *data, int len) +{ + MSDState *s = (MSDState *)dev; + int ret = 0; + struct usb_msd_cbw cbw; + struct usb_msd_csw csw; + + switch (pid) { + case USB_TOKEN_OUT: + if (devep != 2) + goto fail; + + switch (s->mode) { + case USB_MSDM_CBW: + if (len != 31) { + fprintf(stderr, "usb-msd: Bad CBW size"); + goto fail; + } + memcpy(&cbw, data, 31); + if (le32_to_cpu(cbw.sig) != 0x43425355) { + fprintf(stderr, "usb-msd: Bad signature %08x\n", + le32_to_cpu(cbw.sig)); + goto fail; + } + DPRINTF("Command on LUN %d\n", cbw.lun); + if (cbw.lun != 0) { + fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); + goto fail; + } + s->tag = le32_to_cpu(cbw.tag); + s->data_len = le32_to_cpu(cbw.data_len); + if (s->data_len == 0) { + s->mode = USB_MSDM_CSW; + } else if (cbw.flags & 0x80) { + s->mode = USB_MSDM_DATAIN; + } else { + s->mode = USB_MSDM_DATAOUT; + } + DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", + s->tag, cbw.flags, cbw.cmd_len, s->data_len); + scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + ret = len; + break; + + case USB_MSDM_DATAOUT: + DPRINTF("Data out %d/%d\n", len, s->data_len); + if (len > s->data_len) + goto fail; + + if (scsi_write_data(s->scsi_dev, data, len)) + goto fail; + + s->data_len -= len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + ret = len; + break; + + default: + DPRINTF("Unexpected write (len %d)\n", len); + goto fail; + } + break; + + case USB_TOKEN_IN: + if (devep != 1) + goto fail; + + switch (s->mode) { + case USB_MSDM_CSW: + DPRINTF("Command status %d tag 0x%x, len %d\n", + s->result, s->tag, len); + if (len < 13) + goto fail; + + csw.sig = cpu_to_le32(0x53425355); + csw.tag = cpu_to_le32(s->tag); + csw.residue = 0; + csw.status = s->result; + memcpy(data, &csw, 13); + ret = 13; + s->mode = USB_MSDM_CBW; + break; + + case USB_MSDM_DATAIN: + DPRINTF("Data in %d/%d\n", len, s->data_len); + if (len > s->data_len) + len = s->data_len; + + if (scsi_read_data(s->scsi_dev, data, len)) + goto fail; + + s->data_len -= len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + ret = len; + break; + + default: + DPRINTF("Unexpected read (len %d)\n", len); + goto fail; + } + break; + + default: + DPRINTF("Bad token\n"); + fail: + ret = USB_RET_STALL; + break; + } + + return ret; +} + +static void usb_msd_handle_destroy(USBDevice *dev) +{ + MSDState *s = (MSDState *)dev; + + scsi_disk_destroy(s->scsi_dev); + qemu_free(s); +} + +USBDevice *usb_msd_init(const char *filename) +{ + MSDState *s; + BlockDriverState *bdrv; + + s = qemu_mallocz(sizeof(MSDState)); + if (!s) + return NULL; + + bdrv = bdrv_new("usb"); + bdrv_open(bdrv, filename, 0); + + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_msd_handle_reset; + s->dev.handle_control = usb_msd_handle_control; + s->dev.handle_data = usb_msd_handle_data; + s->dev.handle_destroy = usb_msd_handle_destroy; + + snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", + filename); + + s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); + usb_msd_handle_reset((USBDevice *)s); + return (USBDevice *)s; +} diff --git a/tools/ioemu/hw/usb-ohci.c b/tools/ioemu/hw/usb-ohci.c new file mode 100644 index 0000000000..e87d9da70a --- /dev/null +++ b/tools/ioemu/hw/usb-ohci.c @@ -0,0 +1,1190 @@ +/* + * QEMU USB OHCI Emulation + * Copyright (c) 2004 Gianni Tedesco + * Copyright (c) 2006 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * o Isochronous transfers + * o Allocate bandwidth in frames properly + * o Disable timers when nothing needs to be done, or remove timer usage + * all together. + * o Handle unrecoverable errors properly + * o BIOS work to boot from USB storage +*/ + +#include "vl.h" + +//#define DEBUG_OHCI +/* Dump packet contents. */ +//#define DEBUG_PACKET +/* This causes frames to occur 1000x slower */ +//#define OHCI_TIME_WARP 1 + +#ifdef DEBUG_OHCI +#define dprintf printf +#else +#define dprintf(...) +#endif + +/* Number of Downstream Ports on the root hub. */ + +#define OHCI_MAX_PORTS 15 + +static int64_t usb_frame_time; +static int64_t usb_bit_time; + +typedef struct OHCIPort { + USBPort port; + uint32_t ctrl; +} OHCIPort; + +typedef struct { + struct PCIDevice pci_dev; + target_phys_addr_t mem_base; + int mem; + int num_ports; + + QEMUTimer *eof_timer; + int64_t sof_time; + + /* OHCI state */ + /* Control partition */ + uint32_t ctl, status; + uint32_t intr_status; + uint32_t intr; + + /* memory pointer partition */ + uint32_t hcca; + uint32_t ctrl_head, ctrl_cur; + uint32_t bulk_head, bulk_cur; + uint32_t per_cur; + uint32_t done; + int done_count; + + /* Frame counter partition */ + uint32_t fsmps:15; + uint32_t fit:1; + uint32_t fi:14; + uint32_t frt:1; + uint16_t frame_number; + uint16_t padding; + uint32_t pstart; + uint32_t lst; + + /* Root Hub partition */ + uint32_t rhdesc_a, rhdesc_b; + uint32_t rhstatus; + OHCIPort rhport[OHCI_MAX_PORTS]; +} OHCIState; + +/* Host Controller Communications Area */ +struct ohci_hcca { + uint32_t intr[32]; + uint16_t frame, pad; + uint32_t done; +}; + +/* Bitfields for the first word of an Endpoint Desciptor. */ +#define OHCI_ED_FA_SHIFT 0 +#define OHCI_ED_FA_MASK (0x7f<> OHCI_##field##_SHIFT) + +#define OHCI_SET_BM(val, field, newval) do { \ + val &= ~OHCI_##field##_MASK; \ + val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ + } while(0) + +/* endpoint descriptor */ +struct ohci_ed { + uint32_t flags; + uint32_t tail; + uint32_t head; + uint32_t next; +}; + +/* General transfer descriptor */ +struct ohci_td { + uint32_t flags; + uint32_t cbp; + uint32_t next; + uint32_t be; +}; + +#define USB_HZ 12000000 + +/* OHCI Local stuff */ +#define OHCI_CTL_CBSR ((1<<0)|(1<<1)) +#define OHCI_CTL_PLE (1<<2) +#define OHCI_CTL_IE (1<<3) +#define OHCI_CTL_CLE (1<<4) +#define OHCI_CTL_BLE (1<<5) +#define OHCI_CTL_HCFS ((1<<6)|(1<<7)) +#define OHCI_USB_RESET 0x00 +#define OHCI_USB_RESUME 0x40 +#define OHCI_USB_OPERATIONAL 0x80 +#define OHCI_USB_SUSPEND 0xc0 +#define OHCI_CTL_IR (1<<8) +#define OHCI_CTL_RWC (1<<9) +#define OHCI_CTL_RWE (1<<10) + +#define OHCI_STATUS_HCR (1<<0) +#define OHCI_STATUS_CLF (1<<1) +#define OHCI_STATUS_BLF (1<<2) +#define OHCI_STATUS_OCR (1<<3) +#define OHCI_STATUS_SOC ((1<<6)|(1<<7)) + +#define OHCI_INTR_SO (1<<0) /* Scheduling overrun */ +#define OHCI_INTR_WD (1<<1) /* HcDoneHead writeback */ +#define OHCI_INTR_SF (1<<2) /* Start of frame */ +#define OHCI_INTR_RD (1<<3) /* Resume detect */ +#define OHCI_INTR_UE (1<<4) /* Unrecoverable error */ +#define OHCI_INTR_FNO (1<<5) /* Frame number overflow */ +#define OHCI_INTR_RHSC (1<<6) /* Root hub status change */ +#define OHCI_INTR_OC (1<<30) /* Ownership change */ +#define OHCI_INTR_MIE (1<<31) /* Master Interrupt Enable */ + +#define OHCI_HCCA_SIZE 0x100 +#define OHCI_HCCA_MASK 0xffffff00 + +#define OHCI_EDPTR_MASK 0xfffffff0 + +#define OHCI_FMI_FI 0x00003fff +#define OHCI_FMI_FSMPS 0xffff0000 +#define OHCI_FMI_FIT 0x80000000 + +#define OHCI_FR_RT (1<<31) + +#define OHCI_LS_THRESH 0x628 + +#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ +#define OHCI_RHA_PSM (1<<8) +#define OHCI_RHA_NPS (1<<9) +#define OHCI_RHA_DT (1<<10) +#define OHCI_RHA_OCPM (1<<11) +#define OHCI_RHA_NOCP (1<<12) +#define OHCI_RHA_POTPGT_MASK 0xff000000 + +#define OHCI_RHS_LPS (1<<0) +#define OHCI_RHS_OCI (1<<1) +#define OHCI_RHS_DRWE (1<<15) +#define OHCI_RHS_LPSC (1<<16) +#define OHCI_RHS_OCIC (1<<17) +#define OHCI_RHS_CRWE (1<<31) + +#define OHCI_PORT_CCS (1<<0) +#define OHCI_PORT_PES (1<<1) +#define OHCI_PORT_PSS (1<<2) +#define OHCI_PORT_POCI (1<<3) +#define OHCI_PORT_PRS (1<<4) +#define OHCI_PORT_PPS (1<<8) +#define OHCI_PORT_LSDA (1<<9) +#define OHCI_PORT_CSC (1<<16) +#define OHCI_PORT_PESC (1<<17) +#define OHCI_PORT_PSSC (1<<18) +#define OHCI_PORT_OCIC (1<<19) +#define OHCI_PORT_PRSC (1<<20) +#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ + |OHCI_PORT_OCIC|OHCI_PORT_PRSC) + +#define OHCI_TD_DIR_SETUP 0x0 +#define OHCI_TD_DIR_OUT 0x1 +#define OHCI_TD_DIR_IN 0x2 +#define OHCI_TD_DIR_RESERVED 0x3 + +#define OHCI_CC_NOERROR 0x0 +#define OHCI_CC_CRC 0x1 +#define OHCI_CC_BITSTUFFING 0x2 +#define OHCI_CC_DATATOGGLEMISMATCH 0x3 +#define OHCI_CC_STALL 0x4 +#define OHCI_CC_DEVICENOTRESPONDING 0x5 +#define OHCI_CC_PIDCHECKFAILURE 0x6 +#define OHCI_CC_UNDEXPETEDPID 0x7 +#define OHCI_CC_DATAOVERRUN 0x8 +#define OHCI_CC_DATAUNDERRUN 0x9 +#define OHCI_CC_BUFFEROVERRUN 0xc +#define OHCI_CC_BUFFERUNDERRUN 0xd + +/* Update IRQ levels */ +static inline void ohci_intr_update(OHCIState *ohci) +{ + int level = 0; + + if ((ohci->intr & OHCI_INTR_MIE) && + (ohci->intr_status & ohci->intr)) + level = 1; + + pci_set_irq(&ohci->pci_dev, 0, level); +} + +/* Set an interrupt */ +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) +{ + ohci->intr_status |= intr; + ohci_intr_update(ohci); +} + +/* Attach or detach a device on a root hub port. */ +static void ohci_attach(USBPort *port1, USBDevice *dev) +{ + OHCIState *s = port1->opaque; + OHCIPort *port = &s->rhport[port1->index]; + uint32_t old_state = port->ctrl; + + if (dev) { + if (port->port.dev) { + usb_attach(port1, NULL); + } + /* set connect status */ + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + + /* update speed */ + if (dev->speed == USB_SPEED_LOW) + port->ctrl |= OHCI_PORT_LSDA; + else + port->ctrl &= ~OHCI_PORT_LSDA; + port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); + dprintf("usb-ohci: Attached port %d\n", port1->index); + } else { + /* set connect status */ + if (port->ctrl & OHCI_PORT_CCS) { + port->ctrl &= ~OHCI_PORT_CCS; + port->ctrl |= OHCI_PORT_CSC; + } + /* disable port */ + if (port->ctrl & OHCI_PORT_PES) { + port->ctrl &= ~OHCI_PORT_PES; + port->ctrl |= OHCI_PORT_PESC; + } + dev = port->port.dev; + if (dev) { + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); + } + port->port.dev = NULL; + dprintf("usb-ohci: Detached port %d\n", port1->index); + } + + if (old_state != port->ctrl) + ohci_set_interrupt(s, OHCI_INTR_RHSC); +} + +/* Reset the controller */ +static void ohci_reset(OHCIState *ohci) +{ + OHCIPort *port; + int i; + + ohci->ctl = 0; + ohci->status = 0; + ohci->intr_status = 0; + ohci->intr = OHCI_INTR_MIE; + + ohci->hcca = 0; + ohci->ctrl_head = ohci->ctrl_cur = 0; + ohci->bulk_head = ohci->bulk_cur = 0; + ohci->per_cur = 0; + ohci->done = 0; + ohci->done_count = 7; + + /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? + * I took the value linux sets ... + */ + ohci->fsmps = 0x2778; + ohci->fi = 0x2edf; + ohci->fit = 0; + ohci->frt = 0; + ohci->frame_number = 0; + ohci->pstart = 0; + ohci->lst = OHCI_LS_THRESH; + + ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; + ohci->rhdesc_b = 0x0; /* Impl. specific */ + ohci->rhstatus = 0; + + for (i = 0; i < ohci->num_ports; i++) + { + port = &ohci->rhport[i]; + port->ctrl = 0; + if (port->port.dev) + ohci_attach(&port->port, port->port.dev); + } + dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); +} + +/* Get an array of dwords from main memory */ +static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) +{ + int i; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + *buf = le32_to_cpu(*buf); + } + + return 1; +} + +/* Put an array of dwords in to main memory */ +static inline int put_dwords(uint32_t addr, uint32_t *buf, int num) +{ + int i; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); + cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + } + + return 1; +} + +static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed) +{ + return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); +} + +static inline int ohci_read_td(uint32_t addr, struct ohci_td *td) +{ + return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); +} + +static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed) +{ + return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); +} + +static inline int ohci_put_td(uint32_t addr, struct ohci_td *td) +{ + return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); +} + +/* Read/Write the contents of a TD from/to main memory. */ +static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) +{ + uint32_t ptr; + uint32_t n; + + ptr = td->cbp; + n = 0x1000 - (ptr & 0xfff); + if (n > len) + n = len; + cpu_physical_memory_rw(ptr, buf, n, write); + if (n == len) + return; + ptr = td->be & ~0xfffu; + buf += n; + cpu_physical_memory_rw(ptr, buf, len - n, write); +} + +/* Service a transport descriptor. + Returns nonzero to terminate processing of this endpoint. */ + +static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) +{ + int dir; + size_t len = 0; + uint8_t buf[8192]; + char *str = NULL; + int pid; + int ret; + int i; + USBDevice *dev; + struct ohci_td td; + uint32_t addr; + int flag_r; + + addr = ed->head & OHCI_DPTR_MASK; + if (!ohci_read_td(addr, &td)) { + fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); + return 0; + } + + dir = OHCI_BM(ed->flags, ED_D); + switch (dir) { + case OHCI_TD_DIR_OUT: + case OHCI_TD_DIR_IN: + /* Same value. */ + break; + default: + dir = OHCI_BM(td.flags, TD_DP); + break; + } + + switch (dir) { + case OHCI_TD_DIR_IN: + str = "in"; + pid = USB_TOKEN_IN; + break; + case OHCI_TD_DIR_OUT: + str = "out"; + pid = USB_TOKEN_OUT; + break; + case OHCI_TD_DIR_SETUP: + str = "setup"; + pid = USB_TOKEN_SETUP; + break; + default: + fprintf(stderr, "usb-ohci: Bad direction\n"); + return 1; + } + if (td.cbp && td.be) { + if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { + len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); + } else { + len = (td.be - td.cbp) + 1; + } + + if (len && dir != OHCI_TD_DIR_IN) { + ohci_copy_td(&td, buf, len, 0); + } + } + + flag_r = (td.flags & OHCI_TD_R) != 0; +#ifdef DEBUG_PACKET + dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", + addr, len, str, flag_r, td.cbp, td.be); + + if (len >= 0 && dir != OHCI_TD_DIR_IN) { + dprintf(" data:"); + for (i = 0; i < len; i++) + printf(" %.2x", buf[i]); + dprintf("\n"); + } +#endif + ret = USB_RET_NODEV; + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) + continue; + + ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA), + OHCI_BM(ed->flags, ED_EN), buf, len); + if (ret != USB_RET_NODEV) + break; + } +#ifdef DEBUG_PACKET + dprintf("ret=%d\n", ret); +#endif + if (ret >= 0) { + if (dir == OHCI_TD_DIR_IN) { + ohci_copy_td(&td, buf, ret, 1); +#ifdef DEBUG_PACKET + dprintf(" data:"); + for (i = 0; i < ret; i++) + printf(" %.2x", buf[i]); + dprintf("\n"); +#endif + } else { + ret = len; + } + } + + /* Writeback */ + if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { + /* Transmission succeeded. */ + if (ret == len) { + td.cbp = 0; + } else { + td.cbp += ret; + if ((td.cbp & 0xfff) + ret > 0xfff) { + td.cbp &= 0xfff; + td.cbp |= td.be & ~0xfff; + } + } + td.flags |= OHCI_TD_T1; + td.flags ^= OHCI_TD_T0; + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); + OHCI_SET_BM(td.flags, TD_EC, 0); + + ed->head &= ~OHCI_ED_C; + if (td.flags & OHCI_TD_T0) + ed->head |= OHCI_ED_C; + } else { + if (ret >= 0) { + dprintf("usb-ohci: Underrun\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); + } else { + switch (ret) { + case USB_RET_NODEV: + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); + case USB_RET_NAK: + dprintf("usb-ohci: got NAK\n"); + return 1; + case USB_RET_STALL: + dprintf("usb-ohci: got STALL\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); + break; + case USB_RET_BABBLE: + dprintf("usb-ohci: got BABBLE\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); + break; + default: + fprintf(stderr, "usb-ohci: Bad device response %d\n", ret); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); + OHCI_SET_BM(td.flags, TD_EC, 3); + break; + } + } + ed->head |= OHCI_ED_H; + } + + /* Retire this TD */ + ed->head &= ~OHCI_DPTR_MASK; + ed->head |= td.next & OHCI_DPTR_MASK; + td.next = ohci->done; + ohci->done = addr; + i = OHCI_BM(td.flags, TD_DI); + if (i < ohci->done_count) + ohci->done_count = i; + ohci_put_td(addr, &td); + return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; +} + +/* Service an endpoint list. Returns nonzero if active TD were found. */ +static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) +{ + struct ohci_ed ed; + uint32_t next_ed; + uint32_t cur; + int active; + + active = 0; + + if (head == 0) + return 0; + + for (cur = head; cur; cur = next_ed) { + if (!ohci_read_ed(cur, &ed)) { + fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); + return 0; + } + + next_ed = ed.next & OHCI_DPTR_MASK; + + if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) + continue; + + /* Skip isochronous endpoints. */ + if (ed.flags & OHCI_ED_F) + continue; + + while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { +#ifdef DEBUG_PACKET + dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u " + "h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur, + OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), + OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, + (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, + OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0, + (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, + ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); +#endif + active = 1; + + if (ohci_service_td(ohci, &ed)) + break; + } + + ohci_put_ed(cur, &ed); + } + + return active; +} + +/* Generate a SOF event, and set a timer for EOF */ +static void ohci_sof(OHCIState *ohci) +{ + ohci->sof_time = qemu_get_clock(vm_clock); + qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time); + ohci_set_interrupt(ohci, OHCI_INTR_SF); +} + +/* Do frame processing on frame boundary */ +static void ohci_frame_boundary(void *opaque) +{ + OHCIState *ohci = opaque; + struct ohci_hcca hcca; + + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0); + + /* Process all the lists at the end of the frame */ + if (ohci->ctl & OHCI_CTL_PLE) { + int n; + + n = ohci->frame_number & 0x1f; + ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); + } + if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { + if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) + dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); + if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { + ohci->ctrl_cur = 0; + ohci->status &= ~OHCI_STATUS_CLF; + } + } + + if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { + if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { + ohci->bulk_cur = 0; + ohci->status &= ~OHCI_STATUS_BLF; + } + } + + /* Frame boundary, so do EOF stuf here */ + ohci->frt = ohci->fit; + + /* XXX: endianness */ + ohci->frame_number = (ohci->frame_number + 1) & 0xffff; + hcca.frame = cpu_to_le32(ohci->frame_number); + + if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { + if (!ohci->done) + abort(); + if (ohci->intr & ohci->intr_status) + ohci->done |= 1; + hcca.done = cpu_to_le32(ohci->done); + ohci->done = 0; + ohci->done_count = 7; + ohci_set_interrupt(ohci, OHCI_INTR_WD); + } + + if (ohci->done_count != 7 && ohci->done_count != 0) + ohci->done_count--; + + /* Do SOF stuff here */ + ohci_sof(ohci); + + /* Writeback HCCA */ + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1); +} + +/* Start sending SOF tokens across the USB bus, lists are processed in + * next frame + */ +static int ohci_bus_start(OHCIState *ohci) +{ + ohci->eof_timer = qemu_new_timer(vm_clock, + ohci_frame_boundary, + ohci); + + if (ohci->eof_timer == NULL) { + fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", + ohci->pci_dev.name); + /* TODO: Signal unrecoverable error */ + return 0; + } + + dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name); + + ohci_sof(ohci); + + return 1; +} + +/* Stop sending SOF tokens on the bus */ +static void ohci_bus_stop(OHCIState *ohci) +{ + if (ohci->eof_timer) + qemu_del_timer(ohci->eof_timer); +} + +/* Sets a flag in a port status register but only set it if the port is + * connected, if not set ConnectStatusChange flag. If flag is enabled + * return 1. + */ +static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) +{ + int ret = 1; + + /* writing a 0 has no effect */ + if (val == 0) + return 0; + + /* If CurrentConnectStatus is cleared we set + * ConnectStatusChange + */ + if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { + ohci->rhport[i].ctrl |= OHCI_PORT_CSC; + if (ohci->rhstatus & OHCI_RHS_DRWE) { + /* TODO: CSC is a wakeup event */ + } + return 0; + } + + if (ohci->rhport[i].ctrl & val) + ret = 0; + + /* set the bit */ + ohci->rhport[i].ctrl |= val; + + return ret; +} + +/* Set the frame interval - frame interval toggle is manipulated by the hcd only */ +static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) +{ + val &= OHCI_FMI_FI; + + if (val != ohci->fi) { + dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", + ohci->pci_dev.name, ohci->fi, ohci->fi); + } + + ohci->fi = val; +} + +static void ohci_port_power(OHCIState *ohci, int i, int p) +{ + if (p) { + ohci->rhport[i].ctrl |= OHCI_PORT_PPS; + } else { + ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| + OHCI_PORT_CCS| + OHCI_PORT_PSS| + OHCI_PORT_PRS); + } +} + +/* Set HcControlRegister */ +static void ohci_set_ctl(OHCIState *ohci, uint32_t val) +{ + uint32_t old_state; + uint32_t new_state; + + old_state = ohci->ctl & OHCI_CTL_HCFS; + ohci->ctl = val; + new_state = ohci->ctl & OHCI_CTL_HCFS; + + /* no state change */ + if (old_state == new_state) + return; + + switch (new_state) { + case OHCI_USB_OPERATIONAL: + ohci_bus_start(ohci); + break; + case OHCI_USB_SUSPEND: + ohci_bus_stop(ohci); + dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name); + break; + case OHCI_USB_RESUME: + dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); + break; + case OHCI_USB_RESET: + dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); + break; + } +} + +static uint32_t ohci_get_frame_remaining(OHCIState *ohci) +{ + uint16_t fr; + int64_t tks; + + if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) + return (ohci->frt << 31); + + /* Being in USB operational state guarnatees sof_time was + * set already. + */ + tks = qemu_get_clock(vm_clock) - ohci->sof_time; + + /* avoid muldiv if possible */ + if (tks >= usb_frame_time) + return (ohci->frt << 31); + + tks = muldiv64(1, tks, usb_bit_time); + fr = (uint16_t)(ohci->fi - tks); + + return (ohci->frt << 31) | fr; +} + + +/* Set root hub status */ +static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) +{ + uint32_t old_state; + + old_state = ohci->rhstatus; + + /* write 1 to clear OCIC */ + if (val & OHCI_RHS_OCIC) + ohci->rhstatus &= ~OHCI_RHS_OCIC; + + if (val & OHCI_RHS_LPS) { + int i; + + for (i = 0; i < ohci->num_ports; i++) + ohci_port_power(ohci, i, 0); + dprintf("usb-ohci: powered down all ports\n"); + } + + if (val & OHCI_RHS_LPSC) { + int i; + + for (i = 0; i < ohci->num_ports; i++) + ohci_port_power(ohci, i, 1); + dprintf("usb-ohci: powered up all ports\n"); + } + + if (val & OHCI_RHS_DRWE) + ohci->rhstatus |= OHCI_RHS_DRWE; + + if (val & OHCI_RHS_CRWE) + ohci->rhstatus &= ~OHCI_RHS_DRWE; + + if (old_state != ohci->rhstatus) + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); +} + +/* Set root hub port status */ +static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) +{ + uint32_t old_state; + OHCIPort *port; + + port = &ohci->rhport[portnum]; + old_state = port->ctrl; + + /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ + if (val & OHCI_PORT_WTC) + port->ctrl &= ~(val & OHCI_PORT_WTC); + + if (val & OHCI_PORT_CCS) + port->ctrl &= ~OHCI_PORT_PES; + + ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); + + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) + dprintf("usb-ohci: port %d: SUSPEND\n", portnum); + + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { + dprintf("usb-ohci: port %d: RESET\n", portnum); + port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET, + 0, 0, NULL, 0); + port->ctrl &= ~OHCI_PORT_PRS; + /* ??? Should this also set OHCI_PORT_PESC. */ + port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; + } + + /* Invert order here to ensure in ambiguous case, device is + * powered up... + */ + if (val & OHCI_PORT_LSDA) + ohci_port_power(ohci, portnum, 0); + if (val & OHCI_PORT_PPS) + ohci_port_power(ohci, portnum, 1); + + if (old_state != port->ctrl) + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); + + return; +} + +static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr) +{ + OHCIState *ohci = ptr; + + addr -= ohci->mem_base; + + /* Only aligned reads are allowed on OHCI */ + if (addr & 3) { + fprintf(stderr, "usb-ohci: Mis-aligned read\n"); + return 0xffffffff; + } + + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { + /* HcRhPortStatus */ + return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; + } + + switch (addr >> 2) { + case 0: /* HcRevision */ + return 0x10; + + case 1: /* HcControl */ + return ohci->ctl; + + case 2: /* HcCommandStatus */ + return ohci->status; + + case 3: /* HcInterruptStatus */ + return ohci->intr_status; + + case 4: /* HcInterruptEnable */ + case 5: /* HcInterruptDisable */ + return ohci->intr; + + case 6: /* HcHCCA */ + return ohci->hcca; + + case 7: /* HcPeriodCurrentED */ + return ohci->per_cur; + + case 8: /* HcControlHeadED */ + return ohci->ctrl_head; + + case 9: /* HcControlCurrentED */ + return ohci->ctrl_cur; + + case 10: /* HcBulkHeadED */ + return ohci->bulk_head; + + case 11: /* HcBulkCurrentED */ + return ohci->bulk_cur; + + case 12: /* HcDoneHead */ + return ohci->done; + + case 13: /* HcFmInterval */ + return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); + + case 14: /* HcFmRemaining */ + return ohci_get_frame_remaining(ohci); + + case 15: /* HcFmNumber */ + return ohci->frame_number; + + case 16: /* HcPeriodicStart */ + return ohci->pstart; + + case 17: /* HcLSThreshold */ + return ohci->lst; + + case 18: /* HcRhDescriptorA */ + return ohci->rhdesc_a; + + case 19: /* HcRhDescriptorB */ + return ohci->rhdesc_b; + + case 20: /* HcRhStatus */ + return ohci->rhstatus; + + default: + fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); + return 0xffffffff; + } +} + +static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) +{ + OHCIState *ohci = ptr; + + addr -= ohci->mem_base; + + /* Only aligned reads are allowed on OHCI */ + if (addr & 3) { + fprintf(stderr, "usb-ohci: Mis-aligned write\n"); + return; + } + + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { + /* HcRhPortStatus */ + ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); + return; + } + + switch (addr >> 2) { + case 1: /* HcControl */ + ohci_set_ctl(ohci, val); + break; + + case 2: /* HcCommandStatus */ + /* SOC is read-only */ + val = (val & ~OHCI_STATUS_SOC); + + /* Bits written as '0' remain unchanged in the register */ + ohci->status |= val; + + if (ohci->status & OHCI_STATUS_HCR) + ohci_reset(ohci); + break; + + case 3: /* HcInterruptStatus */ + ohci->intr_status &= ~val; + ohci_intr_update(ohci); + break; + + case 4: /* HcInterruptEnable */ + ohci->intr |= val; + ohci_intr_update(ohci); + break; + + case 5: /* HcInterruptDisable */ + ohci->intr &= ~val; + ohci_intr_update(ohci); + break; + + case 6: /* HcHCCA */ + ohci->hcca = val & OHCI_HCCA_MASK; + break; + + case 8: /* HcControlHeadED */ + ohci->ctrl_head = val & OHCI_EDPTR_MASK; + break; + + case 9: /* HcControlCurrentED */ + ohci->ctrl_cur = val & OHCI_EDPTR_MASK; + break; + + case 10: /* HcBulkHeadED */ + ohci->bulk_head = val & OHCI_EDPTR_MASK; + break; + + case 11: /* HcBulkCurrentED */ + ohci->bulk_cur = val & OHCI_EDPTR_MASK; + break; + + case 13: /* HcFmInterval */ + ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; + ohci->fit = (val & OHCI_FMI_FIT) >> 31; + ohci_set_frame_interval(ohci, val); + break; + + case 16: /* HcPeriodicStart */ + ohci->pstart = val & 0xffff; + break; + + case 17: /* HcLSThreshold */ + ohci->lst = val & 0xffff; + break; + + case 18: /* HcRhDescriptorA */ + ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; + ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; + break; + + case 19: /* HcRhDescriptorB */ + break; + + case 20: /* HcRhStatus */ + ohci_set_hub_status(ohci, val); + break; + + default: + fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); + break; + } +} + +/* Only dword reads are defined on OHCI register space */ +static CPUReadMemoryFunc *ohci_readfn[3]={ + ohci_mem_read, + ohci_mem_read, + ohci_mem_read +}; + +/* Only dword writes are defined on OHCI register space */ +static CPUWriteMemoryFunc *ohci_writefn[3]={ + ohci_mem_write, + ohci_mem_write, + ohci_mem_write +}; + +static void ohci_mapfunc(PCIDevice *pci_dev, int i, + uint32_t addr, uint32_t size, int type) +{ + OHCIState *ohci = (OHCIState *)pci_dev; + ohci->mem_base = addr; + cpu_register_physical_memory(addr, size, ohci->mem); +} + +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) +{ + OHCIState *ohci; + int vid = 0x106b; + int did = 0x003f; + int i; + + + if (usb_frame_time == 0) { +#if OHCI_TIME_WARP + usb_frame_time = ticks_per_sec; + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000); +#else + usb_frame_time = muldiv64(1, ticks_per_sec, 1000); + if (ticks_per_sec >= USB_HZ) { + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); + } else { + usb_bit_time = 1; + } +#endif + dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n", + usb_frame_time, usb_bit_time); + } + + ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), + devfn, NULL, NULL); + if (ohci == NULL) { + fprintf(stderr, "usb-ohci: Failed to register PCI device\n"); + return; + } + + ohci->pci_dev.config[0x00] = vid & 0xff; + ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff; + ohci->pci_dev.config[0x02] = did & 0xff; + ohci->pci_dev.config[0x03] = (did >> 8) & 0xff; + ohci->pci_dev.config[0x09] = 0x10; /* OHCI */ + ohci->pci_dev.config[0x0a] = 0x3; + ohci->pci_dev.config[0x0b] = 0xc; + ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ + + ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); + + pci_register_io_region((struct PCIDevice *)ohci, 0, 256, + PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); + + ohci->num_ports = num_ports; + for (i = 0; i < num_ports; i++) { + qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); + } + + ohci_reset(ohci); +} diff --git a/tools/ioemu/hw/usb-uhci.c b/tools/ioemu/hw/usb-uhci.c index 23964f36a5..1a6e0130f9 100644 --- a/tools/ioemu/hw/usb-uhci.c +++ b/tools/ioemu/hw/usb-uhci.c @@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) usb_attach(port1, NULL); } /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; - } + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= UHCI_PORT_LSDA; @@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) USB_MSG_ATTACH, 0, 0, NULL, 0); } else { /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + if (port->ctrl & UHCI_PORT_CCS) { + port->ctrl &= ~UHCI_PORT_CCS; + port->ctrl |= UHCI_PORT_CSC; } /* disable port */ if (port->ctrl & UHCI_PORT_EN) { @@ -638,17 +638,15 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) +void usb_uhci_init(PCIBus *bus, int devfn) { UHCIState *s; uint8_t *pci_conf; - UHCIPort *port; int i; s = (UHCIState *)pci_register_device(bus, "USB-UHCI", sizeof(UHCIState), - ((PCIDevice *)piix3_state)->devfn + 2, - NULL, NULL); + devfn, NULL, NULL); pci_conf = s->dev.config; pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; @@ -663,11 +661,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) pci_conf[0x60] = 0x10; // release number for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - port->port.opaque = s; - port->port.index = i; - port->port.attach = uhci_attach; - usb_ports[i] = &port->port; + qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); diff --git a/tools/ioemu/hw/usb.h b/tools/ioemu/hw/usb.h index 05502e04db..98fde06569 100644 --- a/tools/ioemu/hw/usb.h +++ b/tools/ioemu/hw/usb.h @@ -116,6 +116,8 @@ struct USBDevice { int (*handle_packet)(USBDevice *dev, int pid, uint8_t devaddr, uint8_t devep, uint8_t *data, int len); + void (*handle_destroy)(USBDevice *dev); + int speed; /* The following fields are used by the generic USB device @@ -127,6 +129,7 @@ struct USBDevice { int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, uint8_t *data, int len); uint8_t addr; + char devname[32]; int state; uint8_t setup_buf[8]; @@ -137,12 +140,15 @@ struct USBDevice { int setup_index; }; +typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); + /* USB port on which a device can be connected */ struct USBPort { USBDevice *dev; - void (*attach)(USBPort *port, USBDevice *dev); + usb_attachfn attach; void *opaque; int index; /* internal port index, may be used with the opaque */ + struct USBPort *next; /* Used internally by qemu. */ }; void usb_attach(USBPort *port, USBDevice *dev); @@ -152,10 +158,13 @@ int usb_generic_handle_packet(USBDevice *s, int pid, int set_usb_string(uint8_t *buf, const char *str); /* usb hub */ -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); +USBDevice *usb_hub_init(int nb_ports); /* usb-uhci.c */ -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); +void usb_uhci_init(PCIBus *bus, int devfn); + +/* usb-ohci.c */ +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); @@ -164,3 +173,6 @@ void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); USBDevice *usb_tablet_init(void); + +/* usb-msd.c */ +USBDevice *usb_msd_init(const char *filename); diff --git a/tools/ioemu/hw/versatile_pci.c b/tools/ioemu/hw/versatile_pci.c new file mode 100644 index 0000000000..34a4bc6c5a --- /dev/null +++ b/tools/ioemu/hw/versatile_pci.c @@ -0,0 +1,119 @@ +/* + * ARM Versatile/PB PCI host controller + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +#include "vl.h" + +static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) +{ + return addr & 0xf8ff; +} + +static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1); +} + +static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2); +} + +static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4); +} + +static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1); + return val; +} + +static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_vpb_config_write[] = { + &pci_vpb_config_writeb, + &pci_vpb_config_writew, + &pci_vpb_config_writel, +}; + +static CPUReadMemoryFunc *pci_vpb_config_read[] = { + &pci_vpb_config_readb, + &pci_vpb_config_readw, + &pci_vpb_config_readl, +}; + +static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + pic_set_irq_new(pic, 27 + irq_num, level); +} + +PCIBus *pci_vpb_init(void *pic) +{ + PCIBus *s; + PCIDevice *d; + int mem_config; + + s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3); + /* ??? Register memory space. */ + + mem_config = cpu_register_io_memory(0, pci_vpb_config_read, + pci_vpb_config_write, s); + /* Selfconfig area. */ + cpu_register_physical_memory(0x41000000, 0x10000, mem_config); + /* Normal config area. */ + cpu_register_physical_memory(0x42000000, 0x10000, mem_config); + + d = pci_register_device(s, "Versatile/PB PCI Controller", + sizeof(PCIDevice), -1, NULL, NULL); + d->config[0x00] = 0xee; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x00; // device_id + d->config[0x03] = 0x03; + d->config[0x04] = 0x00; + d->config[0x05] = 0x00; + d->config[0x06] = 0x20; + d->config[0x07] = 0x02; + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x00; // programming i/f + d->config[0x0A] = 0x40; // class_sub = pci host + d->config[0x0B] = 0x0b; // class_base = PCI_bridge + d->config[0x0D] = 0x10; // latency_timer + + return s; +} + diff --git a/tools/ioemu/hw/versatilepb.c b/tools/ioemu/hw/versatilepb.c index e198a518ea..28ec1374ba 100644 --- a/tools/ioemu/hw/versatilepb.c +++ b/tools/ioemu/hw/versatilepb.c @@ -10,6 +10,8 @@ #include "vl.h" #include "arm_pic.h" +#define LOCK_VALUE 0xa05f + /* Primary interrupt controller. */ typedef struct vpb_sic_state @@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) return s; } +/* System controller. */ + +typedef struct { + uint32_t base; + uint32_t leds; + uint16_t lockval; + uint32_t cfgdata1; + uint32_t cfgdata2; + uint32_t flags; + uint32_t nvflags; + uint32_t resetlevel; +} vpb_sys_state; + +static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* ID */ + return 0x41007004; + case 0x04: /* SW */ + /* General purpose hardware switches. + We don't have a useful way of exposing these to the user. */ + return 0; + case 0x08: /* LED */ + return s->leds; + case 0x20: /* LOCK */ + return s->lockval; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + case 0x24: /* 100HZ */ + /* ??? Implement these. */ + return 0; + case 0x28: /* CFGDATA1 */ + return s->cfgdata1; + case 0x2c: /* CFGDATA2 */ + return s->cfgdata2; + case 0x30: /* FLAGS */ + return s->flags; + case 0x38: /* NVFLAGS */ + return s->nvflags; + case 0x40: /* RESETCTL */ + return s->resetlevel; + case 0x44: /* PCICTL */ + return 1; + case 0x48: /* MCI */ + return 0; + case 0x4c: /* FLASH */ + return 0; + case 0x50: /* CLCD */ + return 0x1000; + case 0x54: /* CLCDSER */ + return 0; + case 0x58: /* BOOTCS */ + return 0; + case 0x5c: /* 24MHz */ + /* ??? not implemented. */ + return 0; + case 0x60: /* MISC */ + return 0; + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + case 0xc0: /* SYS_TEST_OSC0 */ + case 0xc4: /* SYS_TEST_OSC1 */ + case 0xc8: /* SYS_TEST_OSC2 */ + case 0xcc: /* SYS_TEST_OSC3 */ + case 0xd0: /* SYS_TEST_OSC4 */ + return 0; + default: + printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void vpb_sys_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + offset -= s->base; + + switch (offset) { + case 0x08: /* LED */ + s->leds = val; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + /* ??? */ + break; + case 0x20: /* LOCK */ + if (val == LOCK_VALUE) + s->lockval = val; + else + s->lockval = val & 0x7fff; + break; + case 0x28: /* CFGDATA1 */ + /* ??? Need to implement this. */ + s->cfgdata1 = val; + break; + case 0x2c: /* CFGDATA2 */ + /* ??? Need to implement this. */ + s->cfgdata2 = val; + break; + case 0x30: /* FLAGSSET */ + s->flags |= val; + break; + case 0x34: /* FLAGSCLR */ + s->flags &= ~val; + break; + case 0x38: /* NVFLAGSSET */ + s->nvflags |= val; + break; + case 0x3c: /* NVFLAGSCLR */ + s->nvflags &= ~val; + break; + case 0x40: /* RESETCTL */ + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x100) + cpu_abort(cpu_single_env, "Board reset\n"); + } + break; + case 0x44: /* PCICTL */ + /* nothing to do. */ + break; + case 0x4c: /* FLASH */ + case 0x50: /* CLCD */ + case 0x54: /* CLCDSER */ + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + break; + default: + printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); + return; + } +} + +static CPUReadMemoryFunc *vpb_sys_readfn[] = { + vpb_sys_read, + vpb_sys_read, + vpb_sys_read +}; + +static CPUWriteMemoryFunc *vpb_sys_writefn[] = { + vpb_sys_write, + vpb_sys_write, + vpb_sys_write +}; + +static vpb_sys_state *vpb_sys_init(uint32_t base) +{ + vpb_sys_state *s; + int iomemtype; + + s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); + if (!s) + return NULL; + s->base = base; + iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, + vpb_sys_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ + return s; +} + /* Board init. */ /* The AB and PB boards both use the same core, just with different @@ -159,6 +343,11 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, CPUState *env; void *pic; void *sic; + void *scsi_hba; + PCIBus *pci_bus; + NICInfo *nd; + int n; + int done_smc = 0; env = cpu_init(); cpu_arm_set_model(env, ARM_CPUID_ARM926); @@ -166,20 +355,33 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + vpb_sys_init(0x10000000); pic = arm_pic_init_cpu(env); pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); sic = vpb_sic_init(0x10003000, pic, 31); pl050_init(0x10006000, sic, 3, 0); pl050_init(0x10007000, sic, 4, 1); - /* TODO: Init PCI NICs. */ - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0x10010000, sic, 25); + pci_bus = pci_vpb_init(sic); + /* The Versatile PCI bridge does not provide access to PCI IO space, + so many of the qemu PCI devices are not useable. */ + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (!nd->model) + nd->model = done_smc ? "rtl8139" : "smc91c111"; + if (strcmp(nd->model, "smc91c111") == 0) { + smc91c111_init(nd, 0x10010000, sic, 25); } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); + pci_nic_init(pci_bus, nd); + } + } + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + scsi_hba = lsi_scsi_init(pci_bus, -1); + for (n = 0; n < MAX_DISKS; n++) { + if (bs_table[n]) { + lsi_scsi_attach(scsi_hba, bs_table[n], n); } } diff --git a/tools/ioemu/hw/vga.c b/tools/ioemu/hw/vga.c index 287a158fd1..bbe3e582a5 100644 --- a/tools/ioemu/hw/vga.c +++ b/tools/ioemu/hw/vga.c @@ -378,10 +378,29 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) VGAState *s = opaque; uint32_t val; - if (s->vbe_index <= VBE_DISPI_INDEX_NB) - val = s->vbe_regs[s->vbe_index]; - else + if (s->vbe_index <= VBE_DISPI_INDEX_NB) { + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { + switch(s->vbe_index) { + /* XXX: do not hardcode ? */ + case VBE_DISPI_INDEX_XRES: + val = VBE_DISPI_MAX_XRES; + break; + case VBE_DISPI_INDEX_YRES: + val = VBE_DISPI_MAX_YRES; + break; + case VBE_DISPI_INDEX_BPP: + val = VBE_DISPI_MAX_BPP; + break; + default: + val = s->vbe_regs[s->vbe_index]; + break; + } + } else { + val = s->vbe_regs[s->vbe_index]; + } + } else { val = 0; + } #ifdef DEBUG_BOCHS_VBE printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); #endif @@ -434,7 +453,8 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->bank_offset = (val << 16); break; case VBE_DISPI_INDEX_ENABLE: - if (val & VBE_DISPI_ENABLED) { + if ((val & VBE_DISPI_ENABLED) && + !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { int h, shift_control; s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = @@ -450,7 +470,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); s->vbe_start_addr = 0; - + /* clear the screen (should be done in BIOS) */ if (!(val & VBE_DISPI_NOCLEARMEM)) { memset(s->vram_ptr, 0, @@ -464,7 +484,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->cr[0x13] = s->vbe_line_offset >> 3; /* width */ s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; - /* height */ + /* height (only meaningful if < 1024) */ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; s->cr[0x12] = h; s->cr[0x07] = (s->cr[0x07] & ~0x42) | @@ -808,6 +828,11 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign return (r << 16) | (g << 8) | b; } +static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b) +{ + return (b << 16) | (g << 8) | r; +} + #define DEPTH 8 #include "vga_template.h" @@ -820,6 +845,10 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign #define DEPTH 32 #include "vga_template.h" +#define BGR_FORMAT +#define DEPTH 32 +#include "vga_template.h" + static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) { unsigned int col; @@ -852,6 +881,13 @@ static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned return col; } +static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel32bgr(r, g, b); + return col; +} + /* return true if the palette was modified */ static int update_palette16(VGAState *s) { @@ -948,9 +984,11 @@ static int update_basic_params(VGAState *s) return full_update; } -static inline int get_depth_index(int depth) +#define NB_DEPTHS 5 + +static inline int get_depth_index(DisplayState *s) { - switch(depth) { + switch(s->depth) { default: case 8: return 0; @@ -959,29 +997,35 @@ static inline int get_depth_index(int depth) case 16: return 2; case 32: - return 3; + if (s->bgr) + return 4; + else + return 3; } } -static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { +static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = { vga_draw_glyph8_8, vga_draw_glyph8_16, vga_draw_glyph8_16, vga_draw_glyph8_32, + vga_draw_glyph8_32, }; -static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = { +static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { vga_draw_glyph16_8, vga_draw_glyph16_16, vga_draw_glyph16_16, vga_draw_glyph16_32, + vga_draw_glyph16_32, }; -static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { +static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { vga_draw_glyph9_8, vga_draw_glyph9_16, vga_draw_glyph9_16, vga_draw_glyph9_32, + vga_draw_glyph9_32, }; static const uint8_t cursor_glyph[32 * 4] = { @@ -1103,7 +1147,7 @@ static void vga_draw_text(VGAState *s, int full_update) } cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; - depth_index = get_depth_index(s->ds->depth); + depth_index = get_depth_index(s->ds); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else @@ -1196,56 +1240,76 @@ enum { VGA_DRAW_LINE_NB, }; -static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { +static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { vga_draw_line2_8, vga_draw_line2_16, vga_draw_line2_16, vga_draw_line2_32, + vga_draw_line2_32, vga_draw_line2d2_8, vga_draw_line2d2_16, vga_draw_line2d2_16, vga_draw_line2d2_32, + vga_draw_line2d2_32, vga_draw_line4_8, vga_draw_line4_16, vga_draw_line4_16, vga_draw_line4_32, + vga_draw_line4_32, vga_draw_line4d2_8, vga_draw_line4d2_16, vga_draw_line4d2_16, vga_draw_line4d2_32, + vga_draw_line4d2_32, vga_draw_line8d2_8, vga_draw_line8d2_16, vga_draw_line8d2_16, vga_draw_line8d2_32, + vga_draw_line8d2_32, vga_draw_line8_8, vga_draw_line8_16, vga_draw_line8_16, vga_draw_line8_32, + vga_draw_line8_32, vga_draw_line15_8, vga_draw_line15_15, vga_draw_line15_16, vga_draw_line15_32, + vga_draw_line15_32bgr, vga_draw_line16_8, vga_draw_line16_15, vga_draw_line16_16, vga_draw_line16_32, + vga_draw_line16_32bgr, vga_draw_line24_8, vga_draw_line24_15, vga_draw_line24_16, vga_draw_line24_32, + vga_draw_line24_32bgr, vga_draw_line32_8, vga_draw_line32_15, vga_draw_line32_16, vga_draw_line32_32, + vga_draw_line32_32bgr, +}; + +typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); + +static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = { + rgb_to_pixel8_dup, + rgb_to_pixel15_dup, + rgb_to_pixel16_dup, + rgb_to_pixel32_dup, + rgb_to_pixel32bgr_dup, }; static int vga_get_bpp(VGAState *s) @@ -1266,11 +1330,19 @@ static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1); +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; + height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; + } else +#endif + { + width = (s->cr[0x01] + 1) * 8; + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1); + } *pwidth = width; *pheight = height; } @@ -1462,7 +1534,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) break; } } - vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; + vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; if (disp_width != s->last_width || height != s->last_height) { @@ -1597,21 +1669,8 @@ static void vga_update_display(void *opaque) if (s->ds->depth == 0) { /* nothing to do */ } else { - switch(s->ds->depth) { - case 8: - s->rgb_to_pixel = rgb_to_pixel8_dup; - break; - case 15: - s->rgb_to_pixel = rgb_to_pixel15_dup; - break; - default: - case 16: - s->rgb_to_pixel = rgb_to_pixel16_dup; - break; - case 32: - s->rgb_to_pixel = rgb_to_pixel32_dup; - break; - } + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; full_update = 0; if (!(s->ar_index & 0x20)) { diff --git a/tools/ioemu/hw/vga_int.h b/tools/ioemu/hw/vga_int.h index 275af653da..47f1574d11 100644 --- a/tools/ioemu/hw/vga_int.h +++ b/tools/ioemu/hw/vga_int.h @@ -30,8 +30,9 @@ /* bochs VBE support */ //#define CONFIG_BOCHS_VBE -#define VBE_DISPI_MAX_XRES 1024 -#define VBE_DISPI_MAX_YRES 768 +#define VBE_DISPI_MAX_XRES 1600 +#define VBE_DISPI_MAX_YRES 1200 +#define VBE_DISPI_MAX_BPP 32 #define VBE_DISPI_INDEX_ID 0x0 #define VBE_DISPI_INDEX_XRES 0x1 @@ -51,6 +52,8 @@ #define VBE_DISPI_DISABLED 0x00 #define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 #define VBE_DISPI_LFB_ENABLED 0x40 #define VBE_DISPI_NOCLEARMEM 0x80 @@ -72,7 +75,7 @@ #endif /* !CONFIG_BOCHS_VBE */ #define CH_ATTR_SIZE (160 * 100) -#define VGA_MAX_HEIGHT 1024 +#define VGA_MAX_HEIGHT 2048 #define VGA_STATE_COMMON \ uint8_t *vram_ptr; \ diff --git a/tools/ioemu/hw/vga_template.h b/tools/ioemu/hw/vga_template.h index 909571ebb3..e7e8cb853e 100644 --- a/tools/ioemu/hw/vga_template.h +++ b/tools/ioemu/hw/vga_template.h @@ -35,7 +35,13 @@ #error unsupport depth #endif -#if DEPTH != 15 +#ifdef BGR_FORMAT +#define PIXEL_NAME glue(DEPTH, bgr) +#else +#define PIXEL_NAME DEPTH +#endif /* BGR_FORMAT */ + +#if DEPTH != 15 && !defined(BGR_FORMAT) static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, uint32_t font_data, @@ -334,118 +340,6 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, } } -#endif /* DEPTH != 15 */ - - -/* XXX: optimize */ - -/* - * 15 bit color - */ -static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ -#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 2); -#else - int w; - uint32_t v, r, g, b; - - w = width; - do { - v = lduw_raw((void *)s); - r = (v >> 7) & 0xf8; - g = (v >> 2) & 0xf8; - b = (v << 3) & 0xf8; - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); - s += 2; - d += BPP; - } while (--w != 0); -#endif -} - -/* - * 16 bit color - */ -static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ -#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 2); -#else - int w; - uint32_t v, r, g, b; - - w = width; - do { - v = lduw_raw((void *)s); - r = (v >> 8) & 0xf8; - g = (v >> 3) & 0xfc; - b = (v << 3) & 0xf8; - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); - s += 2; - d += BPP; - } while (--w != 0); -#endif -} - -/* - * 24 bit color - */ -static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - int w; - uint32_t r, g, b; - - w = width; - do { -#if defined(TARGET_WORDS_BIGENDIAN) - r = s[0]; - g = s[1]; - b = s[2]; -#else - b = s[0]; - g = s[1]; - r = s[2]; -#endif - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); - s += 3; - d += BPP; - } while (--w != 0); -} - -/* - * 32 bit color - */ -static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ -#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 4); -#else - int w; - uint32_t r, g, b; - - w = width; - do { -#if defined(TARGET_WORDS_BIGENDIAN) - r = s[1]; - g = s[2]; - b = s[3]; -#else - b = s[0]; - g = s[1]; - r = s[2]; -#endif - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); - s += 4; - d += BPP; - } while (--w != 0); -#endif -} - -#if DEPTH != 15 void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, const uint8_t *src1, int poffset, int w, @@ -511,9 +405,121 @@ void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, d += BPP; } } + +#endif /* DEPTH != 15 */ + + +/* XXX: optimize */ + +/* + * 15 bit color + */ +static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ +#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + memcpy(d, s, width * 2); +#else + int w; + uint32_t v, r, g, b; + + w = width; + do { + v = lduw_raw((void *)s); + r = (v >> 7) & 0xf8; + g = (v >> 2) & 0xf8; + b = (v << 3) & 0xf8; + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s += 2; + d += BPP; + } while (--w != 0); +#endif +} + +/* + * 16 bit color + */ +static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ +#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + memcpy(d, s, width * 2); +#else + int w; + uint32_t v, r, g, b; + + w = width; + do { + v = lduw_raw((void *)s); + r = (v >> 8) & 0xf8; + g = (v >> 3) & 0xfc; + b = (v << 3) & 0xf8; + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s += 2; + d += BPP; + } while (--w != 0); +#endif +} + +/* + * 24 bit color + */ +static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + int w; + uint32_t r, g, b; + + w = width; + do { +#if defined(TARGET_WORDS_BIGENDIAN) + r = s[0]; + g = s[1]; + b = s[2]; +#else + b = s[0]; + g = s[1]; + r = s[2]; #endif + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s += 3; + d += BPP; + } while (--w != 0); +} + +/* + * 32 bit color + */ +static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ +#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT) + memcpy(d, s, width * 4); +#else + int w; + uint32_t r, g, b; + + w = width; + do { +#if defined(TARGET_WORDS_BIGENDIAN) + r = s[1]; + g = s[2]; + b = s[3]; +#else + b = s[0]; + g = s[1]; + r = s[2]; +#endif + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + s += 4; + d += BPP; + } while (--w != 0); +#endif +} #undef PUT_PIXEL2 #undef DEPTH #undef BPP #undef PIXEL_TYPE +#undef PIXEL_NAME +#undef BGR_FORMAT diff --git a/tools/ioemu/kqemu.c b/tools/ioemu/kqemu.c index bd70474d69..b7a93b0be6 100644 --- a/tools/ioemu/kqemu.c +++ b/tools/ioemu/kqemu.c @@ -119,7 +119,7 @@ static int is_cpuid_supported(void) static void kqemu_update_cpuid(CPUState *env) { - int critical_features_mask, features; + int critical_features_mask, features, ext_features, ext_features_mask; uint32_t eax, ebx, ecx, edx; /* the following features are kept identical on the host and @@ -130,11 +130,14 @@ static void kqemu_update_cpuid(CPUState *env) CPUID_CMOV | CPUID_CX8 | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_SEP; + ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR; if (!is_cpuid_supported()) { features = 0; + ext_features = 0; } else { cpuid(1, eax, ebx, ecx, edx); features = edx; + ext_features = ecx; } #ifdef __x86_64__ /* NOTE: on x86_64 CPUs, SYSENTER is not supported in @@ -144,6 +147,8 @@ static void kqemu_update_cpuid(CPUState *env) #endif env->cpuid_features = (env->cpuid_features & ~critical_features_mask) | (features & critical_features_mask); + env->cpuid_ext_features = (env->cpuid_ext_features & ~ext_features_mask) | + (ext_features & ext_features_mask); /* XXX: we could update more of the target CPUID state so that the non accelerated code sees exactly the same CPU features as the accelerated code */ @@ -598,12 +603,12 @@ void kqemu_record_dump(void) perror("/tmp/kqemu.stats"); exit(1); } - fprintf(f, "total: %lld\n", total); + fprintf(f, "total: %" PRId64 "\n", total); sum = 0; for(i = 0; i < nb_pc_records; i++) { r = pr[i]; sum += r->count; - fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n", + fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n", r->pc, r->count, (double)r->count / (double)total * 100.0, diff --git a/tools/ioemu/loader.c b/tools/ioemu/loader.c index b2d6423fed..3fa681dbb0 100644 --- a/tools/ioemu/loader.c +++ b/tools/ioemu/loader.c @@ -200,7 +200,7 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend, int fd, data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { perror(filename); return -1; diff --git a/tools/ioemu/monitor.c b/tools/ioemu/monitor.c index 071c62a35a..5625ad06e0 100644 --- a/tools/ioemu/monitor.c +++ b/tools/ioemu/monitor.c @@ -89,8 +89,10 @@ void term_puts(const char *str) c = *str++; if (c == '\0') break; + if (c == '\n') + term_outbuf[term_outbuf_index++] = '\r'; term_outbuf[term_outbuf_index++] = c; - if (term_outbuf_index >= sizeof(term_outbuf) || + if (term_outbuf_index >= (sizeof(term_outbuf) - 1) || c == '\n') term_flush(); } @@ -546,16 +548,16 @@ static void memory_dump(int count, int format, int wsize, term_printf(" "); switch(format) { case 'o': - term_printf("%#*llo", max_digits, v); + term_printf("%#*" PRIo64, max_digits, v); break; case 'x': - term_printf("0x%0*llx", max_digits, v); + term_printf("0x%0*" PRIx64, max_digits, v); break; case 'u': - term_printf("%*llu", max_digits, v); + term_printf("%*" PRIu64, max_digits, v); break; case 'd': - term_printf("%*lld", max_digits, v); + term_printf("%*" PRId64, max_digits, v); break; case 'c': term_printc(v); @@ -615,17 +617,17 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne #else switch(format) { case 'o': - term_printf("%#llo", val); + term_printf("%#" PRIo64, val); break; case 'x': - term_printf("%#llx", val); + term_printf("%#" PRIx64, val); break; case 'u': - term_printf("%llu", val); + term_printf("%" PRIu64, val); break; default: case 'd': - term_printf("%lld", val); + term_printf("%" PRId64, val); break; case 'c': term_printc(val); @@ -680,6 +682,8 @@ static const KeyDef key_defs[] = { { 0x09, "8" }, { 0x0a, "9" }, { 0x0b, "0" }, + { 0x0c, "minus" }, + { 0x0d, "equal" }, { 0x0e, "backspace" }, { 0x0f, "tab" }, @@ -729,6 +733,24 @@ static const KeyDef key_defs[] = { { 0x45, "num_lock" }, { 0x46, "scroll_lock" }, + { 0xb5, "kp_divide" }, + { 0x37, "kp_multiply" }, + { 0x4a, "kp_substract" }, + { 0x4e, "kp_add" }, + { 0x9c, "kp_enter" }, + { 0x53, "kp_decimal" }, + + { 0x52, "kp_0" }, + { 0x4f, "kp_1" }, + { 0x50, "kp_2" }, + { 0x51, "kp_3" }, + { 0x4b, "kp_4" }, + { 0x4c, "kp_5" }, + { 0x4d, "kp_6" }, + { 0x47, "kp_7" }, + { 0x48, "kp_8" }, + { 0x49, "kp_9" }, + { 0x56, "<" }, { 0x57, "f11" }, @@ -754,11 +776,18 @@ static const KeyDef key_defs[] = { static int get_keycode(const char *key) { const KeyDef *p; + char *endp; + int ret; for(p = key_defs; p->name != NULL; p++) { if (!strcmp(key, p->name)) return p->keycode; } + if (strstart(key, "0x", NULL)) { + ret = strtoul(key, &endp, 0); + if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) + return ret; + } return -1; } @@ -806,6 +835,26 @@ static void do_send_key(const char *string) } } +static int mouse_button_state; + +static void do_mouse_move(const char *dx_str, const char *dy_str, + const char *dz_str) +{ + int dx, dy, dz; + dx = strtol(dx_str, NULL, 0); + dy = strtol(dy_str, NULL, 0); + dz = 0; + if (dz_str) + dz = strtol(dz_str, NULL, 0); + kbd_mouse_event(dx, dy, dz, mouse_button_state); +} + +static void do_mouse_button(int button_state) +{ + mouse_button_state = button_state; + kbd_mouse_event(0, 0, 0, mouse_button_state); +} + #ifndef CONFIG_DM static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index) { @@ -967,7 +1016,6 @@ static void mem_info(void) } } #endif -#endif /* !CONFIG_DM */ static void do_info_kqemu(void) { @@ -998,6 +1046,7 @@ static void do_info_kqemu(void) term_printf("kqemu support: not compiled\n"); #endif } +#endif /* !CONFIG_DM */ #ifdef CONFIG_PROFILER @@ -1015,11 +1064,11 @@ static void do_info_profile(void) total = qemu_time; if (total == 0) total = 1; - term_printf("async time %lld (%0.3f)\n", + term_printf("async time %" PRId64 " (%0.3f)\n", dev_time, dev_time / (double)ticks_per_sec); - term_printf("qemu time %lld (%0.3f)\n", + term_printf("qemu time %" PRId64 " (%0.3f)\n", qemu_time, qemu_time / (double)ticks_per_sec); - term_printf("kqemu time %lld (%0.3f %0.1f%%) count=%lld int=%lld excp=%lld intr=%lld\n", + term_printf("kqemu time %" PRId64 " (%0.3f %0.1f%%) count=%" PRId64 " int=%" PRId64 " excp=%" PRId64 " intr=%" PRId64 "\n", kqemu_time, kqemu_time / (double)ticks_per_sec, kqemu_time / (double)total * 100.0, kqemu_exec_count, @@ -1044,6 +1093,64 @@ static void do_info_profile(void) } #endif +/* Capture support */ +static LIST_HEAD (capture_list_head, CaptureState) capture_head; + +static void do_info_capture (void) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + term_printf ("[%d]: ", i); + s->ops.info (s->opaque); + } +} + +static void do_stop_capture (int n) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + if (i == n) { + s->ops.destroy (s->opaque); + LIST_REMOVE (s, entries); + qemu_free (s); + return; + } + } +} + +#ifdef HAS_AUDIO +int wav_start_capture (CaptureState *s, const char *path, int freq, + int bits, int nchannels); + +static void do_wav_capture (const char *path, + int has_freq, int freq, + int has_bits, int bits, + int has_channels, int nchannels) +{ + CaptureState *s; + + s = qemu_mallocz (sizeof (*s)); + if (!s) { + term_printf ("Not enough memory to add wave capture\n"); + return; + } + + freq = has_freq ? freq : 44100; + bits = has_bits ? bits : 16; + nchannels = has_channels ? nchannels : 2; + + if (wav_start_capture (s, path, freq, bits, nchannels)) { + term_printf ("Faied to add wave capture\n"); + qemu_free (s); + } + LIST_INSERT_HEAD (&capture_head, s, entries); +} +#endif + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -1102,6 +1209,17 @@ static term_cmd_t term_cmds[] = { { "cpu", "i", do_cpu_set, "index", "set the default CPU" }, #endif /* !CONFIG_DM */ + { "mouse_move", "sss?", do_mouse_move, + "dx dy [dz]", "send mouse move events" }, + { "mouse_button", "i", do_mouse_button, + "state", "change mouse button state (1=L, 2=M, 4=R)" }, +#ifdef HAS_AUDIO + { "wavcapture", "si?i?i?", do_wav_capture, + "path [frequency bits channels]", + "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" }, +#endif + { "stopcapture", "i", do_stop_capture, + "capture index", "stop capture" }, { NULL, NULL, }, }; @@ -1135,15 +1253,17 @@ static term_cmd_t info_cmds[] = { #endif { "jit", "", do_info_jit, "", "show dynamic compiler info", }, -#endif /* !CONFIG_DM */ { "kqemu", "", do_info_kqemu, "", "show kqemu information", }, +#endif /* !CONFIG_DM */ { "usb", "", usb_info, "", "show guest USB devices", }, { "usbhost", "", usb_host_info, "", "show host USB devices", }, { "profile", "", do_info_profile, "", "show profiling information", }, + { "capture", "", do_info_capture, + "show capture information" }, #ifdef CONFIG_DM { "hvmiopage", "", sp_info, "", "show HVM device model shared page info", }, @@ -1588,8 +1708,11 @@ static target_long expr_unary(void) n = 0; break; default: - /* XXX: 64 bit version */ +#if TARGET_LONG_BITS == 64 + n = strtoull(pch, &p, 0); +#else n = strtoul(pch, &p, 0); +#endif if (pch == p) { expr_error("invalid char in expression"); } @@ -1955,7 +2078,6 @@ static void monitor_handle_command(const char *cmdline) while (isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { - typestr++; if (*typestr == '?') { if (*p == '\0') has_arg = 0; @@ -1971,6 +2093,7 @@ static void monitor_handle_command(const char *cmdline) has_arg = 0; } } + typestr++; if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)has_arg; @@ -2069,6 +2192,9 @@ static void monitor_handle_command(const char *cmdline) case 6: cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); break; + case 7: + cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + break; default: term_printf("unsupported number of arguments: %d\n", nb_args); goto fail; @@ -2197,6 +2323,7 @@ void readline_find_completion(const char *cmdline) int nb_args, i, len; const char *ptype, *str; term_cmd_t *cmd; + const KeyDef *key; parse_cmdline(cmdline, &nb_args, args); #ifdef DEBUG_COMPLETION @@ -2258,6 +2385,11 @@ void readline_find_completion(const char *cmdline) for(cmd = info_cmds; cmd->name != NULL; cmd++) { cmd_completion(str, cmd->name); } + } else if (!strcmp(cmd->name, "sendkey")) { + completion_index = strlen(str); + for(key = key_defs; key->name != NULL; key++) { + cmd_completion(str, key->name); + } } break; default: diff --git a/tools/ioemu/osdep.c b/tools/ioemu/osdep.c index f2a69d9a71..ffa29fe8e4 100644 --- a/tools/ioemu/osdep.c +++ b/tools/ioemu/osdep.c @@ -29,6 +29,9 @@ #include #include "cpu.h" +#if defined(USE_KQEMU) +#include "vl.h" +#endif #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) @@ -321,13 +324,15 @@ void qemu_vfree(void *ptr) VirtualFree(ptr, 0, MEM_RELEASE); } -#elif defined(USE_KQEMU) +#else + +#if defined(USE_KQEMU) #include #include #include -void *qemu_vmalloc(size_t size) +void *kqemu_vmalloc(size_t size) { static int phys_ram_fd = -1; static int phys_ram_size = 0; @@ -362,6 +367,7 @@ void *qemu_vmalloc(size_t size) "QEMU_TMPDIR environment variable to set another directory where the QEMU\n" "temporary RAM file will be opened.\n"); } + fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n"); exit(1); } } @@ -403,16 +409,20 @@ void *qemu_vmalloc(size_t size) return ptr; } -void qemu_vfree(void *ptr) +void kqemu_vfree(void *ptr) { /* may be useful some day, but currently we do not need to free */ } -#else +#endif /* alloc shared memory pages */ void *qemu_vmalloc(size_t size) { +#if defined(USE_KQEMU) + if (kqemu_allowed) + return kqemu_vmalloc(size); +#endif #ifdef _BSD return valloc(size); #else @@ -422,6 +432,10 @@ void *qemu_vmalloc(size_t size) void qemu_vfree(void *ptr) { +#if defined(USE_KQEMU) + if (kqemu_allowed) + kqemu_vfree(ptr); +#endif free(ptr); } diff --git a/tools/ioemu/osdep.h b/tools/ioemu/osdep.h index f818ce03a8..29a261cbd5 100644 --- a/tools/ioemu/osdep.h +++ b/tools/ioemu/osdep.h @@ -27,6 +27,8 @@ extern void __longjmp(jmp_buf env, int val); #include +struct siginfo; + /* NOTE: it works only because the glibc sigset_t is >= kernel sigset_t */ struct qemu_sigaction { union { diff --git a/tools/ioemu/pc-bios/README b/tools/ioemu/pc-bios/README index 5e61a28fc1..fc85eb4291 100644 --- a/tools/ioemu/pc-bios/README +++ b/tools/ioemu/pc-bios/README @@ -7,11 +7,10 @@ - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm. -- Proll is a GPL'd boot PROM for Sparc JavaStations - (http://people.redhat.com/zaitcev/linux/). - Applying proll.patch allows circumventing some bugs and enables - faster kernel load through a hack. - - video.x is a PowerMac NDRV compatible driver for a VGA frame buffer. It comes from the Mac-on-Linux project (http://www.maconlinux.org/). + +- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable + firmware implementation. The goal is to implement a 100% IEEE + 1275-1994 (referred to as Open Firmware) compliant firmware. diff --git a/tools/ioemu/pc-bios/bios.diff b/tools/ioemu/pc-bios/bios.diff index 647025b889..e87592784a 100644 --- a/tools/ioemu/pc-bios/bios.diff +++ b/tools/ioemu/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v retrieving revision 1.4 diff -u -w -r1.4 apmbios.S --- apmbios.S 26 Dec 2005 10:35:51 -0000 1.4 -+++ apmbios.S 28 Apr 2006 22:41:19 -0000 ++++ apmbios.S 3 May 2006 21:22:46 -0000 @@ -225,6 +225,7 @@ APMSYM(05): cmp al, #0x05 @@ -19,7 +19,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.160 diff -u -w -r1.160 rombios.c --- rombios.c 25 Jan 2006 17:51:49 -0000 1.160 -+++ rombios.c 28 Apr 2006 22:41:21 -0000 ++++ rombios.c 3 May 2006 21:22:48 -0000 @@ -1816,6 +1816,7 @@ { printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", @@ -38,7 +38,137 @@ diff -u -w -r1.160 rombios.c } //-------------------------------------------------------------------------- -@@ -8713,6 +8717,7 @@ +@@ -3999,6 +4003,29 @@ + } + #endif + ++ ++void set_e820_range(ES, DI, start, end, type) ++ Bit16u ES; ++ Bit16u DI; ++ Bit32u start; ++ Bit32u end; ++ Bit16u type; ++{ ++ write_word(ES, DI, start); ++ write_word(ES, DI+2, start >> 16); ++ write_word(ES, DI+4, 0x00); ++ write_word(ES, DI+6, 0x00); ++ ++ end -= start; ++ write_word(ES, DI+8, end); ++ write_word(ES, DI+10, end >> 16); ++ write_word(ES, DI+12, 0x0000); ++ write_word(ES, DI+14, 0x0000); ++ ++ write_word(ES, DI+16, type); ++ write_word(ES, DI+18, 0x0); ++} ++ + void + int15_function32(regs, ES, DS, FLAGS) + pushad_regs_t regs; // REGS pushed via pushad +@@ -4063,19 +4090,8 @@ + switch(regs.u.r16.bx) + { + case 0: +- write_word(ES, regs.u.r16.di, 0x00); +- write_word(ES, regs.u.r16.di+2, 0x00); +- write_word(ES, regs.u.r16.di+4, 0x00); +- write_word(ES, regs.u.r16.di+6, 0x00); +- +- write_word(ES, regs.u.r16.di+8, 0xFC00); +- write_word(ES, regs.u.r16.di+10, 0x0009); +- write_word(ES, regs.u.r16.di+12, 0x0000); +- write_word(ES, regs.u.r16.di+14, 0x0000); +- +- write_word(ES, regs.u.r16.di+16, 0x1); +- write_word(ES, regs.u.r16.di+18, 0x0); +- ++ set_e820_range(ES, regs.u.r16.di, ++ 0x0000000L, 0x0009fc00L, 1); + regs.u.r32.ebx = 1; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4083,6 +4099,24 @@ + return; + break; + case 1: ++ set_e820_range(ES, regs.u.r16.di, ++ 0x0009fc00L, 0x000a0000L, 2); ++ regs.u.r32.ebx = 2; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; ++ break; ++ case 2: ++ set_e820_range(ES, regs.u.r16.di, ++ 0x000e8000L, 0x00100000L, 2); ++ regs.u.r32.ebx = 3; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; ++ break; ++ case 3: + extended_memory_size = inb_cmos(0x35); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x34); +@@ -4092,9 +4126,9 @@ + extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 + } + extended_memory_size *= 1024; +- extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off ++ extended_memory_size += (16L * 1024 * 1024); + +- if(extended_memory_size <= 15728640) ++ if(extended_memory_size <= (16L * 1024 * 1024)) + { + extended_memory_size = inb_cmos(0x31); + extended_memory_size <<= 8; +@@ -4102,28 +4136,23 @@ + extended_memory_size *= 1024; + } + +- write_word(ES, regs.u.r16.di, 0x0000); +- write_word(ES, regs.u.r16.di+2, 0x0010); +- write_word(ES, regs.u.r16.di+4, 0x0000); +- write_word(ES, regs.u.r16.di+6, 0x0000); +- +- write_word(ES, regs.u.r16.di+8, extended_memory_size); +- extended_memory_size >>= 16; +- write_word(ES, regs.u.r16.di+10, extended_memory_size); +- extended_memory_size >>= 16; +- write_word(ES, regs.u.r16.di+12, extended_memory_size); +- extended_memory_size >>= 16; +- write_word(ES, regs.u.r16.di+14, extended_memory_size); +- +- write_word(ES, regs.u.r16.di+16, 0x1); +- write_word(ES, regs.u.r16.di+18, 0x0); +- +- regs.u.r32.ebx = 0; ++ set_e820_range(ES, regs.u.r16.di, ++ 0x00100000L, extended_memory_size, 1); ++ regs.u.r32.ebx = 4; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; ++ case 4: ++ /* 256KB BIOS area at the end of 4 GB */ ++ set_e820_range(ES, regs.u.r16.di, ++ 0xfffc0000L, 0x00000000L, 2); ++ regs.u.r32.ebx = 0; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; + default: /* AX=E820, DX=534D4150, BX unrecognized */ + goto int15_unimplemented; + break; +@@ -8713,6 +8742,7 @@ mov al, #0x80 bios32_end: popf @@ -46,7 +176,7 @@ diff -u -w -r1.160 rombios.c retf .align 16 -@@ -8823,17 +8828,17 @@ +@@ -8823,17 +8853,17 @@ pci_pro_fail: pop edi pop esi @@ -66,7 +196,7 @@ diff -u -w -r1.160 rombios.c retf pci_pro_select_reg: -@@ -8971,7 +8976,7 @@ +@@ -8971,7 +9001,7 @@ jmp pci_real_ok pci_real_f0d: ;; write configuration dword cmp al, #0x0d @@ -75,7 +205,7 @@ diff -u -w -r1.160 rombios.c call pci_real_select_reg push dx mov dx, #0x0cfc -@@ -8979,6 +8984,46 @@ +@@ -8979,6 +9009,46 @@ out dx, eax pop dx jmp pci_real_ok @@ -122,7 +252,7 @@ diff -u -w -r1.160 rombios.c pci_real_unknown: mov ah, #0x81 pci_real_fail: -@@ -9019,6 +9064,7 @@ +@@ -9019,6 +9089,7 @@ dw 0,0 ;; Miniport data db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved db 0x07 ;; checksum @@ -130,7 +260,7 @@ diff -u -w -r1.160 rombios.c ;; first slot entry PCI-to-ISA (embedded) db 0 ;; pci bus number db 0x08 ;; pci device number (bit 7-3) -@@ -9097,6 +9143,7 @@ +@@ -9097,6 +9168,7 @@ dw 0xdef8 ;; IRQ bitmap INTD# db 5 ;; physical slot (0 = embedded) db 0 ;; reserved diff --git a/tools/ioemu/pc-bios/vgabios.diff b/tools/ioemu/pc-bios/vgabios.diff index 73159a0fd0..661c032e46 100644 --- a/tools/ioemu/pc-bios/vgabios.diff +++ b/tools/ioemu/pc-bios/vgabios.diff @@ -4,808 +4,893 @@ RCS file: /sources/vgabios/vgabios/Makefile,v retrieving revision 1.17 diff -u -w -r1.17 Makefile --- Makefile 6 Mar 2005 13:06:47 -0000 1.17 -+++ Makefile 25 Mar 2006 01:19:02 -0000 -@@ -17,9 +17,9 @@ - all: bios cirrus-bios - - --bios: biossums vgabios.bin vgabios.debug.bin -+bios: biossums vgabios.bin #vgabios.debug.bin - --cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin -+cirrus-bios: vgabios-cirrus.bin #vgabios-cirrus.debug.bin ++++ Makefile 14 Jun 2006 00:51:06 -0000 +@@ -22,7 +22,7 @@ + cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin clean: - /bin/rm -f biossums *.o *.s *.ld86 \ +- /bin/rm -f biossums *.o *.s *.ld86 \ ++ /bin/rm -f biossums vbetables-gen vbetables.h *.o *.s *.ld86 \ + temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak + + dist-clean: clean +@@ -79,3 +79,9 @@ + + biossums: biossums.c + $(CC) -o biossums biossums.c ++ ++vbetables-gen: vbetables-gen.c ++ $(CC) -o vbetables-gen vbetables-gen.c ++ ++vbetables.h: vbetables-gen ++ ./vbetables-gen > $@ Index: clext.c =================================================================== RCS file: /sources/vgabios/vgabios/clext.c,v -retrieving revision 1.9 -diff -u -w -r1.9 clext.c ---- clext.c 4 Dec 2004 15:26:17 -0000 1.9 -+++ clext.c 25 Mar 2006 01:19:03 -0000 -@@ -238,6 +238,21 @@ - 0xffff - }; +retrieving revision 1.10 +diff -u -w -r1.10 clext.c +--- clext.c 25 Mar 2006 10:19:15 -0000 1.10 ++++ clext.c 14 Jun 2006 00:51:06 -0000 +@@ -544,6 +544,13 @@ + cirrus_set_video_mode_extended: + call cirrus_switch_mode + pop ax ;; mode ++ test al, #0x80 ++ jnz cirrus_set_video_mode_extended_1 ++ push ax ++ mov ax, #0xffff ; set to 0xff to keep win 2K happy ++ call cirrus_clear_vram ++ pop ax ++cirrus_set_video_mode_extended_1: + and al, #0x7f -+/* 1600x1200x8 */ -+unsigned short cseq_1600x1200x8[] = { -+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, -+0x760b,0x760c,0x760d,0x760e, -+0x0412,0x0013,0x2017, -+0x341b,0x341c,0x341d,0x341e, -+0xffff -+}; -+unsigned short ccrtc_1600x1200x8[] = { -+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, -+0x6009,0x000c,0x000d, -+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, -+0x001a,0x221b,0x001d, -+0xffff -+}; + push ds +@@ -1011,6 +1018,13 @@ + jnz cirrus_vesa_02h_3 + call cirrus_enable_16k_granularity + cirrus_vesa_02h_3: ++ test bx, #0x8000 ;; no clear ++ jnz cirrus_vesa_02h_4 ++ push ax ++ xor ax,ax ++ call cirrus_clear_vram ++ pop ax ++cirrus_vesa_02h_4: + pop ax + push ds + #ifdef CIRRUS_VESA3_PMINFO +@@ -1479,6 +1493,38 @@ + pop bx + ret - cirrus_mode_t cirrus_modes[] = - { -@@ -291,6 +306,10 @@ - cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, - 6,5,11,6,5,5,0,0,0}, - -+ {0x7b,1600,1200,8,0x00, -+ cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8, -+ 4,0,0,0,0,0,0,0,0}, ++cirrus_clear_vram: ++ pusha ++ push es ++ mov si, ax + - {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, - 0xff,0,0,0,0,0,0,0,0}, - {0xff,0,0,0,0,0,0,0,0, ++ call cirrus_enable_16k_granularity ++ call cirrus_extbios_85h ++ shl al, #2 ++ mov bl, al ++ xor ah,ah ++cirrus_clear_vram_1: ++ mov al, #0x09 ++ mov dx, #0x3ce ++ out dx, ax ++ push ax ++ mov cx, #0xa000 ++ mov es, cx ++ xor di, di ++ mov ax, si ++ mov cx, #8192 ++ cld ++ rep ++ stosw ++ pop ax ++ inc ah ++ cmp ah, bl ++ jne cirrus_clear_vram_1 ++ ++ pop es ++ popa ++ ret ++ + cirrus_extbios_handlers: + ;; 80h + dw cirrus_extbios_80h +Index: vbe.c +=================================================================== +RCS file: /sources/vgabios/vgabios/vbe.c,v +retrieving revision 1.48 +diff -u -w -r1.48 vbe.c +--- vbe.c 26 Dec 2005 19:50:26 -0000 1.48 ++++ vbe.c 14 Jun 2006 00:51:07 -0000 +@@ -118,21 +118,114 @@ + .word VBE_VESA_MODE_END_OF_LIST + #endif + ++ .align 2 + vesa_pm_start: + dw vesa_pm_set_window - vesa_pm_start +- dw vesa_pm_set_display_strt - vesa_pm_start ++ dw vesa_pm_set_display_start - vesa_pm_start + dw vesa_pm_unimplemented - vesa_pm_start +- dw 0 ++ dw vesa_pm_io_ports_table - vesa_pm_start ++vesa_pm_io_ports_table: ++ dw VBE_DISPI_IOPORT_INDEX ++ dw VBE_DISPI_IOPORT_INDEX + 1 ++ dw VBE_DISPI_IOPORT_DATA ++ dw VBE_DISPI_IOPORT_DATA + 1 ++ dw 0xffff ++ dw 0xffff + + USE32 + vesa_pm_set_window: +- mov ax, #0x4f05 +- int #0x10 ++ cmp bx, #0x00 ++ je vesa_pm_set_display_window1 ++ mov ax, #0x0100 ++ ret ++vesa_pm_set_display_window1: ++ mov ax, dx ++ push dx ++ push ax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_BANK ++ out dx, ax ++ pop ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ out dx, ax ++ pop dx ++ mov ax, #0x004f + ret + + vesa_pm_set_display_start: +- mov ax, #0x4f07 +- int #0x10 ++ cmp bl, #0x80 ++ je vesa_pm_set_display_start1 ++ cmp bl, #0x00 ++ je vesa_pm_set_display_start1 ++ mov ax, #0x0100 ++ ret ++vesa_pm_set_display_start1: ++; convert offset to (X, Y) coordinate ++; (would be simpler to change Bochs VBE API...) ++ push eax ++ push ecx ++ push edx ++ push esi ++ push edi ++ shl edx, #16 ++ and ecx, #0xffff ++ or ecx, edx ++ shl ecx, #2 ++ mov eax, ecx ++ ++ push eax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH ++ out dx, ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ in ax, dx ++ movzx ecx, ax ++ ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_BPP ++ out dx, ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ in ax, dx ++ movzx esi, ax ++ pop eax ++ ++ add esi, #7 ++ shr esi, #3 ++ imul ecx, esi ++ xor edx, edx ++ div ecx ++ mov edi, eax ++ mov eax, edx ++ xor edx, edx ++ div esi ++ ++ push dx ++ push ax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_X_OFFSET ++ out dx, ax ++ pop ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ out dx, ax ++ pop dx ++ ++ mov ax, di ++ push dx ++ push ax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_Y_OFFSET ++ out dx, ax ++ pop ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ out dx, ax ++ pop dx ++ ++ pop edi ++ pop esi ++ pop edx ++ pop ecx ++ pop eax ++ mov ax, #0x004f + ret + + vesa_pm_unimplemented: +@@ -835,6 +928,64 @@ + ASM_END + + ++Bit16u vbe_biosfn_read_video_state_size() ++{ ++ return 9 * 2; ++} ++ ++void vbe_biosfn_save_video_state(ES, BX) ++ Bit16u ES; Bit16u BX; ++{ ++ Bit16u enable, i; ++ ++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); ++ enable = inw(VBE_DISPI_IOPORT_DATA); ++ write_word(ES, BX, enable); ++ BX += 2; ++ if (!(enable & VBE_DISPI_ENABLED)) ++ return; ++ for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { ++ if (i != VBE_DISPI_INDEX_ENABLE) { ++ outw(VBE_DISPI_IOPORT_INDEX, i); ++ write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA)); ++ BX += 2; ++ } ++ } ++} ++ ++ ++void vbe_biosfn_restore_video_state(ES, BX) ++ Bit16u ES; Bit16u BX; ++{ ++ Bit16u enable, i; ++ ++ enable = read_word(ES, BX); ++ BX += 2; ++ ++ if (!(enable & VBE_DISPI_ENABLED)) { ++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); ++ outw(VBE_DISPI_IOPORT_DATA, enable); ++ } else { ++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); ++ outw(VBE_DISPI_IOPORT_DATA, enable); ++ ++ for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { ++ outw(VBE_DISPI_IOPORT_INDEX, i); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ } ++ } ++} ++ + /** Function 04h - Save/Restore State + * + * Input: +@@ -849,10 +1000,48 @@ + * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h) + * + */ +-void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX) ++void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX) ++Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX; + { +-} ++ Bit16u ss=get_SS(); ++ Bit16u result, val; + ++ result = 0x4f; ++ switch(GET_DL()) { ++ case 0x00: ++ val = biosfn_read_video_state_size2(CX); ++#ifdef DEBUG ++ printf("VGA state size=%x\n", val); ++#endif ++ if (CX & 8) ++ val += vbe_biosfn_read_video_state_size(); ++ write_word(ss, BX, val); ++ break; ++ case 0x01: ++ val = read_word(ss, BX); ++ val = biosfn_save_video_state(CX, ES, val); ++#ifdef DEBUG ++ printf("VGA save_state offset=%x\n", val); ++#endif ++ if (CX & 8) ++ vbe_biosfn_save_video_state(ES, val); ++ break; ++ case 0x02: ++ val = read_word(ss, BX); ++ val = biosfn_restore_video_state(CX, ES, val); ++#ifdef DEBUG ++ printf("VGA restore_state offset=%x\n", val); ++#endif ++ if (CX & 8) ++ vbe_biosfn_restore_video_state(ES, val); ++ break; ++ default: ++ // function failed ++ result = 0x100; ++ break; ++ } ++ write_word(ss, AX, result); ++} + + /** Function 05h - Display Window Control + * +@@ -1090,7 +1279,7 @@ + */ + ASM_START + vbe_biosfn_return_protected_mode_interface: +- test bx, bx ++ test bl, bl + jnz _fail + mov di, #0xc000 + mov es, di +Index: vbe.h +=================================================================== +RCS file: /sources/vgabios/vgabios/vbe.h,v +retrieving revision 1.24 +diff -u -w -r1.24 vbe.h +--- vbe.h 9 May 2004 20:31:31 -0000 1.24 ++++ vbe.h 14 Jun 2006 00:51:07 -0000 +@@ -14,7 +14,7 @@ + void vbe_biosfn_return_controller_information(AX, ES, DI); + void vbe_biosfn_return_mode_information(AX, CX, ES, DI); + void vbe_biosfn_set_mode(AX, BX, ES, DI); +-void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX); ++void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX); + void vbe_biosfn_set_get_palette_data(AX); + void vbe_biosfn_return_protected_mode_interface(AX); + +@@ -151,6 +151,12 @@ + Bit8u Reserved[189]; + } ModeInfoBlock; + ++typedef struct ModeInfoListItem ++{ ++ Bit16u mode; ++ ModeInfoBlockCompact info; ++} ModeInfoListItem; ++ + // VBE Return Status Info + // AL + #define VBE_RETURN_STATUS_SUPPORTED 0x4F +@@ -193,6 +199,10 @@ + #define VBE_VESA_MODE_1280X1024X1555 0x119 + #define VBE_VESA_MODE_1280X1024X565 0x11A + #define VBE_VESA_MODE_1280X1024X888 0x11B ++#define VBE_VESA_MODE_1600X1200X8 0x11C ++#define VBE_VESA_MODE_1600X1200X1555 0x11D ++#define VBE_VESA_MODE_1600X1200X565 0x11E ++#define VBE_VESA_MODE_1600X1200X888 0x11F + + // BOCHS/PLEX86 'own' mode numbers + #define VBE_OWN_MODE_320X200X8888 0x140 +@@ -202,6 +212,12 @@ + #define VBE_OWN_MODE_1024X768X8888 0x144 + #define VBE_OWN_MODE_1280X1024X8888 0x145 + #define VBE_OWN_MODE_320X200X8 0x146 ++#define VBE_OWN_MODE_1600X1200X8888 0x147 ++#define VBE_OWN_MODE_1152X864X8 0x148 ++#define VBE_OWN_MODE_1152X864X1555 0x149 ++#define VBE_OWN_MODE_1152X864X565 0x14a ++#define VBE_OWN_MODE_1152X864X888 0x14b ++#define VBE_OWN_MODE_1152X864X8888 0x14c + + #define VBE_VESA_MODE_END_OF_LIST 0xFFFF + +@@ -259,7 +275,7 @@ + // like 0xE0000000 + + +- #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4 ++ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8 + + #define VBE_DISPI_BANK_ADDRESS 0xA0000 + #define VBE_DISPI_BANK_SIZE_KB 64 Index: vgabios.c =================================================================== RCS file: /sources/vgabios/vgabios/vgabios.c,v -retrieving revision 1.63 -diff -u -w -r1.63 vgabios.c ---- vgabios.c 26 Dec 2005 19:50:26 -0000 1.63 -+++ vgabios.c 25 Mar 2006 01:19:03 -0000 -@@ -111,6 +111,7 @@ +retrieving revision 1.64 +diff -u -w -r1.64 vgabios.c +--- vgabios.c 25 Mar 2006 10:19:16 -0000 1.64 ++++ vgabios.c 14 Jun 2006 00:51:07 -0000 +@@ -109,8 +109,8 @@ + static void biosfn_write_string(); + static void biosfn_read_state_info(); static void biosfn_read_video_state_size(); - static void biosfn_save_video_state(); - static void biosfn_restore_video_state(); -+extern Bit8u video_save_pointer_table[]; +-static void biosfn_save_video_state(); +-static void biosfn_restore_video_state(); ++static Bit16u biosfn_save_video_state(); ++static Bit16u biosfn_restore_video_state(); + extern Bit8u video_save_pointer_table[]; // This is for compiling with gcc2 and gcc3 - #define ASM_START #asm -@@ -459,6 +460,29 @@ - - pop ds - ret -+ -+_video_save_pointer_table: -+ .word _video_param_table -+ .word 0xc000 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ - ASM_END +@@ -748,12 +748,7 @@ + vbe_biosfn_set_mode(&AX,BX,ES,DI); + break; + case 0x04: +- //FIXME +-#ifdef DEBUG +- unimplemented(); +-#endif +- // function failed +- AX=0x100; ++ vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX); + break; + case 0x09: + //FIXME +@@ -3138,23 +3133,215 @@ + } // -------------------------------------------------------------------------------------------- -@@ -780,8 +804,8 @@ - - // Should we clear the screen ? - Bit8u noclearmem=mode&0x80; -- Bit8u line,mmask,*palette; -- Bit16u i,twidth,theight,cheight; -+ Bit8u line,mmask,*palette,vpti; -+ Bit16u i,twidth,theightm1,cheight; - Bit8u modeset_ctl,video_ctl,vga_switches; - Bit16u crtc_addr; - -@@ -804,9 +828,10 @@ - if(line==0xFF) - return; - -- twidth=vga_modes[line].twidth; -- theight=vga_modes[line].theight; -- cheight=vga_modes[line].cheight; -+ vpti=line_to_vpti[line]; -+ twidth=video_param_table[vpti].twidth; -+ theightm1=video_param_table[vpti].theightm1; -+ cheight=video_param_table[vpti].cheight; - - // Read the bios vga control - video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL); -@@ -866,21 +891,25 @@ - inb(VGAREG_ACTL_RESET); - - // Set Attribute Ctl -- for(i=0;i<=ACTL_MAX_REG;i++) -+ for(i=0;i<=0x13;i++) - {outb(VGAREG_ACTL_ADDRESS,i); -- outb(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]); -+ outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]); - } -+ outb(VGAREG_ACTL_ADDRESS,0x14); -+ outb(VGAREG_ACTL_WRITE_DATA,0x00); - - // Set Sequencer Ctl -- for(i=0;i<=SEQU_MAX_REG;i++) -+ outb(VGAREG_SEQU_ADDRESS,0); -+ outb(VGAREG_SEQU_DATA,0x03); -+ for(i=1;i<=4;i++) - {outb(VGAREG_SEQU_ADDRESS,i); -- outb(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]); -+ outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]); - } - - // Set Grafx Ctl -- for(i=0;i<=GRDC_MAX_REG;i++) -+ for(i=0;i<=8;i++) - {outb(VGAREG_GRDC_ADDRESS,i); -- outb(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]); -+ outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]); - } - - // Set CRTC address VGA or MDA -@@ -889,13 +918,13 @@ - // Disable CRTC write protection - outw(crtc_addr,0x0011); - // Set CRTC regs -- for(i=0;i<=CRTC_MAX_REG;i++) -+ for(i=0;i<=0x18;i++) - {outb(crtc_addr,i); -- outb(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]); -+ outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]); - } - - // Set the misc register -- outb(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg); -+ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg); - - // Enable video - outb(VGAREG_ACTL_ADDRESS,0x20); -@@ -927,9 +956,9 @@ - // Set the BIOS mem - write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode); - write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth); -- write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength); -+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l); - write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr); -- write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1); -+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1); - write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight); - write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem)); - write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9); -@@ -937,8 +966,8 @@ - - // FIXME We nearly have the good tables. to be reworked - write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now -- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00); -- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00); -+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table); -+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000); - - // FIXME - write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but... -@@ -1114,7 +1143,7 @@ - } - else - { -- address = page*vga_modes[line].slength; -+ address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l); - } - - // CRTC regs 0x0c and 0x0d -@@ -1271,7 +1300,7 @@ - else - { - // FIXME gfx mode not complete -- cheight=vga_modes[line].cheight; -+ cheight=video_param_table[line_to_vpti[line]].cheight; - switch(vga_modes[line].memmodel) - { - case PLANAR4: -@@ -1581,7 +1610,7 @@ - else - { - // FIXME gfx mode not complete -- cheight=vga_modes[line].cheight; -+ cheight=video_param_table[line_to_vpti[line]].cheight; - bpp=vga_modes[line].pixbits; - while((count-->0) && (xcurs0) && (xcurs ++#include ++ ++typedef struct { ++ int width; ++ int height; ++ int depth; ++ int mode; ++} ModeInfo; ++ ++ModeInfo modes[] = { ++ /* standard VESA modes */ ++{ 640, 400, 8 , 0x100}, ++{ 640, 480, 8 , 0x101}, ++{ 800, 600, 4 , 0x102}, ++{ 800, 600, 8 , 0x103}, ++ //{ 1024, 768, 4 , 0x104}, ++{ 1024, 768, 8 , 0x105}, ++ //{ 1280, 1024, 4 , 0x106}, ++{ 1280, 1024, 8 , 0x107}, ++{ 320, 200, 15 , 0x10D}, ++{ 320, 200, 16 , 0x10E}, ++{ 320, 200, 24 , 0x10F}, ++{ 640, 480, 15 , 0x110}, ++{ 640, 480, 16 , 0x111}, ++{ 640, 480, 24 , 0x112}, ++{ 800, 600, 15 , 0x113}, ++{ 800, 600, 16 , 0x114}, ++{ 800, 600, 24 , 0x115}, ++{ 1024, 768, 15 , 0x116}, ++{ 1024, 768, 16 , 0x117}, ++{ 1024, 768, 24 , 0x118}, ++{ 1280, 1024, 15 , 0x119}, ++{ 1280, 1024, 16 , 0x11A}, ++{ 1280, 1024, 24 , 0x11B}, ++{ 1600, 1200, 8 , 0x11C}, ++{ 1600, 1200, 15 , 0x11D}, ++{ 1600, 1200, 16 , 0x11E}, ++{ 1600, 1200, 24 , 0x11F}, ++ ++ /* BOCHS/PLE, 86 'own' mode numbers */ ++{ 320, 200, 32 , 0x140}, ++{ 640, 400, 32 , 0x141}, ++{ 640, 480, 32 , 0x142}, ++{ 800, 600, 32 , 0x143}, ++{ 1024, 768, 32 , 0x144}, ++{ 1280, 1024, 32 , 0x145}, ++{ 320, 200, 8 , 0x146}, ++{ 1600, 1200, 32 , 0x147}, ++{ 1152, 864, 8 , 0x148}, ++{ 1152, 864, 15 , 0x149}, ++{ 1152, 864, 16 , 0x14a}, ++{ 1152, 864, 24 , 0x14b}, ++{ 1152, 864, 32 , 0x14c}, ++{ 0, }, ++}; ++ ++int main(int argc, char **argv) ++{ ++ const ModeInfo *pm; ++ int pitch, r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos; ++ const char *str; ++ ++ printf("/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT */\n"); ++ printf("static ModeInfoListItem mode_info_list[]=\n"); ++ printf("{\n"); ++ for(pm = modes; pm->mode != 0; pm++) { ++ printf("{ 0x%04x, /* %dx%dx%d */\n", ++ pm->mode, pm->width, pm->height, pm->depth); ++ printf("{ /*Bit16u ModeAttributes*/ %s,\n", ++ "VBE_MODE_ATTRIBUTE_SUPPORTED | " ++ "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | " ++ "VBE_MODE_ATTRIBUTE_COLOR_MODE | " ++ "VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | " ++ "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE"); ++ ++ printf("/*Bit8u WinAAttributes*/ %s,\n", ++ "VBE_WINDOW_ATTRIBUTE_RELOCATABLE | " ++ "VBE_WINDOW_ATTRIBUTE_READABLE | " ++ "VBE_WINDOW_ATTRIBUTE_WRITEABLE"); ++ ++ printf("/*Bit8u WinBAttributes*/ %d,\n", 0); ++ ++ printf("/*Bit16u WinGranularity*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB"); ++ ++ printf("/*Bit16u WinSize*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB"); ++ ++ printf("/*Bit16u WinASegment*/ %s,\n", "VGAMEM_GRAPH"); ++ ++ printf("/*Bit16u WinBSegment*/ 0x%04x,\n", 0); ++ ++ printf("/*Bit32u WinFuncPtr*/ %d,\n", 0); ++ ++ if (pm->depth == 4) ++ pitch = (pm->width + 7) / 8; ++ else ++ pitch = pm->width * ((pm->depth + 7) / 8); ++ printf("/*Bit16u BytesPerScanLine*/ %d,\n", pitch); ++ ++ // Mandatory information for VBE 1.2 and above ++ printf("/*Bit16u XResolution*/ %d,\n", pm->width); ++ printf("/*Bit16u YResolution*/ %d,\n", pm->height); ++ printf("/*Bit8u XCharSize*/ %d,\n", 8); ++ printf("/*Bit8u YCharSize*/ %d,\n", 16); ++ if (pm->depth == 4) { ++ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 4); ++ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth); ++ } else { ++ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 1); ++ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth); ++ } ++ printf("/*Bit8u NumberOfBanks*/ %d,\n", ++ (pm->height * pitch + 65535) / 65536); ++ ++ if (pm->depth == 4) ++ str = "VBE_MEMORYMODEL_PLANAR"; ++ else if (pm->depth == 8) ++ str = "VBE_MEMORYMODEL_PACKED_PIXEL"; ++ else ++ str = "VBE_MEMORYMODEL_DIRECT_COLOR"; ++ printf("/*Bit8u MemoryModel*/ %s,\n", str); ++ printf("/*Bit8u BankSize*/ %d,\n", 0); ++ /* XXX: check */ ++ printf("/*Bit8u NumberOfImagePages*/ %d,\n", 0); ++ printf("/*Bit8u Reserved_page*/ %d,\n", 0); ++ ++ // Direct Color fields (required for direct/6 and YUV/7 memory models) ++ switch(pm->depth) { ++ case 15: ++ r_size = 5; ++ r_pos = 10; ++ g_size = 5; ++ g_pos = 5; ++ b_size = 5; ++ b_pos = 0; ++ a_size = 1; ++ a_pos = 15; ++ break; ++ case 16: ++ r_size = 5; ++ r_pos = 11; ++ g_size = 6; ++ g_pos = 5; ++ b_size = 5; ++ b_pos = 0; ++ a_size = 0; ++ a_pos = 0; ++ break; ++ case 24: ++ r_size = 8; ++ r_pos = 16; ++ g_size = 8; ++ g_pos = 8; ++ b_size = 8; ++ b_pos = 0; ++ a_size = 0; ++ a_pos = 0; ++ break; ++ case 32: ++ r_size = 8; ++ r_pos = 16; ++ g_size = 8; ++ g_pos = 8; ++ b_size = 8; ++ b_pos = 0; ++ a_size = 8; ++ a_pos = 24; ++ break; ++ default: ++ r_size = 0; ++ r_pos = 0; ++ g_size = 0; ++ g_pos = 0; ++ b_size = 0; ++ b_pos = 0; ++ a_size = 0; ++ a_pos = 0; ++ break; ++ } ++ ++ printf("/*Bit8u RedMaskSize*/ %d,\n", r_size); ++ printf("/*Bit8u RedFieldPosition*/ %d,\n", r_pos); ++ printf("/*Bit8u GreenMaskSize*/ %d,\n", g_size); ++ printf("/*Bit8u GreenFieldPosition*/ %d,\n", g_pos); ++ printf("/*Bit8u BlueMaskSize*/ %d,\n", b_size); ++ printf("/*Bit8u BlueFieldPosition*/ %d,\n", b_pos); ++ printf("/*Bit8u RsvdMaskSize*/ %d,\n", a_size); ++ printf("/*Bit8u RsvdFieldPosition*/ %d,\n", a_pos); ++ printf("/*Bit8u DirectColorModeInfo*/ %d,\n", 0); ++ ++// Mandatory information for VBE 2.0 and above ++ printf("/*Bit32u PhysBasePtr*/ %s,\n", ++ "VBE_DISPI_LFB_PHYSICAL_ADDRESS"); ++ printf("/*Bit32u OffScreenMemOffset*/ %d,\n", 0); ++ printf("/*Bit16u OffScreenMemSize*/ %d,\n", 0); ++ // Mandatory information for VBE 3.0 and above ++ printf("/*Bit16u LinBytesPerScanLine*/ %d,\n", pitch); ++ printf("/*Bit8u BnkNumberOfPages*/ %d,\n", 0); ++ printf("/*Bit8u LinNumberOfPages*/ %d,\n", 0); ++ printf("/*Bit8u LinRedMaskSize*/ %d,\n", r_size); ++ printf("/*Bit8u LinRedFieldPosition*/ %d,\n", r_pos); ++ printf("/*Bit8u LinGreenMaskSize*/ %d,\n", g_size); ++ printf("/*Bit8u LinGreenFieldPosition*/ %d,\n", g_pos); ++ printf("/*Bit8u LinBlueMaskSize*/ %d,\n", b_size); ++ printf("/*Bit8u LinBlueFieldPosition*/ %d,\n", b_pos); ++ printf("/*Bit8u LinRsvdMaskSize*/ %d,\n", a_size); ++ printf("/*Bit8u LinRsvdFieldPosition*/ %d,\n", a_pos); ++ printf("/*Bit32u MaxPixelClock*/ %d,\n", 0); ++ printf("} },\n"); ++ } ++ printf("{ VBE_VESA_MODE_END_OF_LIST,\n"); ++ printf("{ 0,\n"); ++ printf("} },\n"); ++ printf("};\n"); ++ return 0; ++} diff --git a/tools/ioemu/pc-bios/video.x b/tools/ioemu/pc-bios/video.x new file mode 100644 index 0000000000000000000000000000000000000000..761aa0c9d47fc3648a64ccfe9b9747b2a3af9572 GIT binary patch literal 12192 zcmd5?e{fV)mOiihC22!|M%%4c0%;(+jYKwTTwmO zv3Ntt$R;;3}B z#}YBJXKw87?22_Kb}s3Tf&VyqX$PdLs}bb(P>HK)i+6R#Ck?IZXiJQf+gw-0CgZ-F z9k;6O!5A$~b}iowp*uFUZN4|w)Uu|tyJZ4$O?O)&Cb0LdYLJqQt1hiZ=(;DiV-h;j z8nafRCKhk*ZtG$z)pS~@x)r=|?13s)(sy)>3V(f3A*BzPlccyv`5V*@lcIZEPp1{~ z?3-hbYCvfl^NQ1MGHPk&@1xwtKSQBfZ4QNXkNfF+3<>}}{x^X>N>oe5PXOek=n0TGkbz@WRHS-r4#IcM^7tU5TH=9;5n`^O$A^(*#R|{>72#iG?Gm zN1`f2S0q})P|aK$r(Pfze@=N}N0aRf+x|L=-b{M739rA=OonYA(S|<+FkX);UX9F8 zbhke_-rtMyDj8+y56iXUJ_Bo)R;eFQ1snkM0Pf*AZCa2J%XjR!dEWLxefP{H`-D+4 zf#=6q{|d=r~>W*^zixv!e`Lu@Y@$K2hZ!Y$8aC1kw>Oq z3LwhrqeEnsY&$1J(cJla^^zc8rHXHr1CiAS+cSL_^W>P=0AgRA~TT;Ii zO0vBN+|&|;ZESmjj}H4KVPlVDKeQS%;Ug2rMN&_mhW}8NzW;pVn$i64V7$+G2)<+Z zHNDyO4Ej8J-@GK#M*97l)=w_onCq)IFU}8{hzBJfgu^}N3AA68He8E+)5!bg1<37O zJ4|h@Uxq%z&9Lik*cIy|?3#jIXHtIZn9G;C@RcRslVjgfz6+;9`ypSkC0{PtZ2JXR zwru_yH9vOhfITs>4Sya`C)i)~b8JLh6nka@{p9hVa6kKzLx$I|XEerZImTnnX;7u_ zvtC!=Z_A^MV2*D(9y)!0FpK=WA11_~)XZ!?$osEY*Z^@ST|%CE^Q%+o)Z`eF8H1er z4K&YX+Yk2M{|5bUWYT|~J#{Kb=!hE;dV3LUyFSxaSW?PDFYF6@t+!}T?RMHN(_UHV z`K&rL&__zd$o~#(R)9U|(T#b@h?>7BLIo*nUvnHLo!4E5TVQXyFs>qOkdI?2>VDLV zF{T`C<`F=>G&DwT2|2zLqwNCp0Wv>6D_`S&!$pVm5(WZwF zqVAG)zk|QfN9-F2&oI;edUk&m`GNue47$l3?isgBnXn5?%XX=yYaRt#K0_!C`B^sj z_Sc@Px$MJyMSNf$IP+{@yHY%2eH`cCkbV9QAcv8*WgGDR3o}p6KoR-TjGqlFv}gn| z7Vu7-c`lY8?R@C%8!n;Uy4&Rg-Xqt0JpZxJLJTMECx~}>6X#+(bNrHiIKBqP!{D0- zzAE_QJhydZKK5TO`#`or#492HU?0}HkKDjT*;eVk%e->RlSdtb9uooP=aS`0^pJlG z=Co|}HGHn5k8u#bl}AdoLEd4NTJ=1_xoP>C@K@{+%;T*xT4I{o+>ScuCXWNco|j{M zw)JNl_MIlmJcr-|!(}DrC5|6*zkAEzyJ&m%uYUx%%M_aR@q2pMp!)GTw6=)b%#8sS%lx+-F5 zn8(-BwB?R*%)9EF+$FxvK4RVY?_20MJOurMpg}AWdkk{zGj@|}Xk5RkFFWMswMcM3 z^xJ~<3-kK&Sf{?+uBE9P9CUwjec6B6KPUUIG7R}SCSTq+tjD+?Dg%&TwfwNidH;j% zO1m}$KYWo2InIGkKK7D;BfO8%2J}ccO+v36cXd@1ci28j*GGRQ@O^Z>?7wlihZYN( zJ}N{#EbB$6H^{nbG*K<=>cx6RaF%&d=X@OJ2%SVdfVz(Q5$p+j{@K`9mP~!P6S0g3 zX|Ci~$`Cr-2%0_EH?H(XQ( zvq=Fg3XO_<$S>wOQBYA!*Ivi>RDE|rMe3zb*`}B8QLrDM5pZKGUO4Uf<9Xu#i!+6A z$0zo6yk`_6FIfvXEA$Sj%n$Zk$^5llBt~slx`u|0wkOgRnDb z*?yDtp3xLVpRG4+p@QZOL4yvb%+5R;B;wC$4`UM*59ibMkmEY+qe0mHWQ4Gf`mv85 zwe}HmL5}B!gvomI{4db%sy9EG57=67{()@}1#AOc3%D1svEKaeQ-HM?R}F|U0!c~%Jji{^MAMQ4Q5O(y6QgFbmep9Rq8 zgx2dS&(x>h{NEYidl+*467Ue@<@SEa!Se4z`xd}GkYgQSf4zB*<dg9gbvA#p#N zew8f`<{OW_ne%C**w-)Nd>q53I!MJ;Mps-@w{;<(=h$`_=X|)zXzS3_#3qR|fb&~< z{q}^!t;ZS-R2l7En!2M~;#z@Az&^AVtpv@!Ez{d8#jeU{hP@!mKj-W&JNOX@E! z*r~sBTatYT@v{m=gT6&U>poEw8nWIIuxH1Rk5y^MsRrlw?bbQr`mC0U=0`y*&x&BG z`9E;3yM3IyVQd&FvOKWM$MaS49%-d+98qDp}UvfWgybJzA;{5bzPmzN43P;p) zFY0-LaJ7LqeXFm1U^BVb82O82?i(=*ATMNquX$1T%DOFkjYW^M+0vyV1U{Hoiwq&A zx@jTuG-5jVIl+!@9yoUV%3R&2#dcyL{itcq7fQ zzxCeB_CJa@-?ydx;cKav`3#@(_rhmWGj~EK&Oya}*~X`LVI1t7>OY+{j-vjGpb_uk zVxRQ7*VajB$d5_vk{AljUx4PZRS32sLye-YE`eabVBu@7v-9pE5x71%I!2Ky2|1lj(D`N z3A`tcJHX=%MS<-U>)kseUmMRi`b`7!z017dv)?G+(2p(PwdJ^Of;OUAJdQID88^ej zPvTt{zp0FrP(I?V7k6Mk{4RjlQHuI>)H!Bwd}ZJDqF#i0fa^{<>{zF7LT(o={j#cg z#vPh5{YO>(J9@CE{-OqNZhSUn=~L}Krqv&rmyNzSbBz9T+`AVGpv+xZ&`*X+`a*oNu>s z!`HP}gg*t*{}B4Uz%P(EA8?hx6#*Au-0Io+&!HW_++N{}ub7vhvlnfT*!vh$8HGRc z9KEDf8dR?Jm?OLT*F95tzsRx6cJ(iKeAk}&|GsNapixIX^Sq=5O^W z8bL45uFZdy)c>)(@d1@)fMl?CpJToG}%`lBpm38)CkD zOpg{M;5#=!M=$av;@{zbKN1=h=atSfr$>-FY^FZgVL zjumpuO|WAS=cleA=0hL7?*;2j3_T>?_KQ+S>2>h-h78l>aRab7crFB8i=eahXoen^ z&e`Ve(RDFzsT{-e`X|i$BiIOYmKBRV;0YO6*HJm=W!|l@C;yhx&b|cL06so_Q$fPX z3;VrL$l5n<+hN!?P~D^S!?ux3+u}D>_9y;LgMSAJ*z0x2QQ;Hk#P6y&3vE2hnQJWe z`I~(qT)M8a^Z{Q_Xs+6jn)lDJyYhuz>=%0{)pt56=S40xao*I>M@i%|6yo^}^8@Sw zj$i%(@U&&XZ@fyV5^ut)pLoobcwp{u*({TP>p|{B9`+ZJPr&Z5mpAn^&h$r4CsQXs zO|pLY-EJ1=AE5JKAGd?f&%ZhA*Pn0X_$h60HVf`e@Z+;=J?02AZ`2!6=ijtyrQeBt z0bAc->m%07T4#p2I<3WY@)8kHZ%A=9ky99i0B zIbwu3i?M$4?&sB_)?Jd{taK8ofCdPx-^<@Qr4z>l=bNYN;G|3 zX-U7UwC+`u_PukIuD#VtLOY$&W{`zG+0#em!6NJJ33p|`@gx-+#|V2vd0FIckP$eQamG7XXOqf$N~j$D zBEN*)C(YM`Gbzn^ANU##_^t=v7xB9#@ctb5vK)BIfe+@u7v;eFa^OpI;LCI1D{|mH zIq+Hzd~ptZRSvwG1Mkg-x7VBP&;8>2F02Euft^d)WBxdphf{-2qCAVVv>Z+#0(iS`h!+BQ!Jn*8 zAOqHid4cV>EWG8`LfV>$ZQ;J@%bS{4bTqVeY)gtSB^l@ZQxwsf=3RJ&fli|Ab)}=F zd;9jbmQH5LpEtHOwc{hjz^10Q_E?Lc@jeTgPoO}D8TfY9`x}%GP={XLRulu}5K0mn;B~9Hei<{!H>Xw%7SUfIS1%k^K^GB&X2L>&VZSCydxvHzF*`6yf2ff#fpgfN< ziUPY{^EwLbc+D6J=Dg+{%6X(<80+((lxGxgM%(W910RrmL41N$W)+_S+yF`%We{Zu zWf)}y<$07*l#?j0qrB;$8$+e-v7tE$=#T9fn zFIiEu6f%B0+CcDDI8^y9x87E9`(NInRW@yGZi#K$+}gI~{`RdMom~%f#}nJO??~=^ zkoCVju6ps3nx)IWTU&Q`eZ%s5Ry3}>cU5HdeQVaP`yP+0x@UDm!y>ND9YERt&B~l| zjN6xGY&KjY#u+I7%j4&8o97z4jGK#iQgQ|b`%aXzj=GI=!r#jN-#Es721Wkg{rw-@ C=6}@y literal 0 HcmV?d00001 diff --git a/tools/ioemu/qemu-doc.texi b/tools/ioemu/qemu-doc.texi index 9e4735016e..1e49ccfab3 100644 --- a/tools/ioemu/qemu-doc.texi +++ b/tools/ioemu/qemu-doc.texi @@ -78,6 +78,7 @@ For system emulation, the following hardware targets are supported: @item Sun4u (64-bit Sparc processor, in progress) @item Malta board (32-bit MIPS processor) @item ARM Integrator/CP (ARM926E or 1026E processor) +@item ARM Versatile baseboard (ARM926E) @end itemize For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported. @@ -227,6 +228,10 @@ Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@pxref{disk_images}). +@item -no-fd-bootchk +Disable boot signature checking for floppy disks in Bochs BIOS. It may +be needed to boot from old floppy disks. + @item -m megs Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. @@ -245,16 +250,19 @@ with a serial console. @item -vnc d Normally, QEMU uses SDL to display the VGA output. With this option, -you can have QEMU listen on VNC display d and redirect the VGA display -over the VNC session. It is very useful to enable the usb tablet device -when using this option (option @option{-usbdevice tablet}). +you can have QEMU listen on VNC display @var{d} and redirect the VGA +display over the VNC session. It is very useful to enable the usb +tablet device when using this option (option @option{-usbdevice +tablet}). When using the VNC display, you must use the @option{-k} +option to set the keyboard layout. @item -k language Use keyboard layout @var{language} (for example @code{fr} for French). This option is only needed where it is not easy to get raw PC -keycodes (e.g. on Macs or with some X11 servers). You don't need to -use it on PC/Linux or PC/Windows hosts. +keycodes (e.g. on Macs, with some X11 servers or with a VNC +display). You don't normally need to use it on PC/Linux or PC/Windows +hosts. The available layouts are: @example @@ -308,8 +316,7 @@ USB options: Enable the USB driver (will be the default soon) @item -usbdevice devname -Add the USB device @var{devname}. See the monitor command -@code{usb_add} to have more information. +Add the USB device @var{devname}. @xref{usb_devices}. @end table Network options: @@ -492,8 +499,14 @@ Debug/Expert options: @table @option @item -serial dev -Redirect the virtual serial port to host device @var{dev}. Available -devices are: +Redirect the virtual serial port to host character device +@var{dev}. The default device is @code{vc} in graphical mode and +@code{stdio} in non graphical mode. + +This option can be used several times to simulate up to 4 serials +ports. + +Available character devices are: @table @code @item vc Virtual console @@ -512,13 +525,64 @@ Write output to filename. No character can be read. @item stdio [Unix only] standard input/output @item pipe:filename -[Unix only] name pipe @var{filename} -@end table -The default device is @code{vc} in graphical mode and @code{stdio} in -non graphical mode. +name pipe @var{filename} +@item COMn +[Windows only] Use host serial port @var{n} +@item udp:[remote_host]:remote_port[@@[src_ip]:src_port] +This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specifed @var{src_port} a random port is automatically chosen. -This option can be used several times to simulate up to 4 serials -ports. +If you just want a simple readonly console you can use @code{netcat} or +@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as: +@code{nc -u -l -p 4555}. Any time qemu writes something to that port it +will appear in the netconsole session. + +If you plan to send characters back via netconsole or you want to stop +and start qemu a lot of times, you should have qemu use the same +source port each time by using something like @code{-serial +udp::4555@@:4556} to qemu. Another approach is to use a patched +version of netcat which can listen to a TCP port and send and receive +characters via udp. If you have a patched version of netcat which +activates telnet remote echo and single char transfer, then you can +use the following options to step up a netcat redirector to allow +telnet on port 5555 to access the qemu port. +@table @code +@item Qemu Options: +-serial udp::4555@@:4556 +@item netcat options: +-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T +@item telnet options: +localhost 5555 +@end table + + +@item tcp:[host]:port[,server][,nowait] +The TCP Net Console has two modes of operation. It can send the serial +I/O to a location or wait for a connection from a location. By default +the TCP Net Console is sent to @var{host} at the @var{port}. If you use +the @var{,server} option QEMU will wait for a client socket application +to connect to the port before continuing, unless the @code{,nowait} +option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only +one TCP connection at a time is accepted. You can use @code{telnet} to +connect to the corresponding character device. +@table @code +@item Example to send tcp console to 192.168.0.2 port 4444 +-serial tcp:192.168.0.2:4444 +@item Example to listen and wait on port 4444 for connection +-serial tcp::4444,server +@item Example to not wait and listen on ip 192.168.0.100 port 4444 +-serial tcp:192.168.0.100:4444,server,nowait +@end table + +@item telnet:host:port[,server][,nowait] +The telnet protocol is used instead of raw tcp sockets. The options +work the same as if you had specified @code{-serial tcp}. The +difference is that the port acts like a telnet server or client using +telnet option negotiation. This will also allow you to send the +MAGIC_SYSRQ sequence if you use a telnet that supports sending the break +sequence. Typically in unix telnet you do it with Control-] and then +type "send break" followed by pressing the enter key. + +@end table @item -parallel dev Redirect the virtual parallel port to host device @var{dev} (same @@ -552,7 +616,15 @@ images. @item -std-vga Simulate a standard VGA card with Bochs VBE extensions (default is -Cirrus Logic GD5446 PCI VGA) +Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0 +VBE extensions (e.g. Windows XP) and if you want to use high +resolution modes (>= 1280x1024x16) then you should use this option. + +@item -no-acpi +Disable ACPI (Advanced Configuration and Power Interface) support. Use +it if your guest OS complains about ACPI problems (PC target machine +only). + @item -loadvm file Start right away with a saved state (@code{loadvm} in monitor) @end table @@ -669,6 +741,8 @@ show emulated PCI device show USB devices plugged on the virtual USB hub @item info usbhost show all USB host devices +@item info capture +show information about active capturing @end table @item q or quit @@ -683,6 +757,23 @@ Change a removable media. @item screendump filename Save screen into PPM image @var{filename}. +@item wavcapture filename [frequency [bits [channels]]] +Capture audio into @var{filename}. Using sample rate @var{frequency} +bits per sample @var{bits} and number of channels @var{channels}. + +Defaults: +@itemize @minus +@item Sample rate = 44100 Hz - CD quality +@item Bits = 16 +@item Number of channels = 2 - Stereo +@end itemize + +@item stopcapture index +Stop capture with a given @var{index}, index can be obtained with +@example +info capture +@end example + @item log item1[,...] Activate logging of the specified items to @file{/tmp/qemu.log}. @@ -782,10 +873,8 @@ Reset the system. @item usb_add devname -Plug the USB device devname to the QEMU virtual USB hub. @var{devname} -is either a virtual device name (for example @code{mouse}) or a host -USB device identifier. Host USB device identifiers have the following -syntax: @code{host:bus.addr} or @code{host:vendor_id:product_id}. +Add the USB device @var{devname}. For details of available devices see +@ref{usb_devices} @item usb_del devname @@ -1104,31 +1193,39 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @node pcsys_usb @section USB emulation -QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected -to it. You can virtually plug to the hub virtual USB devices or real -host USB devices (experimental, works only on Linux hosts). +QEMU emulates a PCI UHCI USB controller. You can virtually plug +virtual USB devices or real host USB devices (experimental, works only +on Linux hosts). Qemu will automatically create and connect virtual USB hubs +as neccessary to connect multiple USB devices. -@subsection Using virtual USB devices +@menu +* usb_devices:: +* host_usb_devices:: +@end menu +@node usb_devices +@subsection Connecting USB devices -A virtual USB mouse device is available for testing in QEMU. +USB devices can be connected with the @option{-usbdevice} commandline option +or the @code{usb_add} monitor command. Available devices are: -You can try it with the following monitor commands: - -@example -# add the mouse device -(qemu) usb_add mouse - -# show the virtual USB devices plugged on the QEMU Virtual USB hub -(qemu) info usb - Device 0.3, speed 12 Mb/s - -# after some time you can try to remove the mouse -(qemu) usb_del 0.3 -@end example - -The option @option{-usbdevice} is similar to the monitor command -@code{usb_add}. +@table @var +@item @code{mouse} +Virtual Mouse. This will override the PS/2 mouse emulation when activated. +@item @code{tablet} +Pointer device that uses abolsute coordinates (like a touchscreen). +This means qemu is able to report the mouse position without having +to grab the mouse. Also overrides the PS/2 mouse emulation when activated. +@item @code{disk:file} +Mass storage device based on @var{file} (@pxref{disk_images}) +@item @code{host:bus.addr} +Pass through the host device identified by @var{bus.addr} +(Linux only) +@item @code{host:vendor_id:product_id} +Pass through the host device identified by @var{vendor_id:product_id} +(Linux only) +@end table +@node host_usb_devices @subsection Using host USB devices on a Linux host WARNING: this is an experimental feature. QEMU will slow down when @@ -1215,7 +1312,7 @@ Use @code{info reg} to display all the CPU registers. Use @code{x/10i $eip} to display the code at the PC position. @item Use @code{set architecture i8086} to dump 16 bit code. Then use -@code{x/10i $cs*16+*eip} to dump the code at the PC position. +@code{x/10i $cs*16+$eip} to dump the code at the PC position. @end enumerate @node pcsys_os_specific @@ -1250,6 +1347,11 @@ card. All Windows versions starting from Windows 95 should recognize and use this graphic card. For optimal performances, use 16 bit color depth in the guest and the host OS. +If you are using Windows XP as guest OS and if you want to use high +resolution modes which the Cirrus Logic BIOS does not support (i.e. >= +1280x1024x16), then you should use the VESA VBE virtual graphic card +(option @option{-std-vga}). + @subsubsection CPU usage reduction Windows 9x does not correctly use the CPU HLT @@ -1388,7 +1490,7 @@ More information is available at @node Sparc32 System emulator invocation @section Sparc32 System emulator invocation -Use the executable @file{qemu-system-sparc} to simulate a JavaStation +Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5 (sun4m architecture). The emulation is somewhat complete. QEMU emulates the following sun4m peripherals: @@ -1413,13 +1515,14 @@ Floppy drive The number of peripherals is fixed in the architecture. -QEMU uses the Proll, a PROM replacement available at -@url{http://people.redhat.com/@/zaitcev/linux/}. The required -QEMU-specific patches are included with the sources. +Since version 0.8.2, QEMU uses OpenBIOS +@url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable +firmware implementation. The goal is to implement a 100% IEEE +1275-1994 (referred to as Open Firmware) compliant firmware. A sample Linux 2.6 series kernel and ram disk image are available on -the QEMU web site. Please note that currently neither Linux 2.4 -series, NetBSD, nor OpenBSD kernels work. +the QEMU web site. Please note that currently NetBSD, OpenBSD or +Solaris kernels don't work. @c man begin OPTIONS @@ -1486,6 +1589,37 @@ ARM926E or ARM1026E CPU Two PL011 UARTs @item SMC 91c111 Ethernet adapter +@item +PL110 LCD controller +@item +PL050 KMI with PS/2 keyboard and mouse. +@end itemize + +The ARM Versatile baseboard is emulated with the following devices: + +@itemize @minus +@item +ARM926E CPU +@item +PL190 Vectored Interrupt Controller +@item +Four PL011 UARTs +@item +SMC 91c111 Ethernet adapter +@item +PL110 LCD controller +@item +PL050 KMI with PS/2 keyboard and mouse. +@item +PCI host bridge. Note the emulated PCI bridge only provides access to +PCI memory space. It does not provide access to PCI IO space. +This means some devices (eg. ne2k_pci NIC) are not useable, and others +(eg. rtl8139 NIC) are only useable when the guest drivers use the memory +mapped control registers. +@item +PCI OHCI USB controller. +@item +LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices. @end itemize A Linux 2.6 test image is available on the QEMU web site. More @@ -1498,6 +1632,7 @@ information is available in the QEMU mailing-list archive. * Quick Start:: * Wine launch:: * Command line options:: +* Other binaries:: @end menu @node Quick Start @@ -1604,6 +1739,15 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @end table +@node Other binaries +@section Other binaries + +@command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF +binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB +configurations), and arm-uclinux bFLT format binaries. + +The binary format is detected automatically. + @node compilation @chapter Compilation from the sources diff --git a/tools/ioemu/qemu-img.c b/tools/ioemu/qemu-img.c index 3a18c93254..c5a8e1a61c 100644 --- a/tools/ioemu/qemu-img.c +++ b/tools/ioemu/qemu-img.c @@ -23,6 +23,10 @@ */ #include "vl.h" +#ifdef _WIN32 +#include +#endif + void *get_mmap_addr(unsigned long size) { return NULL; @@ -160,12 +164,12 @@ void help(void) static void get_human_readable_size(char *buf, int buf_size, int64_t size) { - char suffixes[NB_SUFFIXES] = "KMGT"; + static const char suffixes[NB_SUFFIXES] = "KMGT"; int64_t base; int i; if (size <= 999) { - snprintf(buf, buf_size, "%lld", (long long) size); + snprintf(buf, buf_size, "%" PRId64, size); } else { base = 1024; for(i = 0; i < NB_SUFFIXES; i++) { @@ -175,8 +179,8 @@ static void get_human_readable_size(char *buf, int buf_size, int64_t size) suffixes[i]); break; } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { - snprintf(buf, buf_size, "%lld%c", - (long long) ((size + (base >> 1)) / base), + snprintf(buf, buf_size, "%" PRId64 "%c", + ((size + (base >> 1)) / base), suffixes[i]); break; } @@ -369,7 +373,7 @@ static int img_create(int argc, char **argv) printf(", backing_file=%s", base_filename); } - printf(", size=%lld kB\n", (long long) (size / 1024)); + printf(", size=%" PRId64 " kB\n", (int64_t) (size / 1024)); ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); if (ret < 0) { if (ret == -ENOTSUP) { @@ -559,7 +563,8 @@ static int img_convert(int argc, char **argv) memset(buf + n * 512, 0, cluster_size - n * 512); if (is_not_zero(buf, cluster_size)) { if (qcow_compress_cluster(out_bs, sector_num, buf) != 0) - error("error while compressing sector %lld", sector_num); + error("error while compressing sector %" PRId64, + sector_num); } sector_num += n; } @@ -598,7 +603,19 @@ static int img_convert(int argc, char **argv) #ifdef _WIN32 static int64_t get_allocated_file_size(const char *filename) { + typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high); + get_compressed_t get_compressed; struct _stati64 st; + + /* WinNT support GetCompressedFileSize to determine allocate size */ + get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA"); + if (get_compressed) { + DWORD high, low; + low = get_compressed(filename, &high); + if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) + return (((int64_t) high) << 32) + low; + } + if (_stati64(filename, &st) < 0) return -1; return st.st_size; @@ -664,10 +681,10 @@ static int img_info(int argc, char **argv) allocated_size); printf("image: %s\n" "file format: %s\n" - "virtual size: %s (%lld bytes)\n" + "virtual size: %s (%" PRId64 " bytes)\n" "disk size: %s\n", filename, fmt_name, size_buf, - (long long) (total_sectors * 512), + (total_sectors * 512), dsize_buf); if (bdrv_is_encrypted(bs)) printf("encrypted: yes\n"); diff --git a/tools/ioemu/sdl.c b/tools/ioemu/sdl.c index 311370e480..f43569f1ad 100644 --- a/tools/ioemu/sdl.c +++ b/tools/ioemu/sdl.c @@ -81,6 +81,11 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->data = screen->pixels; ds->linesize = screen->pitch; ds->depth = screen->format->BitsPerPixel; + if (ds->depth == 32 && screen->format->Rshift == 0) { + ds->bgr = 1; + } else { + ds->bgr = 0; + } ds->width = w; ds->height = h; } @@ -281,17 +286,17 @@ static void sdl_update_caption(void) static void sdl_hide_cursor(void) { if (kbd_mouse_is_absolute()) { - SDL_ShowCursor(1); - SDL_SetCursor(sdl_cursor_hidden); + SDL_ShowCursor(1); + SDL_SetCursor(sdl_cursor_hidden); } else { - SDL_ShowCursor(0); + SDL_ShowCursor(0); } } static void sdl_show_cursor(void) { if (!kbd_mouse_is_absolute()) { - SDL_ShowCursor(1); + SDL_ShowCursor(1); } } @@ -442,10 +447,18 @@ static void sdl_refresh(DisplayState *ds) gui_key_modifier_pressed = 0; if (gui_keysym == 0) { /* exit/enter grab if pressing Ctrl-Alt */ - if (!gui_grab) - sdl_grab_start(); - else + if (!gui_grab) { + /* if the application is not active, + do not try to enter grab state. It + prevents + 'SDL_WM_GrabInput(SDL_GRAB_ON)' + from blocking all the application + (SDL bug). */ + if (SDL_GetAppState() & SDL_APPACTIVE) + sdl_grab_start(); + } else { sdl_grab_end(); + } /* SDL does not send back all the modifiers key, so we must correct it */ reset_keys(); diff --git a/tools/ioemu/tap-win32.c b/tools/ioemu/tap-win32.c index b6056955c0..af5e25e683 100644 --- a/tools/ioemu/tap-win32.c +++ b/tools/ioemu/tap-win32.c @@ -630,6 +630,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, typedef struct TAPState { VLANClientState *vc; tap_win32_overlapped_t *handle; + HANDLE tap_event; } TAPState; static TAPState *tap_win32_state = NULL; @@ -656,6 +657,7 @@ void tap_win32_poll(void) if (size > 0) { qemu_send_packet(s->vc, buf, size); tap_win32_free_buffer(s->handle, buf); + SetEvent(s->tap_event); } } @@ -676,5 +678,11 @@ int tap_win32_init(VLANState *vlan, const char *ifname) snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); tap_win32_state = s; + + s->tap_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!s->tap_event) { + fprintf(stderr, "tap-win32: Failed CreateEvent\n"); + } + qemu_add_wait_object(s->tap_event, NULL, NULL); return 0; } diff --git a/tools/ioemu/target-i386/exec.h b/tools/ioemu/target-i386/exec.h index 4ff527f841..609a5869a0 100644 --- a/tools/ioemu/target-i386/exec.h +++ b/tools/ioemu/target-i386/exec.h @@ -496,6 +496,9 @@ void save_native_fp_state(CPUState *env); float approx_rsqrt(float a); float approx_rcp(float a); void update_fp_status(void); +void helper_hlt(void); +void helper_monitor(void); +void helper_mwait(void); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; diff --git a/tools/ioemu/target-i386/helper.c b/tools/ioemu/target-i386/helper.c index 123f510497..70e9fae3b0 100644 --- a/tools/ioemu/target-i386/helper.c +++ b/tools/ioemu/target-i386/helper.c @@ -1674,6 +1674,7 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); next_eip = env->eip + next_eip_addend; switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); + CC_OP = CC_OP_EFLAGS; break; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -1834,6 +1835,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); + CC_OP = CC_OP_EFLAGS; return; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -2948,9 +2950,14 @@ void helper_fxam_ST0(void) if (SIGND(temp)) env->fpus |= 0x200; /* C1 <-- 1 */ + /* XXX: test fptags too */ expdif = EXPD(temp); if (expdif == MAXEXPD) { +#ifdef USE_X86LDOUBLE + if (MANTD(temp) == 0x8000000000000000ULL) +#else if (MANTD(temp) == 0) +#endif env->fpus |= 0x500 /*Infinity*/; else env->fpus |= 0x100 /*NaN*/; @@ -3252,7 +3259,7 @@ static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) v = (uint64_t)a1 * (uint64_t)b1; *phigh += v; #ifdef DEBUG_MULDIV - printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n", a, b, *phigh, *plow); #endif } @@ -3301,7 +3308,7 @@ static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) a0 = (a0 << 1) | qb; } #if defined(DEBUG_MULDIV) - printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n", + printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", *phigh, *plow, b, a0, a1); #endif *plow = a0; @@ -3401,6 +3408,34 @@ void helper_bswapq_T0(void) } #endif +void helper_hlt(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ + env->hflags |= HF_HALTED_MASK; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); +} + +void helper_monitor(void) +{ + if (ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: store address ? */ +} + +void helper_mwait(void) +{ + if (ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: not complete but not completely erroneous */ + if (env->cpu_index != 0 || env->next_cpu != NULL) { + /* more than one CPU: do not sleep because another CPU may + wake this one */ + } else { + helper_hlt(); + } +} + float approx_rsqrt(float a) { return 1.0 / sqrt(a); diff --git a/tools/ioemu/target-i386/helper2.c b/tools/ioemu/target-i386/helper2.c index 9d5d9b564e..19af159f92 100644 --- a/tools/ioemu/target-i386/helper2.c +++ b/tools/ioemu/target-i386/helper2.c @@ -35,7 +35,10 @@ #include #include -_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) +int modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + return syscall(__NR_modify_ldt, func, ptr, bytecount); +} #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) #define modify_ldt_ldt_s user_desc @@ -261,11 +264,11 @@ void cpu_dump_state(CPUState *env, FILE *f, #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { cpu_fprintf(f, - "RAX=%016llx RBX=%016llx RCX=%016llx RDX=%016llx\n" - "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n" - "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n" - "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n" - "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", + "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" + "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" + "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" + "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" + "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], @@ -326,28 +329,28 @@ void cpu_dump_state(CPUState *env, FILE *f, if (env->hflags & HF_LMA_MASK) { for(i = 0; i < 6; i++) { SegmentCache *sc = &env->segs[i]; - cpu_fprintf(f, "%s =%04x %016llx %08x %08x\n", + cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n", seg_name[i], sc->selector, sc->base, sc->limit, sc->flags); } - cpu_fprintf(f, "LDT=%04x %016llx %08x %08x\n", + cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n", env->ldt.selector, env->ldt.base, env->ldt.limit, env->ldt.flags); - cpu_fprintf(f, "TR =%04x %016llx %08x %08x\n", + cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n", env->tr.selector, env->tr.base, env->tr.limit, env->tr.flags); - cpu_fprintf(f, "GDT= %016llx %08x\n", + cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n", env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %016llx %08x\n", + cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%016llx CR3=%016llx CR4=%08x\n", + cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", (uint32_t)env->cr[0], env->cr[2], env->cr[3], @@ -391,7 +394,7 @@ void cpu_dump_state(CPUState *env, FILE *f, snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, "CCS=%016llx CCD=%016llx CCO=%-8s\n", + cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", env->cc_src, env->cc_dst, cc_op_name); } else @@ -424,10 +427,10 @@ void cpu_dump_state(CPUState *env, FILE *f, } l; } tmp; tmp.d = env->fpregs[i].d; - cpu_fprintf(f, "FPR%d=%016llx %04x", + cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", i, tmp.l.lower, tmp.l.upper); #else - cpu_fprintf(f, "FPR%d=%016llx", + cpu_fprintf(f, "FPR%d=%016" PRIx64, i, env->fpregs[i].mmx.q); #endif if ((i & 1) == 1) diff --git a/tools/ioemu/target-i386/op.c b/tools/ioemu/target-i386/op.c index a9a8665a1c..7a3aa77273 100644 --- a/tools/ioemu/target-i386/op.c +++ b/tools/ioemu/target-i386/op.c @@ -614,10 +614,17 @@ void OPPROTO op_movq_eip_im64(void) void OPPROTO op_hlt(void) { - env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ - env->hflags |= HF_HALTED_MASK; - env->exception_index = EXCP_HLT; - cpu_loop_exit(); + helper_hlt(); +} + +void OPPROTO op_monitor(void) +{ + helper_monitor(); +} + +void OPPROTO op_mwait(void) +{ + helper_mwait(); } void OPPROTO op_debug(void) diff --git a/tools/ioemu/target-i386/translate.c b/tools/ioemu/target-i386/translate.c index a1b91d3539..f905f323dd 100644 --- a/tools/ioemu/target-i386/translate.c +++ b/tools/ioemu/target-i386/translate.c @@ -100,6 +100,7 @@ typedef struct DisasContext { int popl_esp_hack; /* for correct popl with esp base handling */ int rip_offset; /* only used in x86_64, but left for simplicity */ int cpuid_features; + int cpuid_ext_features; } DisasContext; static void gen_eob(DisasContext *s); @@ -2905,6 +2906,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) break; case 0xc4: /* pinsrw */ case 0x1c4: + s->rip_offset = 1; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); val = ldub_code(s->pc++); if (b1) { @@ -2945,16 +2947,16 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) break; case 0x2d6: /* movq2dq */ gen_op_enter_mmx(); - rm = (modrm & 7) | REX_B(s); - gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), - offsetof(CPUX86State,fpregs[reg & 7].mmx)); - gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); + rm = (modrm & 7); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,fpregs[rm].mmx)); + gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); break; case 0x3d6: /* movdq2q */ gen_op_enter_mmx(); - rm = (modrm & 7); - gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx), - offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); break; case 0xd7: /* pmovmskb */ case 0x1d7: @@ -2975,7 +2977,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) } } else { /* generic MMX or SSE operation */ - if (b == 0xf7) { + switch(b) { + case 0xf7: /* maskmov : we must prepare A0 */ if (mod != 3) goto illegal_op; @@ -2990,13 +2993,21 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) gen_op_andl_A0_ffff(); } gen_add_A0_ds_seg(s); + break; + case 0x70: /* pshufx insn */ + case 0xc6: /* pshufx insn */ + case 0xc2: /* compare insns */ + s->rip_offset = 1; + break; + default: + break; } if (is_xmm) { op1_offset = offsetof(CPUX86State,xmm_regs[reg]); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,xmm_t0); - if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f) || + if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) || b == 0xc2)) { /* specific case for SSE single instructions */ if (b1 == 2) { @@ -5557,26 +5568,69 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; + rm = modrm & 7; switch(op) { case 0: /* sgdt */ - case 1: /* sidt */ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); - else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); gen_add_A0_im(s, 2); - if (op == 0) - gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base)); - else - gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base)); + gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); break; + case 1: + if (mod == 3) { + switch (rm) { + case 0: /* monitor */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg[R_EBX](); + gen_op_addq_A0_AL(); + } else +#endif + { + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + gen_op_monitor(); + break; + case 1: /* mwait */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(s->pc - s->cs_base); + gen_op_mwait(); + gen_eob(s); + break; + default: + goto illegal_op; + } + } else { /* sidt */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit)); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_add_A0_im(s, 2); + gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + } + break; case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) @@ -5619,7 +5673,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } else { if (mod == 3) { #ifdef TARGET_X86_64 - if (CODE64(s) && (modrm & 7) == 0) { + if (CODE64(s) && rm == 0) { /* swapgs */ gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base)); gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); @@ -6338,6 +6392,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->mem_index = 1 * 4; } dc->cpuid_features = env->cpuid_features; + dc->cpuid_ext_features = env->cpuid_ext_features; #ifdef TARGET_X86_64 dc->lma = (flags >> HF_LMA_SHIFT) & 1; dc->code64 = (flags >> HF_CS64_SHIFT) & 1; diff --git a/tools/ioemu/tests/Makefile b/tools/ioemu/tests/Makefile index 59a0b6d994..d7abae69e3 100644 --- a/tools/ioemu/tests/Makefile +++ b/tools/ioemu/tests/Makefile @@ -1,6 +1,7 @@ -include ../config-host.mak -CFLAGS=-Wall -O2 -g #-msse2 +CFLAGS=-Wall -O2 -g +#CFLAGS+=-msse2 LDFLAGS= ifeq ($(ARCH),i386) diff --git a/tools/ioemu/tests/test-i386.c b/tools/ioemu/tests/test-i386.c index 310a93aebe..4a25d03b66 100644 --- a/tools/ioemu/tests/test-i386.c +++ b/tools/ioemu/tests/test-i386.c @@ -50,7 +50,7 @@ #define FMTLX "%016lx" #define X86_64_ONLY(x) x #else -#define FMT64X "%016llx" +#define FMT64X "%016" PRIx64 #define FMTLX "%08lx" #define X86_64_ONLY(x) #endif @@ -789,6 +789,12 @@ void test_fcmp(double a, double b) a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); } fpu_clear_exceptions(); + asm volatile("fxam\n" + "fstsw %%ax\n" + : "=a" (fpus) + : "t" (a)); + printf("fxam(%f)=%04lx\n", a, fpus & 0x4700); + fpu_clear_exceptions(); } void test_fcvt(double a) @@ -958,12 +964,17 @@ void test_floats(void) test_fcmp(2, 3); test_fcmp(2, q_nan.d); test_fcmp(q_nan.d, -1); + test_fcmp(-1.0/0.0, -1); + test_fcmp(1.0/0.0, -1); test_fcvt(0.5); test_fcvt(-0.5); test_fcvt(1.0/7.0); test_fcvt(-1.0/9.0); test_fcvt(32768); test_fcvt(-1e20); + test_fcvt(-1.0/0.0); + test_fcvt(1.0/0.0); + test_fcvt(q_nan.d); test_fconst(); test_fbcd(1234567890123456); test_fbcd(-123451234567890); @@ -2188,9 +2199,12 @@ void test_sse_comi(double a1, double b1) r.q[1], r.q[0]);\ } +/* Force %xmm0 usage to avoid the case where both register index are 0 + to test intruction decoding more extensively */ #define CVT_OP_XMM2MMX(op)\ {\ - asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq));\ + asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \ + : "%xmm0");\ printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ @@ -2544,6 +2558,10 @@ void test_sse(void) CVT_OP_XMM(cvtpd2dq); CVT_OP_XMM(cvttpd2dq); + /* sse/mmx moves */ + CVT_OP_XMM2MMX(movdq2q); + CVT_OP_MMX2XMM(movq2dq); + /* int to float */ a.l[0] = -6; a.l[1] = 2; diff --git a/tools/ioemu/usb-linux.c b/tools/ioemu/usb-linux.c index b08eaebabb..0a13753d48 100644 --- a/tools/ioemu/usb-linux.c +++ b/tools/ioemu/usb-linux.c @@ -26,7 +26,7 @@ #if defined(__linux__) #include #include -#define __user /* new versions of usbdevice_fs.h use this private attribute */ +#include #include #include @@ -45,11 +45,13 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, int vendor_id, int product_id, const char *product_name, int speed); static int usb_host_find_device(int *pbus_num, int *paddr, + char *product_name, int product_name_size, const char *devname); //#define DEBUG #define USBDEVFS_PATH "/proc/bus/usb" +#define PRODUCT_NAME_SZ 32 typedef struct USBHostDevice { USBDevice dev; @@ -66,6 +68,15 @@ static void usb_host_handle_reset(USBDevice *dev) #endif } +static void usb_host_handle_destroy(USBDevice *dev) +{ + USBHostDevice *s = (USBHostDevice *)dev; + + if (s->fd >= 0) + close(s->fd); + qemu_free(s); +} + static int usb_host_handle_control(USBDevice *dev, int request, int value, @@ -146,8 +157,11 @@ USBDevice *usb_host_device_open(const char *devname) char buf[1024]; int descr_len, dev_descr_len, config_descr_len, nb_interfaces; int bus_num, addr; + char product_name[PRODUCT_NAME_SZ]; - if (usb_host_find_device(&bus_num, &addr, devname) < 0) + if (usb_host_find_device(&bus_num, &addr, + product_name, sizeof(product_name), + devname) < 0) return NULL; snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", @@ -231,6 +245,15 @@ USBDevice *usb_host_device_open(const char *devname) dev->dev.handle_reset = usb_host_handle_reset; dev->dev.handle_control = usb_host_handle_control; dev->dev.handle_data = usb_host_handle_data; + dev->dev.handle_destroy = usb_host_handle_destroy; + + if (product_name[0] == '\0') + snprintf(dev->dev.devname, sizeof(dev->dev.devname), + "host:%s", devname); + else + pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), + product_name); + return (USBDevice *)dev; } @@ -338,6 +361,7 @@ typedef struct FindDeviceState { int product_id; int bus_num; int addr; + char product_name[PRODUCT_NAME_SZ]; } FindDeviceState; static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, @@ -346,8 +370,11 @@ static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, const char *product_name, int speed) { FindDeviceState *s = opaque; - if (vendor_id == s->vendor_id && - product_id == s->product_id) { + if ((vendor_id == s->vendor_id && + product_id == s->product_id) || + (bus_num == s->bus_num && + addr == s->addr)) { + pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name); s->bus_num = bus_num; s->addr = addr; return 1; @@ -360,6 +387,7 @@ static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 'bus.addr' (decimal numbers) or 'vendor_id:product_id' (hexa numbers) */ static int usb_host_find_device(int *pbus_num, int *paddr, + char *product_name, int product_name_size, const char *devname) { const char *p; @@ -370,6 +398,11 @@ static int usb_host_find_device(int *pbus_num, int *paddr, if (p) { *pbus_num = strtoul(devname, NULL, 0); *paddr = strtoul(p + 1, NULL, 0); + fs.bus_num = *pbus_num; + fs.addr = *paddr; + ret = usb_host_scan(&fs, usb_host_find_device_scan); + if (ret) + pstrcpy(product_name, product_name_size, fs.product_name); return 0; } p = strchr(devname, ':'); @@ -380,6 +413,7 @@ static int usb_host_find_device(int *pbus_num, int *paddr, if (ret) { *pbus_num = fs.bus_num; *paddr = fs.addr; + pstrcpy(product_name, product_name_size, fs.product_name); return 0; } } diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 7084b78c57..c5bd964edb 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -94,11 +94,7 @@ //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT -#if !defined(CONFIG_SOFTMMU) -#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) -#else #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) -#endif #ifdef TARGET_PPC #define DEFAULT_RAM_SIZE 144 @@ -108,6 +104,9 @@ /* 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 @@ -148,8 +147,6 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; int win2k_install_hack = 0; #endif int usb_enabled = 0; -USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; -USBDevice *vm_usb_hub; static VLANState *first_vlan; int smp_cpus = 1; int vnc_display = -1; @@ -160,6 +157,8 @@ int vnc_display = -1; #else #define MAX_CPUS 1 #endif +int acpi_enabled = 0; +int fd_bootchk = 1; extern int vcpus; @@ -167,8 +166,6 @@ int xc_handle; time_t timeoffset = 0; -int acpi_enabled = 0; - char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; extern int domid; @@ -501,162 +498,6 @@ int kbd_mouse_is_absolute(void) return qemu_put_mouse_event_absolute; } -/***********************************************************/ -/* timers */ - -#if defined(__powerpc__) - -static inline uint32_t get_tbl(void) -{ - uint32_t tbl; - asm volatile("mftb %0" : "=r" (tbl)); - return tbl; -} - -static inline uint32_t get_tbu(void) -{ - uint32_t tbl; - asm volatile("mftbu %0" : "=r" (tbl)); - return tbl; -} - -int64_t cpu_get_real_ticks(void) -{ - uint32_t l, h, h1; - /* NOTE: we test if wrapping has occurred */ - do { - h = get_tbu(); - l = get_tbl(); - h1 = get_tbu(); - } while (h != h1); - return ((int64_t)h << 32) | l; -} - -#elif defined(__i386__) - -int64_t cpu_get_real_ticks(void) -{ -#ifdef _WIN32 - LARGE_INTEGER ti; - QueryPerformanceCounter(&ti); - return ti.QuadPart; -#else - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; -#endif -} - -#elif defined(__x86_64__) - -int64_t cpu_get_real_ticks(void) -{ - uint32_t low,high; - int64_t val; - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - val = high; - val <<= 32; - val |= low; - return val; -} - -#elif defined(__ia64) - -int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); - return val; -} - -#elif defined(__s390__) - -int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); - return val; -} - -#else -#error unsupported CPU -#endif - -static int64_t cpu_ticks_prev; -static int64_t cpu_ticks_offset; -static int cpu_ticks_enabled; - -static inline 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; - } -} - -/* enable cpu_get_ticks() */ -void cpu_enable_ticks(void) -{ - if (!cpu_ticks_enabled) { - cpu_ticks_offset -= cpu_get_real_ticks(); - 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_ticks_enabled = 0; - } -} - -#ifdef _WIN32 -void cpu_calibrate_ticks(void) -{ - LARGE_INTEGER freq; - int ret; - - ret = QueryPerformanceFrequency(&freq); - if (ret == 0) { - fprintf(stderr, "Could not calibrate ticks\n"); - exit(1); - } - ticks_per_sec = freq.QuadPart; -} - -#else -static int64_t get_clock(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000LL + tv.tv_usec; -} - -void cpu_calibrate_ticks(void) -{ - int64_t usec, ticks; - - usec = get_clock(); - ticks = cpu_get_real_ticks(); - usleep(50 * 1000); - usec = get_clock() - usec; - ticks = cpu_get_real_ticks() - ticks; - ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; -} -#endif /* !_WIN32 */ - /* compute with 96 bit intermediate result: (a*b)/c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) { @@ -681,6 +522,133 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t 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 @@ -819,28 +787,21 @@ int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_TIMER_REALTIME: -#ifdef _WIN32 - return GetTickCount(); -#else - { - struct tms tp; - - /* Note that using gettimeofday() is not a good solution - for timers because its value change when the date is - modified. */ - if (timer_freq == 100) { - return times(&tp) * 10; - } else { - return ((int64_t)times(&tp) * 1000) / timer_freq; - } - } -#endif + return get_clock() / 1000000; default: case QEMU_TIMER_VIRTUAL: - return cpu_get_ticks(); + 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) { @@ -919,7 +880,7 @@ static void host_alarm_handler(int host_signum) delta_max = delta; delta_cum += delta; if (++count == DISP_FREQ) { - printf("timer: min=%lld us max=%lld us avg=%lld us avg_freq=%0.3f Hz\n", + 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), @@ -994,11 +955,8 @@ static int start_rtc_timer(void) #endif /* !CONFIG_DM */ -static void init_timers(void) +static void init_timer_alarm(void) { - rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); - vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); - #ifdef _WIN32 { int count=0; @@ -1023,7 +981,7 @@ static void init_timers(void) perror("failed CreateEvent"); exit(1); } - ResetEvent(host_alarm); + qemu_add_wait_object(host_alarm, NULL, NULL); } pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; #else @@ -1382,7 +1340,9 @@ CharDriverState *qemu_chr_open_pipe(const char *filename) static int term_got_escape, client_index; static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; -int term_fifo_size; +static int term_fifo_size; +static int term_timestamps; +static int64_t term_timestamps_start; void term_print_help(void) { @@ -1391,6 +1351,7 @@ void term_print_help(void) "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" ); @@ -1437,6 +1398,10 @@ static void stdio_received_byte(int ch) goto send_char; } break; + case 't': + term_timestamps = !term_timestamps; + term_timestamps_start = -1; + break; case TERM_ESCAPE: goto send_char; } @@ -1494,6 +1459,39 @@ static void stdio_read(void *opaque) 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; @@ -1539,6 +1537,7 @@ CharDriverState *qemu_chr_open_stdio(void) 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; @@ -2193,6 +2192,426 @@ CharDriverState *qemu_chr_open_win_file_out(const char *file_out) } #endif +/***********************************************************/ +/* UDP Net console */ + +typedef struct { + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *fd_opaque; + int fd; + struct sockaddr_in daddr; + char buf[1024]; + int bufcnt; + int bufptr; + int max_size; +} NetCharDriver; + +static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + NetCharDriver *s = chr->opaque; + + return sendto(s->fd, buf, len, 0, + (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in)); +} + +static int udp_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + NetCharDriver *s = chr->opaque; + + s->max_size = s->fd_can_read(s->fd_opaque); + + /* If there were any stray characters in the queue process them + * first + */ + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + s->bufptr++; + s->max_size = s->fd_can_read(s->fd_opaque); + } + return s->max_size; +} + +static void udp_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + NetCharDriver *s = chr->opaque; + + if (s->max_size == 0) + return; + s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0); + s->bufptr = s->bufcnt; + if (s->bufcnt <= 0) + return; + + s->bufptr = 0; + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + s->bufptr++; + s->max_size = s->fd_can_read(s->fd_opaque); + } +} + +static void udp_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + NetCharDriver *s = chr->opaque; + + if (s->fd >= 0) { + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; + qemu_set_fd_handler2(s->fd, udp_chr_read_poll, + udp_chr_read, NULL, chr); + } +} + +int parse_host_port(struct sockaddr_in *saddr, const char *str); +int parse_host_src_port(struct sockaddr_in *haddr, + struct sockaddr_in *saddr, + const char *str); + +CharDriverState *qemu_chr_open_udp(const char *def) +{ + CharDriverState *chr = NULL; + NetCharDriver *s = NULL; + int fd = -1; + struct sockaddr_in saddr; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto return_err; + s = qemu_mallocz(sizeof(NetCharDriver)); + if (!s) + goto return_err; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket(PF_INET, SOCK_DGRAM)"); + goto return_err; + } + + if (parse_host_src_port(&s->daddr, &saddr, def) < 0) { + printf("Could not parse: %s\n", def); + goto return_err; + } + + if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) + { + perror("bind"); + goto return_err; + } + + s->fd = fd; + s->bufcnt = 0; + s->bufptr = 0; + chr->opaque = s; + chr->chr_write = udp_chr_write; + chr->chr_add_read_handler = udp_chr_add_read_handler; + return chr; + +return_err: + if (chr) + free(chr); + if (s) + free(s); + if (fd >= 0) + closesocket(fd); + return NULL; +} + +/***********************************************************/ +/* TCP Net console */ + +typedef struct { + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *fd_opaque; + int fd, listen_fd; + int connected; + int max_size; + int do_telnetopt; +} TCPCharDriver; + +static void tcp_chr_accept(void *opaque); + +static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + TCPCharDriver *s = chr->opaque; + if (s->connected) { + return send_all(s->fd, buf, len); + } else { + /* XXX: indicate an error ? */ + return len; + } +} + +static int tcp_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + if (!s->connected) + return 0; + s->max_size = s->fd_can_read(s->fd_opaque); + return s->max_size; +} + +#define IAC 255 +#define IAC_BREAK 243 +static void tcp_chr_process_IAC_bytes(CharDriverState *chr, + TCPCharDriver *s, + char *buf, int *size) +{ + /* Handle any telnet client's basic IAC options to satisfy char by + * char mode with no echo. All IAC options will be removed from + * the buf and the do_telnetopt variable will be used to track the + * state of the width of the IAC information. + * + * IAC commands come in sets of 3 bytes with the exception of the + * "IAC BREAK" command and the double IAC. + */ + + int i; + int j = 0; + + for (i = 0; i < *size; i++) { + if (s->do_telnetopt > 1) { + if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) { + /* Double IAC means send an IAC */ + if (j != i) + buf[j] = buf[i]; + j++; + s->do_telnetopt = 1; + } else { + if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { + /* Handle IAC break commands by sending a serial break */ + chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); + s->do_telnetopt++; + } + s->do_telnetopt++; + } + if (s->do_telnetopt >= 4) { + s->do_telnetopt = 1; + } + } else { + if ((unsigned char)buf[i] == IAC) { + s->do_telnetopt = 2; + } else { + if (j != i) + buf[j] = buf[i]; + j++; + } + } + } + *size = j; +} + +static void tcp_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + uint8_t buf[1024]; + int len, size; + + if (!s->connected || s->max_size <= 0) + return; + len = sizeof(buf); + if (len > s->max_size) + len = s->max_size; + size = recv(s->fd, buf, len, 0); + if (size == 0) { + /* connection closed */ + s->connected = 0; + if (s->listen_fd >= 0) { + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + } + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + closesocket(s->fd); + s->fd = -1; + } else if (size > 0) { + if (s->do_telnetopt) + tcp_chr_process_IAC_bytes(chr, s, buf, &size); + if (size > 0) + s->fd_read(s->fd_opaque, buf, size); + } +} + +static void tcp_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + TCPCharDriver *s = chr->opaque; + + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; +} + +static void tcp_chr_connect(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + + s->connected = 1; + qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, + tcp_chr_read, NULL, chr); +} + +#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; +static void tcp_chr_telnet_init(int fd) +{ + char buf[3]; + /* Send the telnet negotion to put telnet in binary, no echo, single char mode */ + IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ + send(fd, (char *)buf, 3, 0); +} + +static void tcp_chr_accept(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + struct sockaddr_in saddr; + socklen_t len; + int fd; + + for(;;) { + len = sizeof(saddr); + fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + if (s->do_telnetopt) + tcp_chr_telnet_init(fd); + break; + } + } + socket_set_nonblock(fd); + s->fd = fd; + qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + tcp_chr_connect(chr); +} + +static void tcp_chr_close(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + if (s->fd >= 0) + closesocket(s->fd); + if (s->listen_fd >= 0) + closesocket(s->listen_fd); + qemu_free(s); +} + +static CharDriverState *qemu_chr_open_tcp(const char *host_str, + int is_telnet) +{ + CharDriverState *chr = NULL; + TCPCharDriver *s = NULL; + int fd = -1, ret, err, val; + int is_listen = 0; + int is_waitconnect = 1; + const char *ptr; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + goto fail; + + ptr = host_str; + while((ptr = strchr(ptr,','))) { + ptr++; + if (!strncmp(ptr,"server",6)) { + is_listen = 1; + } else if (!strncmp(ptr,"nowait",6)) { + is_waitconnect = 0; + } else { + printf("Unknown option: %s\n", ptr); + goto fail; + } + } + if (!is_listen) + is_waitconnect = 0; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto fail; + s = qemu_mallocz(sizeof(TCPCharDriver)); + if (!s) + goto fail; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + goto fail; + + if (!is_waitconnect) + socket_set_nonblock(fd); + + s->connected = 0; + s->fd = -1; + s->listen_fd = -1; + if (is_listen) { + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) + goto fail; + ret = listen(fd, 0); + if (ret < 0) + goto fail; + s->listen_fd = fd; + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + if (is_telnet) + s->do_telnetopt = 1; + } else { + for(;;) { + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + err = socket_error(); + if (err == EINTR || err == EWOULDBLOCK) { + } else if (err == EINPROGRESS) { + break; + } else { + goto fail; + } + } else { + s->connected = 1; + break; + } + } + s->fd = fd; + if (s->connected) + tcp_chr_connect(chr); + else + qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); + } + + chr->opaque = s; + chr->chr_write = tcp_chr_write; + chr->chr_add_read_handler = tcp_chr_add_read_handler; + chr->chr_close = tcp_chr_close; + if (is_listen && is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", host_str); + tcp_chr_accept(chr); + socket_set_nonblock(s->listen_fd); + } + + return chr; + fail: + if (fd >= 0) + closesocket(fd); + qemu_free(s); + qemu_free(chr); + return NULL; +} + CharDriverState *qemu_chr_open(const char *filename) { const char *p; @@ -2202,6 +2621,15 @@ CharDriverState *qemu_chr_open(const char *filename) } else if (!strcmp(filename, "null")) { return qemu_chr_open_null(); } else + if (strstart(filename, "tcp:", &p)) { + return qemu_chr_open_tcp(p, 0); + } else + if (strstart(filename, "telnet:", &p)) { + return qemu_chr_open_tcp(p, 1); + } else + if (strstart(filename, "udp:", &p)) { + return qemu_chr_open_udp(p); + } else #ifndef _WIN32 if (strstart(filename, "file:", &p)) { return qemu_chr_open_file_out(p); @@ -2309,6 +2737,45 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) return 0; } +int parse_host_src_port(struct sockaddr_in *haddr, + struct sockaddr_in *saddr, + const char *input_str) +{ + char *str = strdup(input_str); + char *host_str = str; + char *src_str; + char *ptr; + + /* + * Chop off any extra arguments at the end of the string which + * would start with a comma, then fill in the src port information + * if it was provided else use the "any address" and "any port". + */ + if ((ptr = strchr(str,','))) + *ptr = '\0'; + + if ((src_str = strchr(input_str,'@'))) { + *src_str = '\0'; + src_str++; + } + + if (parse_host_port(haddr, host_str) < 0) + goto fail; + + if (!src_str || *src_str == '\0') + src_str = ":0"; + + if (parse_host_port(saddr, src_str) < 0) + goto fail; + + free(str); + return(0); + +fail: + free(str); + return -1; +} + int parse_host_port(struct sockaddr_in *saddr, const char *str) { char buf[512]; @@ -2908,7 +3375,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) socket_set_nonblock(fd); return fd; fail: - if (fd>=0) close(fd); + if (fd >= 0) + closesocket(fd); return -1; } @@ -3036,7 +3504,7 @@ static void net_socket_accept(void *opaque) } s1 = net_socket_fd_init(s->vlan, fd, 1); if (!s1) { - close(fd); + closesocket(fd); } else { snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), "socket: connection from %s:%d", @@ -3342,47 +3810,74 @@ void do_info_network(void) /***********************************************************/ /* USB devices */ +static USBPort *used_usb_ports; +static USBPort *free_usb_ports; + +/* ??? Maybe change this to register a hub to keep track of the topology. */ +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach) +{ + port->opaque = opaque; + port->index = index; + port->attach = attach; + port->next = free_usb_ports; + free_usb_ports = port; +} + static int usb_device_add(const char *devname) { const char *p; USBDevice *dev; - int i; + USBPort *port; - if (!vm_usb_hub) - return -1; - for(i = 0;i < MAX_VM_USB_PORTS; i++) { - if (!vm_usb_ports[i]->dev) - break; - } - if (i == MAX_VM_USB_PORTS) + if (!free_usb_ports) return -1; if (strstart(devname, "host:", &p)) { dev = usb_host_device_open(p); - if (!dev) - return -1; } else if (!strcmp(devname, "mouse")) { dev = usb_mouse_init(); - if (!dev) - return -1; } else if (!strcmp(devname, "tablet")) { dev = usb_tablet_init(); - if (!dev) - return -1; + } else if (strstart(devname, "disk:", &p)) { + dev = usb_msd_init(p); } else { return -1; } - usb_attach(vm_usb_ports[i], dev); + if (!dev) + return -1; + + /* Find a USB port to add the device to. */ + port = free_usb_ports; + if (!port->next) { + USBDevice *hub; + + /* Create a new hub and chain it on. */ + free_usb_ports = NULL; + port->next = used_usb_ports; + used_usb_ports = port; + + hub = usb_hub_init(VM_USB_HUB_SIZE); + usb_attach(port, hub); + port = free_usb_ports; + } + + free_usb_ports = port->next; + port->next = used_usb_ports; + used_usb_ports = port; + usb_attach(port, dev); return 0; } static int usb_device_del(const char *devname) { + USBPort *port; + USBPort **lastp; USBDevice *dev; - int bus_num, addr, i; + int bus_num, addr; const char *p; - if (!vm_usb_hub) + if (!used_usb_ports) return -1; p = strchr(devname, '.'); @@ -3392,14 +3887,23 @@ static int usb_device_del(const char *devname) addr = strtoul(p + 1, NULL, 0); if (bus_num != 0) return -1; - for(i = 0;i < MAX_VM_USB_PORTS; i++) { - dev = vm_usb_ports[i]->dev; - if (dev && dev->addr == addr) - break; + + lastp = &used_usb_ports; + port = used_usb_ports; + while (port && port->dev->addr != addr) { + lastp = &port->next; + port = port->next; } - if (i == MAX_VM_USB_PORTS) + + if (!port) return -1; - usb_attach(vm_usb_ports[i], NULL); + + dev = port->dev; + *lastp = port->next; + usb_attach(port, NULL); + dev->handle_destroy(dev); + port->next = free_usb_ports; + free_usb_ports = port; return 0; } @@ -3422,35 +3926,34 @@ void do_usb_del(const char *devname) void usb_info(void) { USBDevice *dev; - int i; + USBPort *port; const char *speed_str; - if (!vm_usb_hub) { + if (!usb_enabled) { term_printf("USB support not enabled\n"); return; } - for(i = 0; i < MAX_VM_USB_PORTS; i++) { - dev = vm_usb_ports[i]->dev; - if (dev) { - term_printf("Hub port %d:\n", i); - switch(dev->speed) { - case USB_SPEED_LOW: - speed_str = "1.5"; - break; - case USB_SPEED_FULL: - speed_str = "12"; - break; - case USB_SPEED_HIGH: - speed_str = "480"; - break; - default: - speed_str = "?"; - break; - } - term_printf(" Device %d.%d, speed %s Mb/s\n", - 0, dev->addr, speed_str); + for (port = used_usb_ports; port; port = port->next) { + dev = port->dev; + if (!dev) + continue; + switch(dev->speed) { + case USB_SPEED_LOW: + speed_str = "1.5"; + break; + case USB_SPEED_FULL: + speed_str = "12"; + break; + case USB_SPEED_HIGH: + speed_str = "480"; + break; + default: + speed_str = "?"; + break; } + term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n", + 0, dev->addr, speed_str, dev->devname); } } @@ -3520,20 +4023,6 @@ void dumb_display_init(DisplayState *ds) ds->dpy_refresh = dumb_refresh; } -#if !defined(CONFIG_SOFTMMU) -/***********************************************************/ -/* cpu signal handler */ -static void host_segv_handler(int host_signum, siginfo_t *info, - void *puc) -{ - if (cpu_signal_handler(host_signum, info, puc)) - return; - if (stdio_nb_clients > 0) - term_exit(); - abort(); -} -#endif - /***********************************************************/ /* I/O handling */ @@ -3640,6 +4129,51 @@ void qemu_del_polling_cb(PollingFunc *func, void *opaque) } } +#ifdef _WIN32 +/***********************************************************/ +/* Wait objects support */ +typedef struct WaitObjects { + int num; + HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; + WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; + void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; +} WaitObjects; + +static WaitObjects wait_objects = {0}; + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + WaitObjects *w = &wait_objects; + + if (w->num >= MAXIMUM_WAIT_OBJECTS) + return -1; + w->events[w->num] = handle; + w->func[w->num] = func; + w->opaque[w->num] = opaque; + w->num++; + return 0; +} + +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + int i, found; + WaitObjects *w = &wait_objects; + + found = 0; + for (i = 0; i < w->num; i++) { + if (w->events[i] == handle) + found = 1; + if (found) { + w->events[i] = w->events[i + 1]; + w->func[i] = w->func[i + 1]; + w->opaque[i] = w->opaque[i + 1]; + } + } + if (found) + w->num--; +} +#endif + /***********************************************************/ /* savevm/loadvm support */ @@ -4184,11 +4718,11 @@ void cpu_save(QEMUFile *f, void *opaque) /* FPU */ for(i = 0; i < TARGET_FPREGS; i++) { union { - TARGET_FPREG_T f; - target_ulong i; + float32 f; + uint32_t i; } u; u.f = env->fpr[i]; - qemu_put_betl(f, u.i); + qemu_put_be32(f, u.i); } qemu_put_betls(f, &env->pc); @@ -4220,10 +4754,10 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /* FPU */ for(i = 0; i < TARGET_FPREGS; i++) { union { - TARGET_FPREG_T f; - target_ulong i; + float32 f; + uint32_t i; } u; - u.i = qemu_get_betl(f); + u.i = qemu_get_be32(f); env->fpr[i] = u.f; } @@ -4536,21 +5070,18 @@ void main_loop_wait(int timeout) } #ifdef _WIN32 if (ret == 0 && timeout > 0) { - int err; - HANDLE hEvents[1]; - - hEvents[0] = host_alarm; - ret = WaitForMultipleObjects(1, hEvents, FALSE, timeout); - switch(ret) { - case WAIT_OBJECT_0 + 0: - break; - case WAIT_TIMEOUT: - break; - default: - err = GetLastError(); - fprintf(stderr, "Wait error %d %d\n", ret, err); - break; - } + int err; + WaitObjects *w = &wait_objects; + + ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout); + if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { + if (w->func[ret - WAIT_OBJECT_0]) + w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); + } else if (ret == WAIT_TIMEOUT) { + } else { + err = GetLastError(); + fprintf(stderr, "Wait error %d %d\n", ret, err); + } } #endif /* poll any events */ @@ -4718,6 +5249,9 @@ void help(void) #endif /* !CONFIG_DM */ "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" +#ifdef TARGET_I386 + "-no-fd-bootchk disable boot signature checking for floppy disks\n" +#endif "-m megs set virtual RAM size to megs MB [default=%d]\n" "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" @@ -4796,6 +5330,7 @@ void help(void) " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" #ifdef USE_KQEMU + "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n" "-no-kqemu disable KQEMU kernel module usage\n" #endif #ifdef USE_CODE_COPY @@ -4804,6 +5339,7 @@ void help(void) #ifdef TARGET_I386 "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" + "-no-acpi disable ACPI\n" #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" @@ -4818,23 +5354,13 @@ void help(void) "\n" "When using -nographic, press 'ctrl-a h' to get some help.\n" , -#ifdef CONFIG_SOFTMMU "qemu", -#else - "qemu-fast", -#endif DEFAULT_RAM_SIZE, #ifndef _WIN32 DEFAULT_NETWORK_SCRIPT, #endif DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); -#ifndef CONFIG_SOFTMMU - printf("\n" - "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n" - "work. Please use the 'qemu' executable to have a more accurate (but slower)\n" - "PC emulation.\n"); -#endif exit(1); } @@ -4855,6 +5381,9 @@ enum { #endif /* !CONFIG_DM */ QEMU_OPTION_boot, QEMU_OPTION_snapshot, +#ifdef TARGET_I386 + QEMU_OPTION_no_fd_bootchk, +#endif QEMU_OPTION_m, QEMU_OPTION_nographic, #ifdef HAS_AUDIO @@ -4899,12 +5428,13 @@ enum { QEMU_OPTION_usbdevice, QEMU_OPTION_smp, QEMU_OPTION_vnc, - QEMU_OPTION_vncviewer, + QEMU_OPTION_no_acpi, QEMU_OPTION_d, QEMU_OPTION_vcpus, QEMU_OPTION_timeoffset, QEMU_OPTION_acpi, + QEMU_OPTION_vncviewer, }; typedef struct QEMUOption { @@ -4928,6 +5458,9 @@ const QEMUOption qemu_options[] = { #endif /* !CONFIG_DM */ { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, +#ifdef TARGET_I386 + { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk }, +#endif { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, { "k", HAS_ARG, QEMU_OPTION_k }, @@ -4983,6 +5516,7 @@ const QEMUOption qemu_options[] = { /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "d", HAS_ARG, QEMU_OPTION_d }, { "vcpus", 1, QEMU_OPTION_vcpus }, @@ -5182,6 +5716,14 @@ static void select_soundhw (const char *optarg) } #endif +#ifdef _WIN32 +static BOOL WINAPI qemu_ctrl_handler(DWORD type) +{ + exit(STATUS_CONTROL_C_EXIT); + return TRUE; +} +#endif + #define MAX_NET_CLIENTS 32 #include @@ -5287,7 +5829,7 @@ int main(int argc, char **argv) int parallel_device_index; const char *loadvm = NULL; QEMUMachine *machine; - char usb_devices[MAX_VM_USB_PORTS][128]; + char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; unsigned long nr_pages; xen_pfn_t *page_array; @@ -5296,10 +5838,36 @@ int main(int argc, char **argv) char qemu_dm_logfilename[64]; LIST_INIT (&vm_change_state_head); -#if !defined(CONFIG_SOFTMMU) - /* we never want that malloc() uses mmap() */ - mallopt(M_MMAP_THRESHOLD, 4096 * 1024); +#ifndef _WIN32 + { + struct sigaction act; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + } +#else + SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE); + /* Note: cpu_interrupt() is currently not SMP safe, so we force + QEMU to run on a single CPU */ + { + HANDLE h; + DWORD mask, smask; + int i; + h = GetCurrentProcess(); + if (GetProcessAffinityMask(h, &mask, &smask)) { + for(i = 0; i < 32; i++) { + if (mask & (1 << i)) + break; + } + if (i != 32) { + mask = 1 << i; + SetProcessAffinityMask(h, mask); + } + } + } #endif + register_machines(); machine = first_machine; initrd_filename = NULL; @@ -5499,6 +6067,11 @@ int main(int argc, char **argv) case QEMU_OPTION_fdb: fd_filename[1] = optarg; break; +#ifdef TARGET_I386 + case QEMU_OPTION_no_fd_bootchk: + fd_bootchk = 0; + break; +#endif #ifdef USE_CODE_COPY case QEMU_OPTION_no_code_copy: code_copy_enabled = 0; @@ -5675,7 +6248,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_usbdevice: usb_enabled = 1; - if (usb_devices_index >= MAX_VM_USB_PORTS) { + if (usb_devices_index >= MAX_USB_CMDLINE) { fprintf(stderr, "Too many USB devices\n"); exit(1); } @@ -5698,8 +6271,8 @@ int main(int argc, char **argv) exit(1); } break; - case QEMU_OPTION_vncviewer: - vncviewer++; + case QEMU_OPTION_no_acpi: + acpi_enabled = 0; break; case QEMU_OPTION_domainname: strncat(domain_name, optarg, sizeof(domain_name) - 20); @@ -5718,6 +6291,9 @@ int main(int argc, char **argv) case QEMU_OPTION_acpi: acpi_enabled = 1; break; + case QEMU_OPTION_vncviewer: + vncviewer++; + break; } } } @@ -5749,16 +6325,11 @@ int main(int argc, char **argv) } #endif /* !CONFIG_DM */ -#if !defined(CONFIG_SOFTMMU) - /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ - { - static uint8_t stdout_buf[4096]; - setvbuf(stdout, stdout_buf, _IOLBF, sizeof(stdout_buf)); - } -#else setvbuf(stdout, NULL, _IOLBF, 0); -#endif + init_timers(); + init_timer_alarm(); + #ifdef _WIN32 socket_init(); #endif @@ -5859,45 +6430,11 @@ int main(int argc, char **argv) #endif #else /* !CONFIG_DM */ -#ifdef CONFIG_SOFTMMU phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { fprintf(stderr, "Could not allocate physical memory\n"); exit(1); } -#else - /* as we must map the same page at several addresses, we must use - a fd */ - { - const char *tmpdir; - - tmpdir = getenv("QEMU_TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; - snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); - if (mkstemp(phys_ram_file) < 0) { - fprintf(stderr, "Could not create temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } - phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); - if (phys_ram_fd < 0) { - fprintf(stderr, "Could not open temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } - ftruncate(phys_ram_fd, phys_ram_size); - unlink(phys_ram_file); - phys_ram_base = mmap(get_mmap_addr(phys_ram_size), - phys_ram_size, - PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, - phys_ram_fd, 0); - if (phys_ram_base == MAP_FAILED) { - fprintf(stderr, "Could not map physical memory\n"); - exit(1); - } - } -#endif #endif /* !CONFIG_DM */ @@ -5952,22 +6489,10 @@ int main(int argc, char **argv) } } - /* init USB devices */ - if (usb_enabled) { - vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS); - for(i = 0; i < usb_devices_index; i++) { - if (usb_device_add(usb_devices[i]) < 0) { - fprintf(stderr, "Warning: could not add USB device %s\n", - usb_devices[i]); - } - } - } - register_savevm("timer", 0, 1, timer_save, timer_load, NULL); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); init_ioports(); - cpu_calibrate_ticks(); /* terminal init */ if (nographic) { @@ -6003,7 +6528,7 @@ int main(int argc, char **argv) exit(1); } if (!strcmp(serial_devices[i], "vc")) - qemu_chr_printf(serial_hds[i], "serial%d console\n", i); + qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); } } @@ -6016,55 +6541,10 @@ int main(int argc, char **argv) exit(1); } if (!strcmp(parallel_devices[i], "vc")) - qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i); + qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); } } - /* setup cpu signal handlers for MMU / self modifying code handling */ -#if !defined(CONFIG_SOFTMMU) - -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - { - stack_t stk; - signal_stack = memalign(16, SIGNAL_STACK_SIZE); - stk.ss_sp = signal_stack; - stk.ss_size = SIGNAL_STACK_SIZE; - stk.ss_flags = 0; - - if (sigaltstack(&stk, NULL) < 0) { - fprintf(logfile, "sigaltstack returned error %d\n", errno); - exit(1); - } - } -#endif - { - struct sigaction act; - - sigfillset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif - act.sa_sigaction = host_segv_handler; - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGBUS, &act, NULL); -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - sigaction(SIGFPE, &act, NULL); -#endif - } -#endif - -#ifndef _WIN32 - { - struct sigaction act; - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &act, NULL); - } -#endif - init_timers(); - qemu_set_fd_handler(xenstore_fd(), xenstore_process_event, NULL, NULL); machine->init(ram_size, vga_ram_size, boot_device, @@ -6072,6 +6552,16 @@ int main(int argc, char **argv) kernel_filename, kernel_cmdline, initrd_filename, timeoffset); + /* init USB devices */ + if (usb_enabled) { + for(i = 0; i < usb_devices_index; i++) { + if (usb_device_add(usb_devices[i]) < 0) { + fprintf(stderr, "Warning: could not add USB device %s\n", + usb_devices[i]); + } + } + } + if (vnc_display == -1) { gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 5eca554463..a95d0687a5 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -37,7 +37,6 @@ #include #include #include -#include "audio/audio.h" #include "xenctrl.h" #include "xs.h" @@ -49,16 +48,24 @@ #endif #ifdef _WIN32 +#include +#define fsync _commit #define lseek _lseeki64 #define ENOTSUP 4096 -/* XXX: find 64 bit version */ -#define ftruncate chsize +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + static inline char *realpath(const char *path, char *resolved_path) { _fullpath(resolved_path, path, _MAX_PATH); return resolved_path; } + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" #endif #ifdef QEMU_TOOL @@ -72,6 +79,7 @@ static inline char *realpath(const char *path, char *resolved_path) #else +#include "audio/audio.h" #include "cpu.h" #include "gdbstub.h" @@ -163,7 +171,7 @@ extern int acpi_enabled; extern int smp_cpus; /* XXX: make it dynamic */ -#if defined (TARGET_PPC) +#if defined (TARGET_PPC) || defined (TARGET_SPARC64) #define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) #define BIOS_SIZE (128 * 1024) @@ -236,6 +244,14 @@ typedef int PollingFunc(void *opaque); int qemu_add_polling_cb(PollingFunc *func, void *opaque); void qemu_del_polling_cb(PollingFunc *func, void *opaque); +#ifdef _WIN32 +/* Wait objects handling */ +typedef void WaitObjectFunc(void *opaque); + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +#endif + /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ @@ -393,6 +409,7 @@ int qemu_timer_pending(QEMUTimer *ts); extern int64_t ticks_per_sec; extern int pit_min_timer_count; +int64_t cpu_get_ticks(void); void cpu_enable_ticks(void); void cpu_disable_ticks(void); @@ -515,6 +532,8 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +/* Ensure contents are flushed to disk. */ +void bdrv_flush(BlockDriverState *bs); #define BDRV_TYPE_HD 0 #define BDRV_TYPE_CDROM 1 @@ -612,6 +631,20 @@ typedef struct PCIIORegion { #define PCI_ROM_SLOT 6 #define PCI_NUM_REGIONS 7 + +#define PCI_DEVICES_MAX 64 + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + struct PCIDevice { /* PCI config space */ uint8_t config[256]; @@ -625,6 +658,7 @@ struct PCIDevice { /* do not access the following fields */ PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; + /* ??? This is a PC-specific hack, and should be removed. */ int irq_index; }; @@ -646,21 +680,37 @@ void pci_default_write_config(PCIDevice *d, void generic_pci_save(QEMUFile* f, void *opaque); int generic_pci_load(QEMUFile* f, void *opaque, int version_id); -extern struct PIIX3State *piix3_state; - -PCIBus *i440fx_init(void); -void piix3_init(PCIBus *bus); -void pci_bios_init(void); -void pci_info(void); - -/* temporary: will be moved in platform specific file */ -void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque); -PCIBus *pci_prep_init(void); -PCIBus *pci_grackle_init(uint32_t base); -PCIBus *pci_pmac_init(void); -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base); +typedef void (*pci_set_irq_fn)(PCIDevice *pci_dev, void *pic, + int irq_num, int level); +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min); void pci_nic_init(PCIBus *bus, NICInfo *nd); +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); +uint32_t pci_data_read(void *opaque, uint32_t addr, int len); +int pci_bus_num(PCIBus *s); +void pci_for_each_device(void (*fn)(PCIDevice *d)); + +void pci_info(void); + +/* prep_pci.c */ +PCIBus *pci_prep_init(void); + +/* grackle_pci.c */ +PCIBus *pci_grackle_init(uint32_t base, void *pic); + +/* unin_pci.c */ +PCIBus *pci_pmac_init(void *pic); + +/* apb_pci.c */ +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, + void *pic); + +PCIBus *pci_vpb_init(void *pic); + +/* piix_pci.c */ +PCIBus *i440fx_init(void); +int piix3_init(PCIBus *bus); +void pci_bios_init(void); /* openpic.c */ typedef struct openpic_t openpic_t; @@ -690,12 +740,13 @@ extern struct soundhw soundhw[]; /* vga.c */ -#define VGA_RAM_SIZE (4096 * 1024) +#define VGA_RAM_SIZE (8192 * 1024) struct DisplayState { uint8_t *data; int linesize; int depth; + int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ int width; int height; void *opaque; @@ -745,10 +796,14 @@ void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, int secondary_ide_enabled); -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn); int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); +/* cdrom.c */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); + /* es1370.c */ int es1370_init (PCIBus *bus, AudioState *s); @@ -794,6 +849,10 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd); void pci_rtl8139_init(PCIBus *bus, NICInfo *nd); +/* pcnet.c */ + +void pci_pcnet_init(PCIBus *bus, NICInfo *nd); + /* pckbd.c */ void kbd_init(void); @@ -861,9 +920,15 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); void pcspk_init(PITState *); int pcspk_audio_init(AudioState *); +/* acpi.c */ +extern int acpi_enabled; +void piix4_pm_init(PCIBus *bus, int devfn); +void acpi_bios_init(void); + /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; +extern int fd_bootchk; void ioport_set_a20(int enable); int ioport_get_a20(void); @@ -1006,15 +1071,32 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); /* usb ports of the VM */ -#define MAX_VM_USB_PORTS 8 +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach); -extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; -extern USBDevice *vm_usb_hub; +#define VM_USB_HUB_SIZE 8 void do_usb_add(const char *devname); void do_usb_del(const char *devname); void usb_info(void); +/* scsi-disk.c */ +typedef struct SCSIDevice SCSIDevice; +typedef void (*scsi_completionfn)(void *, uint32_t, int); + +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + scsi_completionfn completion, + void *opaque); +void scsi_disk_destroy(SCSIDevice *s); + +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); +int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); +int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); + +/* lsi53c895a.c */ +void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *lsi_scsi_init(PCIBus *bus, int devfn); + /* integratorcp.c */ extern QEMUMachine integratorcp926_machine; extern QEMUMachine integratorcp1026_machine; @@ -1082,6 +1164,15 @@ int sh7750_register_io_device(struct SH7750State *s, /* tc58128.c */ int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); +/* NOR flash devices */ +typedef struct pflash_t pflash_t; + +pflash_t *pflash_register (target_ulong base, ram_addr_t off, + BlockDriverState *bs, + target_ulong sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c index bcba222e42..3c0a7cdad9 100644 --- a/tools/ioemu/vnc.c +++ b/tools/ioemu/vnc.c @@ -47,6 +47,20 @@ typedef struct VncState VncState; typedef int VncReadEvent(VncState *vs, char *data, size_t len); +typedef void VncWritePixels(VncState *vs, void *data, int size); + +typedef void VncSendHextileTile(VncState *vs, + int x, int y, int w, int h, + uint32_t *last_bg, + uint32_t *last_fg, + int *has_bg, int *has_fg); + +#if 0 +#define VNC_MAX_WIDTH 2048 +#define VNC_MAX_HEIGHT 2048 +#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) +#endif + struct VncState { QEMUTimer *timer; @@ -62,13 +76,19 @@ struct VncState int has_update; /* there's outstanding updates in the * visible area */ char *old_data; - int depth; + int depth; /* internal VNC frame buffer byte per pixel */ int has_resize; int has_hextile; Buffer output; Buffer input; kbd_layout_t *kbd_layout; - int ctl_keys; /* Ctrl+Alt starts calibration */ + /* current output mode information */ + VncWritePixels *write_pixels; + VncSendHextileTile *send_hextile_tile; + int pix_bpp, pix_big_endian; + int red_shift, red_max, red_shift1; + int green_shift, green_max, green_shift1; + int blue_shift, blue_max, blue_shift1; VncReadEvent *read_handler; size_t read_handler_expect; @@ -79,6 +99,8 @@ struct VncState int visible_h; int slow_client; + + int ctl_keys; /* Ctrl+Alt starts calibration */ }; #define DIRTY_PIXEL_BITS 64 @@ -104,6 +126,49 @@ static void vnc_update_client(void *opaque); static void vnc_client_read(void *opaque); static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h); +#if 0 +static inline void vnc_set_bit(uint32_t *d, int k) +{ + d[k >> 5] |= 1 << (k & 0x1f); +} + +static inline void vnc_clear_bit(uint32_t *d, int k) +{ + d[k >> 5] &= ~(1 << (k & 0x1f)); +} + +static inline void vnc_set_bits(uint32_t *d, int n, int nb_words) +{ + int j; + + j = 0; + while (n >= 32) { + d[j++] = -1; + n -= 32; + } + if (n > 0) + d[j++] = (1 << n) - 1; + while (j < nb_words) + d[j++] = 0; +} + +static inline int vnc_get_bit(const uint32_t *d, int k) +{ + return (d[k >> 5] >> (k & 0x1f)) & 1; +} + +static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, + int nb_words) +{ + int i; + for(i = 0; i < nb_words; i++) { + if ((d1[i] & d2[i]) != 0) + return 1; + } + return 0; +} +#endif + static void set_bits_in_row(VncState *vs, uint64_t *row, int x, int y, int w, int h) { @@ -182,6 +247,66 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h) framebuffer_set_updated(vs, 0, 0, ds->width, ds->height); } +/* fastest code */ +static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size) +{ + vnc_write(vs, pixels, size); +} + +/* slowest but generic code. */ +static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) +{ + unsigned int r, g, b; + + r = (v >> vs->red_shift1) & vs->red_max; + g = (v >> vs->green_shift1) & vs->green_max; + b = (v >> vs->blue_shift1) & vs->blue_max; + v = (r << vs->red_shift) | + (g << vs->green_shift) | + (b << vs->blue_shift); + switch(vs->pix_bpp) { + case 1: + buf[0] = v; + break; + case 2: + if (vs->pix_big_endian) { + buf[0] = v >> 8; + buf[1] = v; + } else { + buf[1] = v >> 8; + buf[0] = v; + } + break; + default: + case 4: + if (vs->pix_big_endian) { + buf[0] = v >> 24; + buf[1] = v >> 16; + buf[2] = v >> 8; + buf[3] = v; + } else { + buf[3] = v >> 24; + buf[2] = v >> 16; + buf[1] = v >> 8; + buf[0] = v; + } + break; + } +} + +static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) +{ + uint32_t *pixels = pixels1; + uint8_t buf[4]; + int n, i; + + n = size >> 2; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } +} + static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) { int i; @@ -191,7 +316,7 @@ static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h row = vs->ds->data + y * vs->ds->linesize + x * vs->depth; for (i = 0; i < h; i++) { - vnc_write(vs, row, w * vs->depth); + vs->write_pixels(vs, row, w * vs->depth); row += vs->ds->linesize; } } @@ -214,35 +339,26 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) #include "vnchextile.h" #undef BPP +#define GENERIC +#define BPP 32 +#include "vnchextile.h" +#undef BPP +#undef GENERIC + static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h) { int i, j; int has_fg, has_bg; uint32_t last_fg32, last_bg32; - uint16_t last_fg16, last_bg16; - uint8_t last_fg8, last_bg8; vnc_framebuffer_update(vs, x, y, w, h, 5); has_fg = has_bg = 0; for (j = y; j < (y + h); j += 16) { for (i = x; i < (x + w); i += 16) { - switch (vs->depth) { - case 1: - send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg8, &last_fg8, &has_bg, &has_fg); - break; - case 2: - send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg16, &last_fg16, &has_bg, &has_fg); - break; - case 4: - send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg32, &last_fg32, &has_bg, &has_fg); - break; - default: - break; - } + vs->send_hextile_tile(vs, i, j, + MIN(16, x + w - i), MIN(16, y + h - j), + &last_bg32, &last_fg32, &has_bg, &has_fg); } } } @@ -522,7 +638,7 @@ static void vnc_client_error(VncState *vs) static void vnc_client_write(void *opaque) { - ssize_t ret; + long ret; VncState *vs = opaque; ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); @@ -547,7 +663,7 @@ static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) static void vnc_client_read(void *opaque) { VncState *vs = opaque; - ssize_t ret; + long ret; buffer_reserve(&vs->input, 4096); @@ -816,30 +932,79 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) } } +static int compute_nbits(unsigned int val) +{ + int n; + n = 0; + while (val != 0) { + n++; + val >>= 1; + } + return n; +} + static void set_pixel_format(VncState *vs, int bits_per_pixel, int depth, int big_endian_flag, int true_color_flag, int red_max, int green_max, int blue_max, int red_shift, int green_shift, int blue_shift) { - switch (bits_per_pixel) { - case 32: - case 24: - vs->depth = 4; - break; - case 16: - vs->depth = 2; - break; - case 8: - vs->depth = 1; - break; - default: - vnc_client_error(vs); - break; - } + int host_big_endian_flag; - if (!true_color_flag) +#ifdef WORDS_BIGENDIAN + host_big_endian_flag = 1; +#else + host_big_endian_flag = 0; +#endif + if (!true_color_flag) { + fail: vnc_client_error(vs); + return; + } + if (bits_per_pixel == 32 && + host_big_endian_flag == big_endian_flag && + red_max == 0xff && green_max == 0xff && blue_max == 0xff && + red_shift == 16 && green_shift == 8 && blue_shift == 0) { + vs->depth = 4; + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_32; + } else + if (bits_per_pixel == 16 && + host_big_endian_flag == big_endian_flag && + red_max == 31 && green_max == 63 && blue_max == 31 && + red_shift == 11 && green_shift == 5 && blue_shift == 0) { + vs->depth = 2; + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_16; + } else + if (bits_per_pixel == 8 && + red_max == 7 && green_max == 7 && blue_max == 3 && + red_shift == 5 && green_shift == 2 && blue_shift == 0) { + vs->depth = 1; + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_8; + } else + { + /* generic and slower case */ + if (bits_per_pixel != 8 && + bits_per_pixel != 16 && + bits_per_pixel != 32) + goto fail; + vs->depth = 4; + vs->red_shift = red_shift; + vs->red_max = red_max; + vs->red_shift1 = 24 - compute_nbits(red_max); + vs->green_shift = green_shift; + vs->green_max = green_max; + vs->green_shift1 = 16 - compute_nbits(green_max); + vs->blue_shift = blue_shift; + vs->blue_max = blue_max; + vs->blue_shift1 = 8 - compute_nbits(blue_max); + vs->pix_bpp = bits_per_pixel / 8; + vs->pix_big_endian = big_endian_flag; + vs->write_pixels = vnc_write_pixels_generic; + vs->send_hextile_tile = send_hextile_tile_generic; + } vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); @@ -929,7 +1094,11 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ vnc_write_u8(vs, vs->depth * 8); /* depth */ +#ifdef WORDS_BIGENDIAN + vnc_write_u8(vs, 1); /* big-endian-flag */ +#else vnc_write_u8(vs, 0); /* big-endian-flag */ +#endif vnc_write_u8(vs, 1); /* true-color-flag */ if (vs->depth == 4) { vnc_write_u16(vs, 0xFF); /* red-max */ @@ -938,6 +1107,7 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write_u8(vs, 16); /* red-shift */ vnc_write_u8(vs, 8); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_32; } else if (vs->depth == 2) { vnc_write_u16(vs, 31); /* red-max */ vnc_write_u16(vs, 63); /* green-max */ @@ -945,14 +1115,18 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write_u8(vs, 11); /* red-shift */ vnc_write_u8(vs, 5); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_16; } else if (vs->depth == 1) { - vnc_write_u16(vs, 3); /* red-max */ + /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ + vnc_write_u16(vs, 7); /* red-max */ vnc_write_u16(vs, 7); /* green-max */ vnc_write_u16(vs, 3); /* blue-max */ vnc_write_u8(vs, 5); /* red-shift */ vnc_write_u8(vs, 2); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_8; } + vs->write_pixels = vnc_write_pixels_copy; vnc_write(vs, pad, 3); /* padding */ diff --git a/tools/ioemu/vnchextile.h b/tools/ioemu/vnchextile.h index 7277670a56..16a354d60a 100644 --- a/tools/ioemu/vnchextile.h +++ b/tools/ioemu/vnchextile.h @@ -1,15 +1,23 @@ #define CONCAT_I(a, b) a ## b #define CONCAT(a, b) CONCAT_I(a, b) #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) +#ifdef GENERIC +#define NAME generic +#else +#define NAME BPP +#endif -static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, - int x, int y, int w, int h, - pixel_t *last_bg, pixel_t *last_fg, - int *has_bg, int *has_fg) +static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, + int x, int y, int w, int h, + uint32_t *last_bg32, + uint32_t *last_fg32, + int *has_bg, int *has_fg) { char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); pixel_t *irow = (pixel_t *)row; int j, i; + pixel_t *last_bg = (pixel_t *)last_bg32; + pixel_t *last_fg = (pixel_t *)last_fg32; pixel_t bg = 0; pixel_t fg = 0; int n_colors = 0; @@ -122,10 +130,15 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, has_color = 1; } else if (irow[i] != color) { has_color = 0; - +#ifdef GENERIC + vnc_convert_pixel(vs, data + n_data, color); + n_data += vs->pix_bpp; +#else memcpy(data + n_data, &color, sizeof(color)); - hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1); - n_data += 2 + sizeof(pixel_t); + n_data += sizeof(pixel_t); +#endif + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); + n_data += 2; n_subtiles++; min_x = -1; @@ -137,9 +150,15 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, } } if (has_color) { - memcpy(data + n_data, &color, sizeof(color)); - hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1); - n_data += 2 + sizeof(pixel_t); +#ifdef GENERIC + vnc_convert_pixel(vs, data + n_data, color); + n_data += vs->pix_bpp; +#else + memcpy(data + n_data, &color, sizeof(color)); + n_data += sizeof(pixel_t); +#endif + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); + n_data += 2; n_subtiles++; } irow += vs->ds->linesize / sizeof(pixel_t); @@ -169,21 +188,22 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, vnc_write_u8(vs, flags); if (n_colors < 4) { if (flags & 0x02) - vnc_write(vs, last_bg, sizeof(pixel_t)); + vs->write_pixels(vs, last_bg, sizeof(pixel_t)); if (flags & 0x04) - vnc_write(vs, last_fg, sizeof(pixel_t)); + vs->write_pixels(vs, last_fg, sizeof(pixel_t)); if (n_subtiles) { vnc_write_u8(vs, n_subtiles); vnc_write(vs, data, n_data); } } else { for (j = 0; j < h; j++) { - vnc_write(vs, row, w * vs->depth); + vs->write_pixels(vs, row, w * vs->depth); row += vs->ds->linesize; } } } +#undef NAME #undef pixel_t #undef CONCAT_I #undef CONCAT From 21d94d93884bfc083a39ac145b5b0529ac752279 Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Mon, 7 Aug 2006 18:26:20 +0100 Subject: [PATCH 109/111] [qemu] Update ioemu to qemu 0.8.2. (.CVS files) Signed-off-by: Christian Limpach --- tools/ioemu/.CVS/Entries | 190 +++++++++++++-------------- tools/ioemu/.CVS/Entries.Log | 7 + tools/ioemu/.CVS/Tag | 2 +- tools/ioemu/.cvsignore | 13 ++ tools/ioemu/audio/.CVS/Entries | 37 +++--- tools/ioemu/audio/.CVS/Tag | 2 +- tools/ioemu/fpu/.CVS/Entries | 12 +- tools/ioemu/fpu/.CVS/Tag | 2 +- tools/ioemu/hw/.CVS/Entries | 159 ++++++++++++---------- tools/ioemu/hw/.CVS/Tag | 2 +- tools/ioemu/keymaps/.CVS/Entries | 70 +++++----- tools/ioemu/keymaps/.CVS/Tag | 2 +- tools/ioemu/pc-bios/.CVS/Entries | 27 ++-- tools/ioemu/pc-bios/.CVS/Tag | 2 +- tools/ioemu/target-i386/.CVS/Entries | 24 ++-- tools/ioemu/target-i386/.CVS/Tag | 2 +- tools/ioemu/tests/.CVS/Entries | 34 ++--- tools/ioemu/tests/.CVS/Tag | 2 +- 18 files changed, 313 insertions(+), 276 deletions(-) create mode 100644 tools/ioemu/.CVS/Entries.Log diff --git a/tools/ioemu/.CVS/Entries b/tools/ioemu/.CVS/Entries index 43bfd4c3ee..1e081de485 100644 --- a/tools/ioemu/.CVS/Entries +++ b/tools/ioemu/.CVS/Entries @@ -11,99 +11,99 @@ D/tests//// D/fpu//// D/keymaps//// D/target-mips//// -/.cvsignore/1.13/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/COPYING/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/COPYING.LIB/1.2/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/Changelog/1.116/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/LICENSE/1.2/Sat Feb 12 14:45:23 2005//Trelease_0_8_1 -/Makefile/1.99/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/Makefile.target/1.107/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/README/1.12/Wed May 24 10:40:08 2006//Trelease_0_8_1 -/README.distrib/1.2/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/TODO/1.38/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/VERSION/1.28/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/a.out.h/1.2/Wed May 24 10:40:08 2006//Trelease_0_8_1 -/aes.c/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/aes.h/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/alpha-dis.c/1.3/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/alpha.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/arm-dis.c/1.3/Wed May 24 10:40:08 2006//Trelease_0_8_1 -/arm.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/block-bochs.c/1.1/Tue Apr 26 21:34:00 2005//Trelease_0_8_1 -/block-cloop.c/1.3/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/block-cow.c/1.5/Thu May 25 12:38:49 2006//Trelease_0_8_1 -/block-dmg.c/1.4/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/block-qcow.c/1.6/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/block-vmdk.c/1.7/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/block-vpc.c/1.2/Thu May 25 12:38:49 2006//Trelease_0_8_1 -/block-vvfat.c/1.5/Thu May 25 18:22:25 2006//Trelease_0_8_1 -/block.c/1.26/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/block_int.h/1.4/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/bswap.h/1.5/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/cocoa.m/1.8/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/configure/1.100/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/console.c/1.5/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/cpu-all.h/1.54/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/cpu-defs.h/1.15/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/cpu-exec.c/1.78/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/dis-asm.h/1.11/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/disas.c/1.30/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/disas.h/1.7/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/dyngen-exec.h/1.27/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/dyngen-op.h/1.1/Mon Jan 3 23:40:55 2005//Trelease_0_8_1 -/dyngen.c/1.42/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/dyngen.h/1.10/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/elf.h/1.6/Thu May 25 12:38:50 2006//Trelease_0_8_1 -/elf_ops.h/1.3/Tue May 2 20:54:12 2006//Trelease_0_8_1 -/exec-all.h/1.47/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/exec.c/1.79/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/gdbstub.c/1.36/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/gdbstub.h/1.2/Tue Apr 26 20:42:36 2005//Trelease_0_8_1 -/i386-dis.c/1.5/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/i386-vl.ld/1.3/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/i386.ld/1.2/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/ia64.ld/1.1/Thu Apr 7 22:20:28 2005//Trelease_0_8_1 -/keymaps.c/1.2/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/kqemu.c/1.10/Thu May 25 18:22:26 2006//Trelease_0_8_1 -/kqemu.h/1.1/Wed Feb 8 22:39:17 2006//Trelease_0_8_1 -/linux-2.6.9-qemu-fast.patch/1.1/Wed Dec 8 23:48:11 2004//Trelease_0_8_1 -/loader.c/1.2/Wed Apr 26 22:05:26 2006//Trelease_0_8_1 -/m68k-dis.c/1.1/Sun Nov 6 16:52:11 2005//Trelease_0_8_1 -/m68k.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/mips-dis.c/1.3/Thu May 25 18:22:28 2006//Trelease_0_8_1 -/monitor.c/1.48/Thu May 25 18:22:28 2006//Trelease_0_8_1 -/osdep.c/1.10/Wed May 24 10:40:10 2006//Trelease_0_8_1 -/osdep.h/1.5/Wed May 24 10:40:10 2006//Trelease_0_8_1 -/ppc-dis.c/1.7/Thu May 25 12:38:51 2006//Trelease_0_8_1 -/ppc.ld/1.2/Thu May 25 12:38:51 2006//Trelease_0_8_1 -/qemu-binfmt-conf.sh/1.4/Thu May 25 18:22:28 2006//Trelease_0_8_1 -/qemu-doc.texi/1.87/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/qemu-img.c/1.8/Thu May 25 12:38:51 2006//Trelease_0_8_1 -/qemu-img.texi/1.2/Thu May 25 12:38:51 2006//Trelease_0_8_1 -/qemu-tech.texi/1.9/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/qemu_socket.h/1.1/Sun Apr 30 22:53:25 2006//Trelease_0_8_1 -/readline.c/1.1/Tue May 23 19:16:56 2006//Trelease_0_8_1 -/s390.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/sdl.c/1.26/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/sdl_keysym.h/1.3/Tue Mar 1 21:43:41 2005//Trelease_0_8_1 -/sh4-dis.c/1.1/Thu Apr 27 21:05:14 2006//Trelease_0_8_1 -/softmmu_exec.h/1.1/Sun Oct 30 18:16:26 2005//Trelease_0_8_1 -/softmmu_header.h/1.13/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/softmmu_template.h/1.16/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/sparc-dis.c/1.2/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/sparc.ld/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/tap-win32.c/1.2/Sun Feb 19 12:40:00 2006//Trelease_0_8_1 -/texi2pod.pl/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/thunk.c/1.6/Wed May 24 10:40:10 2006//Trelease_0_8_1 -/thunk.h/1.13/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/translate-all.c/1.14/Thu May 25 18:22:29 2006//Trelease_0_8_1 -/translate-op.c/1.1/Sun Mar 13 16:53:06 2005//Trelease_0_8_1 -/usb-linux.c/1.4/Sat Mar 11 18:03:38 2006//Trelease_0_8_1 -/vgafont.h/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/vl.c/1.184/Thu May 25 18:22:30 2006//Trelease_0_8_1 -/vl.h/1.116/Thu May 25 18:22:30 2006//Trelease_0_8_1 -/vnc.c/1.4/Mon May 1 21:44:22 2006//Trelease_0_8_1 -/vnc_keysym.h/1.1/Sun Apr 30 21:28:36 2006//Trelease_0_8_1 -/vnchextile.h/1.1/Sun Apr 30 21:28:36 2006//Trelease_0_8_1 -/x86_64.ld/1.1/Thu Jan 6 20:50:00 2005//Trelease_0_8_1 D/target-sh4//// +/.cvsignore/1.14/Sun Aug 6 01:03:44 2006//Trelease_0_8_2 +/COPYING/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/COPYING.LIB/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/Changelog/1.121/Sun Aug 6 01:03:44 2006//Trelease_0_8_2 +/LICENSE/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/Makefile/1.104/Sun Aug 6 01:03:44 2006//Trelease_0_8_2 +/Makefile.target/1.121/Sun Aug 6 01:03:44 2006//Trelease_0_8_2 +/README/1.12/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/README.distrib/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/TODO/1.39/Sun Aug 6 01:03:44 2006//Trelease_0_8_2 +/VERSION/1.29/Sun Aug 6 01:03:44 2006//Trelease_0_8_2 +/a.out.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/aes.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/aes.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/alpha-dis.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/alpha.ld/1.1/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/arm-dis.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/arm.ld/1.1/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block-bochs.c/1.1/Sun Aug 6 00:55:02 2006//Trelease_0_8_2 +/block-cloop.c/1.3/Sun Aug 6 00:55:02 2006//Trelease_0_8_2 +/block-cow.c/1.6/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block-dmg.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/block-qcow.c/1.7/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block-vmdk.c/1.8/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block-vpc.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block-vvfat.c/1.6/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block.c/1.28/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/block_int.h/1.5/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/bswap.h/1.5/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/cocoa.m/1.10/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/configure/1.110/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/console.c/1.8/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/cpu-all.h/1.57/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/cpu-defs.h/1.16/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/cpu-exec.c/1.83/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/dis-asm.h/1.11/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/disas.c/1.31/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/disas.h/1.7/Sun Aug 6 00:55:03 2006//Trelease_0_8_2 +/dyngen-exec.h/1.29/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/dyngen-op.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/dyngen.c/1.45/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/dyngen.h/1.11/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/elf.h/1.7/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/elf_ops.h/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/exec-all.h/1.48/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/exec.c/1.82/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/gdbstub.c/1.40/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/gdbstub.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/i386-dis.c/1.5/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/i386-vl.ld/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/i386.ld/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/ia64.ld/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/keymaps.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/kqemu.c/1.12/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/kqemu.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/linux-2.6.9-qemu-fast.patch/1.1/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/loader.c/1.3/Sun Aug 6 01:03:45 2006//Trelease_0_8_2 +/m68k-dis.c/1.1/Sun Aug 6 01:03:46 2006//Trelease_0_8_2 +/m68k.ld/1.1/Sun Aug 6 01:03:46 2006//Trelease_0_8_2 +/mips-dis.c/1.4/Sun Aug 6 01:03:47 2006//Trelease_0_8_2 +/monitor.c/1.54/Sun Aug 6 01:03:47 2006//Trelease_0_8_2 +/osdep.c/1.11/Sun Aug 6 01:03:47 2006//Trelease_0_8_2 +/osdep.h/1.6/Sun Aug 6 01:03:47 2006//Trelease_0_8_2 +/ppc-dis.c/1.7/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/ppc.ld/1.2/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/qemu-binfmt-conf.sh/1.4/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/qemu-doc.texi/1.100/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/qemu-img.c/1.10/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/qemu-img.texi/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/qemu-tech.texi/1.9/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/qemu_socket.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/readline.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/s390.ld/1.1/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/sdl.c/1.29/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/sdl_keysym.h/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/sh4-dis.c/1.1/Sun Aug 6 01:03:48 2006//Trelease_0_8_2 +/softmmu_exec.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/softmmu_header.h/1.13/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/softmmu_template.h/1.16/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/sparc-dis.c/1.3/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/sparc.ld/1.1/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/tap-win32.c/1.3/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/texi2pod.pl/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/thunk.c/1.6/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/thunk.h/1.13/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/translate-all.c/1.14/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/translate-op.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/usb-linux.c/1.8/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/vgafont.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/vl.c/1.202/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/vl.h/1.136/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/vnc.c/1.7/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/vnc_keysym.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/vnchextile.h/1.2/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/x86_64.ld/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 diff --git a/tools/ioemu/.CVS/Entries.Log b/tools/ioemu/.CVS/Entries.Log new file mode 100644 index 0000000000..45c50e12f4 --- /dev/null +++ b/tools/ioemu/.CVS/Entries.Log @@ -0,0 +1,7 @@ +A D/linux-user//// +A D/slirp//// +A D/target-arm//// +A D/target-mips//// +A D/target-ppc//// +A D/target-sh4//// +A D/target-sparc//// diff --git a/tools/ioemu/.CVS/Tag b/tools/ioemu/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/.CVS/Tag +++ b/tools/ioemu/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/.cvsignore b/tools/ioemu/.cvsignore index 101139fc8d..7be41c433f 100644 --- a/tools/ioemu/.cvsignore +++ b/tools/ioemu/.cvsignore @@ -11,6 +11,8 @@ ppc64-softmmu ppc-user qemu-doc.html qemu-tech.html +qemu-doc.info +qemu-tech.info qemu.1 qemu.pod qemu-img.1 @@ -25,5 +27,16 @@ mips-softmmu mipsel-softmmu mips-user mipsel-user +.gdbinit sh4-user sh4-softmmu +*.aux +*.cp +*.dvi +*.fn +*.ky +*.log +*.pg +*.toc +*.tp +*.vr diff --git a/tools/ioemu/audio/.CVS/Entries b/tools/ioemu/audio/.CVS/Entries index bc177d5db8..7d60c0c65e 100644 --- a/tools/ioemu/audio/.CVS/Entries +++ b/tools/ioemu/audio/.CVS/Entries @@ -1,19 +1,20 @@ -/alsaaudio.c/1.5/Sun Nov 20 18:53:05 2005//Trelease_0_8_1 -/audio.c/1.9/Thu May 25 18:22:31 2006//Trelease_0_8_1 -/audio.h/1.5/Thu May 25 18:22:31 2006//Trelease_0_8_1 -/audio_int.h/1.7/Thu May 25 18:22:31 2006//Trelease_0_8_1 -/audio_template.h/1.4/Sun Nov 20 16:24:34 2005//Trelease_0_8_1 -/coreaudio.c/1.5/Sun Nov 20 18:53:42 2005//Trelease_0_8_1 -/dsound_template.h/1.2/Sat Nov 5 18:55:27 2005//Trelease_0_8_1 -/dsoundaudio.c/1.2/Sat Nov 5 18:55:27 2005//Trelease_0_8_1 -/fmodaudio.c/1.5/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/mixeng.c/1.4/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/mixeng.h/1.2/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/mixeng_template.h/1.2/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/noaudio.c/1.4/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/ossaudio.c/1.9/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/rate_template.h/1.2/Sat Nov 5 18:55:27 2005//Trelease_0_8_1 -/sdlaudio.c/1.6/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/sys-queue.h/1.1/Sun Oct 30 18:58:22 2005//Trelease_0_8_1 -/wavaudio.c/1.6/Thu May 25 18:22:32 2006//Trelease_0_8_1 +/alsaaudio.c/1.7/Sun Aug 6 01:03:49 2006//Trelease_0_8_2 +/audio.c/1.14/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/audio.h/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/audio_int.h/1.10/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/audio_template.h/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/coreaudio.c/1.7/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/dsound_template.h/1.4/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/dsoundaudio.c/1.3/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/fmodaudio.c/1.7/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/mixeng.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/mixeng.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/mixeng_template.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/noaudio.c/1.7/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/ossaudio.c/1.11/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/rate_template.h/1.3/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/sdlaudio.c/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/sys-queue.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/wavaudio.c/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/wavcapture.c/1.5/Sat Jul 22 17:06:44 2006//Trelease_0_8_2 D diff --git a/tools/ioemu/audio/.CVS/Tag b/tools/ioemu/audio/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/audio/.CVS/Tag +++ b/tools/ioemu/audio/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/fpu/.CVS/Entries b/tools/ioemu/fpu/.CVS/Entries index 4da09e72d9..0e2bf27a9d 100644 --- a/tools/ioemu/fpu/.CVS/Entries +++ b/tools/ioemu/fpu/.CVS/Entries @@ -1,7 +1,7 @@ -/softfloat-macros.h/1.1/Sun Mar 13 16:54:06 2005//Trelease_0_8_1 -/softfloat-native.c/1.3/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/softfloat-native.h/1.6/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/softfloat-specialize.h/1.1/Sun Mar 13 16:54:06 2005//Trelease_0_8_1 -/softfloat.c/1.2/Sun Mar 13 18:52:28 2005//Trelease_0_8_1 -/softfloat.h/1.3/Thu May 25 18:22:32 2006//Trelease_0_8_1 +/softfloat-macros.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/softfloat-native.c/1.4/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/softfloat-native.h/1.6/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/softfloat-specialize.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/softfloat.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/softfloat.h/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 D diff --git a/tools/ioemu/fpu/.CVS/Tag b/tools/ioemu/fpu/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/fpu/.CVS/Tag +++ b/tools/ioemu/fpu/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/hw/.CVS/Entries b/tools/ioemu/hw/.CVS/Entries index aa66f2b34f..600ce46b85 100644 --- a/tools/ioemu/hw/.CVS/Entries +++ b/tools/ioemu/hw/.CVS/Entries @@ -1,72 +1,89 @@ -/adb.c/1.6/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/adlib.c/1.5/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/apic.c/1.8/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/arm_boot.c/1.1/Thu Apr 27 23:15:07 2006//Trelease_0_8_1 -/arm_pic.c/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/arm_pic.h/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/arm_timer.c/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/cirrus_vga.c/1.21/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/cirrus_vga_rop.h/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/cirrus_vga_rop2.h/1.7/Thu May 25 12:52:49 2006//Trelease_0_8_1 -/cuda.c/1.10/Thu May 25 12:38:51 2006//Trelease_0_8_1 -/dma.c/1.14/Thu May 25 18:22:32 2006//Trelease_0_8_1 -/es1370.c/1.4/Sun Nov 20 16:20:39 2005//Trelease_0_8_1 -/esp.c/1.6/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/fdc.c/1.18/Wed May 24 10:40:13 2006//Trelease_0_8_1 -/fmopl.c/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/fmopl.h/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/heathrow_pic.c/1.2/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/i8254.c/1.8/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/i8259.c/1.18/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/ide.c/1.42/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/integratorcp.c/1.9/Thu Apr 27 23:15:07 2006//Trelease_0_8_1 -/iommu.c/1.6/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/lance.c/1.7/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/m48t59.c/1.7/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/m48t59.h/1.5/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/mc146818rtc.c/1.6/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/mips_r4k.c/1.16/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/ne2000.c/1.19/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/openpic.c/1.9/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/parallel.c/1.4/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/pc.c/1.53/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/pci.c/1.24/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/pckbd.c/1.15/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/pcspk.c/1.1/Mon Apr 24 21:58:30 2006//Trelease_0_8_1 -/pl011.c/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/pl050.c/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/pl080.c/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/pl110.c/1.6/Tue Apr 18 19:02:59 2006//Trelease_0_8_1 -/pl110_template.h/1.2/Sun Feb 19 12:31:32 2006//Trelease_0_8_1 -/pl190.c/1.1/Sun Apr 9 01:32:52 2006//Trelease_0_8_1 -/ppc.c/1.9/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/ppc_chrp.c/1.21/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/ppc_prep.c/1.26/Thu May 25 18:22:33 2006//Trelease_0_8_1 -/ps2.c/1.4/Wed Apr 12 21:09:07 2006//Trelease_0_8_1 -/rtl8139.c/1.1/Sun Feb 5 04:14:41 2006//Trelease_0_8_1 -/sb16.c/1.19/Thu May 25 18:22:34 2006//Trelease_0_8_1 -/serial.c/1.12/Thu May 25 18:22:34 2006//Trelease_0_8_1 -/sh7750.c/1.1/Thu Apr 27 21:32:09 2006//Trelease_0_8_1 -/sh7750_regnames.c/1.1/Thu Apr 27 21:32:09 2006//Trelease_0_8_1 -/sh7750_regnames.h/1.1/Thu Apr 27 21:32:09 2006//Trelease_0_8_1 -/sh7750_regs.h/1.1/Thu Apr 27 21:32:09 2006//Trelease_0_8_1 -/shix.c/1.1/Thu Apr 27 21:32:09 2006//Trelease_0_8_1 -/slavio_intctl.c/1.6/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/slavio_misc.c/1.3/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/slavio_serial.c/1.6/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/slavio_timer.c/1.3/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/smc91c111.c/1.3/Sat Feb 4 22:15:28 2006//Trelease_0_8_1 -/sun4m.c/1.16/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/sun4u.c/1.8/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/tc58128.c/1.1/Thu Apr 27 21:32:09 2006//Trelease_0_8_1 -/tcx.c/1.7/Thu May 25 18:22:35 2006//Trelease_0_8_1 -/usb-hid.c/1.2/Wed Apr 12 21:09:07 2006//Trelease_0_8_1 -/usb-hub.c/1.3/Sun Apr 30 21:53:59 2006//Trelease_0_8_1 -/usb-uhci.c/1.8/Tue Apr 25 21:01:19 2006//Trelease_0_8_1 -/usb.c/1.6/Mon Apr 24 21:18:20 2006//Trelease_0_8_1 -/usb.h/1.4/Wed Apr 12 21:09:07 2006//Trelease_0_8_1 -/versatilepb.c/1.2/Thu Apr 27 23:15:07 2006//Trelease_0_8_1 -/vga.c/1.42/Thu May 25 18:22:36 2006//Trelease_0_8_1 -/vga_int.h/1.6/Thu May 25 18:20:53 2006//Trelease_0_8_1 -/vga_template.h/1.11/Wed May 17 14:47:01 2006//Trelease_0_8_1 +/acpi-dsdt.dsl/1.3/Wed Jun 14 18:17:04 2006//Trelease_0_8_2 +/acpi-dsdt.hex/1.3/Wed Jun 14 18:17:04 2006//Trelease_0_8_2 +/acpi.c/1.5/Wed Jun 14 18:17:04 2006//Trelease_0_8_2 +/adb.c/1.6/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/adlib.c/1.6/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/apb_pci.c/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/apic.c/1.9/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/arm_boot.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/arm_pic.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/arm_pic.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/arm_timer.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/cdrom.c/1.1/Thu May 25 23:58:51 2006//Trelease_0_8_2 +/cirrus_vga.c/1.21/Sun Aug 6 00:55:02 2006//Trelease_0_8_2 +/cirrus_vga_rop.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/cirrus_vga_rop2.h/1.7/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/cuda.c/1.11/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/dma.c/1.14/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/es1370.c/1.6/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/esp.c/1.12/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/fdc.c/1.18/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/fmopl.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fmopl.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/grackle_pci.c/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/heathrow_pic.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/i8254.c/1.8/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/i8259.c/1.19/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/ide.c/1.45/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/integratorcp.c/1.9/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/iommu.c/1.6/Sun Aug 6 00:55:03 2006//Trelease_0_8_2 +/lance.c/1.7/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/lsi53c895a.c/1.1/Tue May 30 01:48:12 2006//Trelease_0_8_2 +/m48t59.c/1.8/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/m48t59.h/1.5/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/mc146818rtc.c/1.6/Sun Aug 6 00:55:02 2006//Trelease_0_8_2 +/mips_r4k.c/1.18/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/ne2000.c/1.20/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/openpic.c/1.9/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/parallel.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/pc.c/1.60/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/pci.c/1.27/Sun Aug 6 01:03:50 2006//Trelease_0_8_2 +/pci_host.h/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/pckbd.c/1.15/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/pcnet.c/1.4/Fri Jul 14 09:40:02 2006//Trelease_0_8_2 +/pcspk.c/1.2/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/pflash_cfi02.c/1.2/Tue Jul 4 09:46:31 2006//Trelease_0_8_2 +/piix_pci.c/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/pl011.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/pl050.c/1.2/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/pl080.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/pl110.c/1.6/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/pl110_template.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/pl190.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/ppc.c/1.9/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/ppc_chrp.c/1.23/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/ppc_prep.c/1.27/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/prep_pci.c/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/ps2.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/rtl8139.c/1.4/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/sb16.c/1.22/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/scsi-disk.c/1.7/Sun Jun 4 11:39:07 2006//Trelease_0_8_2 +/serial.c/1.12/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/sh7750.c/1.2/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/sh7750_regnames.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/sh7750_regnames.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/sh7750_regs.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/shix.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/slavio_intctl.c/1.7/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/slavio_misc.c/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/slavio_serial.c/1.6/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/slavio_timer.c/1.4/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/smc91c111.c/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/sun4m.c/1.18/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/sun4u.c/1.11/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/tc58128.c/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/tcx.c/1.7/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/unin_pci.c/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/usb-hid.c/1.5/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/usb-hub.c/1.8/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/usb-msd.c/1.4/Wed Jul 19 18:06:15 2006//Trelease_0_8_2 +/usb-ohci.c/1.3/Thu May 25 23:37:07 2006//Trelease_0_8_2 +/usb-uhci.c/1.11/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/usb.c/1.8/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/usb.h/1.9/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/versatile_pci.c/1.1/Sat May 13 16:11:23 2006//Trelease_0_8_2 +/versatilepb.c/1.5/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/vga.c/1.44/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/vga_int.h/1.7/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 +/vga_template.h/1.13/Sun Aug 6 01:03:51 2006//Trelease_0_8_2 D diff --git a/tools/ioemu/hw/.CVS/Tag b/tools/ioemu/hw/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/hw/.CVS/Tag +++ b/tools/ioemu/hw/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/keymaps/.CVS/Entries b/tools/ioemu/keymaps/.CVS/Entries index db41d231e0..2a2b7d670d 100644 --- a/tools/ioemu/keymaps/.CVS/Entries +++ b/tools/ioemu/keymaps/.CVS/Entries @@ -1,36 +1,36 @@ -/ar/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/common/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/da/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/de/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/de-ch/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/en-gb/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/en-us/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/es/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/et/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/fi/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/fo/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/fr/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/fr-be/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/fr-ca/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/fr-ch/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/hr/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/hu/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/is/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/it/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/ja/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/lt/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/lv/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/mk/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/modifiers/1.2/Tue Mar 1 21:43:42 2005//Trelease_0_8_1 -/nl/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/nl-be/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/no/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/pl/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/pt/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/pt-br/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/ru/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/sl/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/sv/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/th/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 -/tr/1.1/Sun Dec 12 16:56:30 2004//Trelease_0_8_1 +/ar/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/common/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/da/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/de/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/de-ch/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/en-gb/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/en-us/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/es/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/et/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fi/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fo/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fr/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fr-be/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fr-ca/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/fr-ch/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/hr/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/hu/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/is/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/it/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/ja/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/lt/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/lv/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/mk/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/modifiers/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/nl/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/nl-be/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/no/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/pl/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/pt/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/pt-br/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/ru/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/sl/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/sv/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/th/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 +/tr/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2 D diff --git a/tools/ioemu/keymaps/.CVS/Tag b/tools/ioemu/keymaps/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/keymaps/.CVS/Tag +++ b/tools/ioemu/keymaps/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/pc-bios/.CVS/Entries b/tools/ioemu/pc-bios/.CVS/Entries index 75847c2486..0e8ec7ca13 100644 --- a/tools/ioemu/pc-bios/.CVS/Entries +++ b/tools/ioemu/pc-bios/.CVS/Entries @@ -1,15 +1,14 @@ -/Makefile/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/README/1.7/Thu May 25 12:38:52 2006//Trelease_0_8_1 -/bios.bin/1.13/Thu May 25 18:22:37 2006/-kb/Trelease_0_8_1 -/bios.diff/1.11/Thu May 25 18:22:37 2006//Trelease_0_8_1 -/linux_boot.S/1.1/Wed May 17 14:47:01 2006//Trelease_0_8_1 -/linux_boot.bin/1.1/Wed May 17 14:47:01 2006/-kb/Trelease_0_8_1 -/ohw.diff/1.2/Thu Jul 7 22:38:00 2005//Trelease_0_8_1 -/ppc_rom.bin/1.6/Thu May 25 12:39:00 2006/-kb/Trelease_0_8_1 -/proll.elf/1.5/Thu May 25 18:22:38 2006/-kb/Trelease_0_8_1 -/proll.patch/1.6/Thu May 25 18:22:38 2006//Trelease_0_8_1 -/vgabios-cirrus.bin/1.6/Thu May 25 18:22:38 2006/-kb/Trelease_0_8_1 -/vgabios.bin/1.5/Thu May 25 18:22:39 2006/-kb/Trelease_0_8_1 -/vgabios.diff/1.2/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/video.x/1.1/Sun Jul 3 14:00:51 2005/-kb/Trelease_0_8_1 +/Makefile/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/README/1.8/Sun Aug 6 01:03:54 2006//Trelease_0_8_2 +/bios.bin/1.14/Sun Aug 6 01:03:55 2006/-kb/Trelease_0_8_2 +/bios.diff/1.12/Sun Aug 6 01:03:55 2006//Trelease_0_8_2 +/linux_boot.S/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/linux_boot.bin/1.1/Sun Aug 6 01:03:55 2006/-kb/Trelease_0_8_2 +/ohw.diff/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2 +/openbios-sparc32/1.1/Wed Jun 14 12:36:32 2006/-kb/Trelease_0_8_2 +/ppc_rom.bin/1.6/Sun Aug 6 01:04:00 2006/-kb/Trelease_0_8_2 +/vgabios-cirrus.bin/1.8/Sun Aug 6 01:04:00 2006/-kb/Trelease_0_8_2 +/vgabios.bin/1.8/Sun Aug 6 01:04:00 2006/-kb/Trelease_0_8_2 +/vgabios.diff/1.5/Sun Aug 6 01:04:00 2006//Trelease_0_8_2 +/video.x/1.1/Sun Aug 6 01:04:00 2006/-kb/Trelease_0_8_2 D diff --git a/tools/ioemu/pc-bios/.CVS/Tag b/tools/ioemu/pc-bios/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/pc-bios/.CVS/Tag +++ b/tools/ioemu/pc-bios/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/target-i386/.CVS/Entries b/tools/ioemu/target-i386/.CVS/Entries index c230f3222b..e7b571fd99 100644 --- a/tools/ioemu/target-i386/.CVS/Entries +++ b/tools/ioemu/target-i386/.CVS/Entries @@ -1,13 +1,13 @@ -/cpu.h/1.36/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/exec.h/1.29/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/helper.c/1.65/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/helper2.c/1.41/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/op.c/1.44/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/opreg_template.h/1.3/Wed May 24 10:40:25 2006//Trelease_0_8_1 -/ops_mem.h/1.7/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/ops_sse.h/1.6/Tue Apr 26 20:38:17 2005//Trelease_0_8_1 -/ops_template.h/1.10/Wed May 24 10:40:25 2006//Trelease_0_8_1 -/ops_template_mem.h/1.6/Thu May 25 18:22:39 2006//Trelease_0_8_1 -/translate-copy.c/1.7/Wed May 24 10:40:25 2006//Trelease_0_8_1 -/translate.c/1.56/Thu May 25 18:22:39 2006//Trelease_0_8_1 +/cpu.h/1.36/Wed Jul 26 12:39:11 2006//Trelease_0_8_2 +/exec.h/1.30/Sun Aug 6 01:04:03 2006//Trelease_0_8_2 +/helper.c/1.69/Sun Aug 6 01:04:03 2006//Trelease_0_8_2 +/helper2.c/1.43/Sun Aug 6 01:04:03 2006//Trelease_0_8_2 +/op.c/1.45/Sun Aug 6 01:04:03 2006//Trelease_0_8_2 +/opreg_template.h/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/ops_mem.h/1.7/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/ops_sse.h/1.6/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/ops_template.h/1.10/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/ops_template_mem.h/1.6/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/translate-copy.c/1.7/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/translate.c/1.59/Sun Aug 6 01:04:03 2006//Trelease_0_8_2 D diff --git a/tools/ioemu/target-i386/.CVS/Tag b/tools/ioemu/target-i386/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/target-i386/.CVS/Tag +++ b/tools/ioemu/target-i386/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 diff --git a/tools/ioemu/tests/.CVS/Entries b/tools/ioemu/tests/.CVS/Entries index 50674cddfc..abafbef780 100644 --- a/tools/ioemu/tests/.CVS/Entries +++ b/tools/ioemu/tests/.CVS/Entries @@ -1,18 +1,18 @@ -/.cvsignore/1.4/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/Makefile/1.36/Thu May 25 18:22:40 2006//Trelease_0_8_1 -/hello-arm.c/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/hello-i386.c/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/linux-test.c/1.3/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/pi_10.com/1.1/Wed May 17 14:47:02 2006/-kb/Trelease_0_8_1 -/qruncom.c/1.4/Thu May 25 18:22:41 2006//Trelease_0_8_1 -/runcom.c/1.3/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/sha1.c/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/test-i386-code16.S/1.3/Wed May 24 10:40:26 2006//Trelease_0_8_1 -/test-i386-muldiv.h/1.2/Wed May 24 10:40:26 2006//Trelease_0_8_1 -/test-i386-shift.h/1.5/Thu May 25 18:22:41 2006//Trelease_0_8_1 -/test-i386-vm86.S/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/test-i386.c/1.49/Wed May 24 10:40:26 2006//Trelease_0_8_1 -/test-i386.h/1.2/Wed May 24 10:40:26 2006//Trelease_0_8_1 -/test_path.c/1.1/Wed May 17 14:47:02 2006//Trelease_0_8_1 -/testthread.c/1.2/Wed May 17 14:47:02 2006//Trelease_0_8_1 +/.cvsignore/1.4/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/Makefile/1.37/Sun Aug 6 01:04:06 2006//Trelease_0_8_2 +/hello-arm.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/hello-i386.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/linux-test.c/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/pi_10.com/1.1/Sun Aug 6 01:04:06 2006/-kb/Trelease_0_8_2 +/qruncom.c/1.4/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/runcom.c/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/sha1.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/test-i386-code16.S/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/test-i386-muldiv.h/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/test-i386-shift.h/1.5/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/test-i386-vm86.S/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/test-i386.c/1.52/Sun Aug 6 01:04:06 2006//Trelease_0_8_2 +/test-i386.h/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/test_path.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 +/testthread.c/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2 D diff --git a/tools/ioemu/tests/.CVS/Tag b/tools/ioemu/tests/.CVS/Tag index 31c251a4bf..bd48d406fa 100644 --- a/tools/ioemu/tests/.CVS/Tag +++ b/tools/ioemu/tests/.CVS/Tag @@ -1 +1 @@ -Nrelease_0_8_1 +Nrelease_0_8_2 From 93a961f49bcb4ed06f830e9232871eb1efea62ca Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Mon, 7 Aug 2006 18:27:27 +0100 Subject: [PATCH 110/111] [qemu] Update ioemu to qemu 0.8.2. Signed-off-by: Christian Limpach --- tools/ioemu/pc-bios/proll.patch | 4067 ------------------------------- 1 file changed, 4067 deletions(-) delete mode 100644 tools/ioemu/pc-bios/proll.patch diff --git a/tools/ioemu/pc-bios/proll.patch b/tools/ioemu/pc-bios/proll.patch deleted file mode 100644 index cc69519efb..0000000000 --- a/tools/ioemu/pc-bios/proll.patch +++ /dev/null @@ -1,4067 +0,0 @@ -diff -ruN proll_18.orig/Makefile proll-patch-15/Makefile ---- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 -+++ proll-patch-15/Makefile 2005-11-09 18:14:51.000000000 +0000 -@@ -4,6 +4,7 @@ - make -C krups-ser all - make -C espresso all - make -C espresso-ser all -+ make -C qemu all - - clean: - make -C mrcoffee clean -@@ -11,3 +12,4 @@ - make -C krups-ser clean - make -C espresso clean - make -C espresso-ser clean -+ make -C qemu clean -diff -ruN proll_18.orig/qemu/Makefile proll-patch-15/qemu/Makefile ---- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/Makefile 2005-08-14 10:25:06.000000000 +0000 -@@ -0,0 +1,123 @@ -+# -+# proll: -+# qemu/Makefile - make PROLL for QEMU -+# $Id: proll.patch,v 1.6 2005/11/11 00:24:57 bellard Exp $ -+# -+# Copyright 1999 Pete Zaitcev -+# This is Free Software is licensed under terms of GNU General Public License. -+# -+ -+CC = gcc -+ -+#CROSS = /usr/local/sparc/bin/sparc-sun-linux- -+CROSS = sparc-unknown-linux-gnu- -+ -+CROSSCC = $(CROSS)gcc -+CROSSLD = $(CROSS)ld -+CROSSNM = $(CROSS)nm -+ -+RM = /bin/rm -f -+ELFTOAOUT = elftoaout -+ -+# -+SRC = ../src -+ -+# Due to remapping algorithm PROLBASE should be algned on PMD. -+# We make PROLBASE a define instead of using _start because we -+# want to shift it to form a PGD entry. A relocatable label will not work. -+# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . -+PROLBASE = 0xffd00000 -+PROLRODATA = 0xffd08000 -+PROLDATA = 0xffd0b000 -+PROLSIZE = 240*1024 -+ -+# Linux -+# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. -+# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. -+# __ANSI__ is supposed to be on by default but it is not. -+CFLAGS = -O2 -W -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -Wa,-xarch=v8 -g -DQEMU -m32 -fno-builtin -+ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g -Wa,-xarch=v8 -Wa,-32 -+# Solaris or Linux/i386 cross compilation -+#CFLAGS = -Iinclude -O -+ -+LDFLAGS = -N -Ttext $(PROLBASE) --section-start .rodata=$(PROLRODATA) -Tdata $(PROLDATA) -Tbss $(PROLDATA) -+ -+ALL = proll.aout -+PROLLEXE = proll.elf -+ -+OBJS = head.o wuf.o wof.o main.o $(CONSOLE) \ -+ printf.o le.o system_qemu.o iommu.o \ -+ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o \ -+ vconsole.o hconsole.o rconsole.o vcons_zs.o esp.o -+ -+all: $(ALL) -+ -+$(PROLLEXE): $(OBJS) -+ $(CROSSLD) $(LDFLAGS) -o $(PROLLEXE) $(OBJS) -+ -+head.o: head.S $(SRC)/phys_jj.h \ -+ $(SRC)/asi.h $(SRC)/psr.h $(SRC)/crs.h -+ $(CROSSCC) $(ASFLAGS) -DPROLBASE=$(PROLBASE) -o $*.o -c $*.S -+ -+main.o: main.c $(SRC)/asi.h $(SRC)/pgtsrmmu.h $(SRC)/iommu.h \ -+ $(SRC)/phys_jj.h $(SRC)/vconsole.h $(SRC)/version.h $(SRC)/general.h \ -+ $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+openprom.o: openprom.c $(SRC)/openprom.h $(SRC)/general.h $(SRC)/romlib.h \ -+ $(SRC)/vconsole.h $(SRC)/system.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+ -+system_qemu.o: system_qemu.c $(SRC)/vconsole.h $(SRC)/pgtsrmmu.h \ -+ $(SRC)/timer.h $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/asi.h \ -+ $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h $(SRC)/crs.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+iommu.o: $(SRC)/iommu.c $(SRC)/pgtsrmmu.h $(SRC)/phys_jj.h $(SRC)/iommu.h \ -+ $(SRC)/vconsole.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/asi.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+vconsole.o: $(SRC)/vconsole.c $(SRC)/vconsole.h $(SRC)/hconsole.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+vcons_zs.o: $(SRC)/vcons_zs.c $(SRC)/vconsole.h $(SRC)/system.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+hconsole.o: $(SRC)/hconsole.c $(SRC)/hconsole.h $(SRC)/rconsole.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+rconsole.o: $(SRC)/rconsole.c $(SRC)/rconsole.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+printf.o: $(SRC)/printf.c -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+esp.o: $(SRC)/esp.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+tftp.o: $(SRC)/tftp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/tftp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+udp.o: $(SRC)/udp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+packet.o: $(SRC)/packet.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+sched_4m.o: $(SRC)/sched_4m.c $(SRC)/system.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+bootp.o: $(SRC)/bootp.c $(SRC)/general.h $(SRC)/net.h \ -+ $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/bootp.h -+ $(CROSSCC) $(CFLAGS) -DNOBPEXT=1 -c $(SRC)/$*.c -+ -+wuf.o: $(SRC)/wuf.S -+ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S -+wof.o: $(SRC)/wof.S -+ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S -+ -+#genlab.o: genlab.c -+# $(CC) -c $*.c -+# -+#genlab: genlab.o -+# $(CC) -o genlab genlab.o -+ -+clean: -+ $(RM) $(OBJS) -+ $(RM) $(PROLLEXE) proll.aout -+ -+proll.aout: $(PROLLEXE) -+ $(ELFTOAOUT) -o proll.aout $(PROLLEXE) -diff -ruN proll_18.orig/qemu/head.S proll-patch-15/qemu/head.S ---- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/head.S 2005-07-12 22:24:17.000000000 +0000 -@@ -0,0 +1,543 @@ -+/** -+ ** Standalone startup code for Linux PROM emulator. -+ ** Copyright 1999 Pete A. Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+/* -+ * $Id: proll.patch,v 1.6 2005/11/11 00:24:57 bellard Exp $ -+ */ -+ -+#include -+#include -+#include -+/* #include */ /* Trap entries. Do not use. */ -+#include "phys_jj.h" -+ -+#define C_LABEL(name) name -+#define REGWIN_SZ 0x40 -+ -+#define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ -+ -+ /* 22 is 24-2, (va)>>(SRMMU_PGDIR_SHIFT-PTESIZESHFT) */ -+#define VATOPGDOFF(va) (((va)>>22)&0x3FC) -+#define VATOPMDOFF(va) (((va)>>16)&0xFC) -+ -+#define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ -+ -+/* Here are some trap goodies */ -+ -+#if 0 -+/* Generic trap entry. */ -+#define TRAP_ENTRY(type, label) \ -+ rd %psr, %l0; b label; rd %wim, %l3; nop; -+#endif -+ -+/* Data/text faults. */ -+#define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 1, %l7; -+#define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 0, %l7; -+ -+#if 0 -+/* This is for traps we should NEVER get. */ -+#define BAD_TRAP(num) \ -+ rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3; -+ -+/* This is for traps when we want just skip the instruction which caused it */ -+#define SKIP_TRAP(type, name) \ -+ jmpl %l2, %g0; rett %l2 + 4; nop; nop; -+ -+/* Notice that for the system calls we pull a trick. We load up a -+ * different pointer to the system call vector table in %l7, but call -+ * the same generic system call low-level entry point. The trap table -+ * entry sequences are also HyperSparc pipeline friendly ;-) -+ */ -+ -+/* Software trap for Linux system calls. */ -+#define LINUX_SYSCALL_TRAP \ -+ sethi %hi(C_LABEL(sys_call_table)), %l7; \ -+ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ -+ b linux_sparc_syscall; \ -+ rd %psr, %l0; -+ -+/* Software trap for SunOS4.1.x system calls. */ -+#define SUNOS_SYSCALL_TRAP \ -+ rd %psr, %l0; \ -+ sethi %hi(C_LABEL(sunos_sys_table)), %l7; \ -+ b linux_sparc_syscall; \ -+ or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; -+ -+/* Software trap for Slowaris system calls. */ -+#define SOLARIS_SYSCALL_TRAP \ -+ b solaris_syscall; \ -+ rd %psr, %l0; \ -+ nop; \ -+ nop; -+ -+#define INDIRECT_SOLARIS_SYSCALL(x) \ -+ mov x, %g1; \ -+ b solaris_syscall; \ -+ rd %psr, %l0; \ -+ nop; -+ -+#define BREAKPOINT_TRAP \ -+ b breakpoint_trap; \ -+ rd %psr,%l0; \ -+ nop; \ -+ nop; -+ -+/* Software trap for Sparc-netbsd system calls. */ -+#define NETBSD_SYSCALL_TRAP \ -+ sethi %hi(C_LABEL(sys_call_table)), %l7; \ -+ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ -+ b bsd_syscall; \ -+ rd %psr, %l0; -+ -+/* The Get Condition Codes software trap for userland. */ -+#define GETCC_TRAP \ -+ b getcc_trap_handler; mov %psr, %l0; nop; nop; -+ -+/* The Set Condition Codes software trap for userland. */ -+#define SETCC_TRAP \ -+ b setcc_trap_handler; mov %psr, %l0; nop; nop; -+ -+/* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and -+ * gets handled with another macro. -+ */ -+#define TRAP_ENTRY_INTERRUPT(int_level) \ -+ mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; -+ -+/* NMI's (Non Maskable Interrupts) are special, you can't keep them -+ * from coming in, and basically if you get one, the shows over. ;( -+ * On the sun4c they are usually asynchronous memory errors, on the -+ * the sun4m they could be either due to mem errors or a software -+ * initiated interrupt from the prom/kern on an SMP box saying "I -+ * command you to do CPU tricks, read your mailbox for more info." -+ */ -+#define NMI_TRAP \ -+ rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop; -+ -+#endif -+ -+/* Window overflows/underflows are special and we need to try to be as -+ * efficient as possible here.... -+ */ -+#define WINDOW_SPILL \ -+ rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop; -+ -+#define WINDOW_FILL \ -+ rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop; -+ -+#define STUB_TRAP ba stub_trap; nop; nop; nop; -+ -+#define TRAP_ENTRY(a,b) STUB_TRAP -+#define SKIP_TRAP(a,b) STUB_TRAP -+#define SUNOS_SYSCALL_TRAP STUB_TRAP -+#define SOLARIS_SYSCALL_TRAP STUB_TRAP -+#define NETBSD_SYSCALL_TRAP STUB_TRAP -+#define LINUX_SYSCALL_TRAP STUB_TRAP -+#define BREAKPOINT_TRAP STUB_TRAP -+#define NMI_TRAP STUB_TRAP -+#define GETCC_TRAP STUB_TRAP -+#define SETCC_TRAP STUB_TRAP -+#define BAD_TRAP(n) STUB_TRAP -+#define TRAP_ENTRY_INTERRUPT(i) STUB_TRAP -+#define INDIRECT_SOLARIS_SYSCALL(i) STUB_TRAP -+ -+ .section ".text" -+ .globl start, _start -+_start: -+start: -+ .globl spill_window_entry, fill_window_entry -+ -+#define EXPORT_TRAP(trap) \ -+ .globl trap; \ -+ .type trap,function; \ -+ .size trap, 16 -+ -+EXPORT_TRAP(t_zero) -+EXPORT_TRAP(t_wovf) -+EXPORT_TRAP(t_wunf) -+EXPORT_TRAP(t_irq1) -+EXPORT_TRAP(t_irq2) -+EXPORT_TRAP(t_irq3) -+EXPORT_TRAP(t_irq4) -+EXPORT_TRAP(t_irq5) -+EXPORT_TRAP(t_irq6) -+EXPORT_TRAP(t_irq7) -+EXPORT_TRAP(t_irq8) -+EXPORT_TRAP(t_irq9) -+EXPORT_TRAP(t_irq10) -+EXPORT_TRAP(t_irq11) -+EXPORT_TRAP(t_irq12) -+EXPORT_TRAP(t_irq13) -+EXPORT_TRAP(t_irq14) -+EXPORT_TRAP(t_irq15) -+ -+C_LABEL(trapbase): -+t_zero: b goprol; nop; nop; nop; -+t_tflt: SRMMU_TFAULT /* Inst. Access Exception */ -+t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ -+t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ -+t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ -+t_wovf: WINDOW_SPILL /* Window Overflow */ -+t_wunf: WINDOW_FILL /* Window Underflow */ -+t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ -+t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ -+t_dflt: SRMMU_DFAULT /* Data Miss Exception */ -+t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ -+t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ -+t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) -+t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ -+t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ -+t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ -+t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ -+t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ -+t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ -+t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ -+t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ -+t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ -+t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ -+t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ -+t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ -+t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ -+t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ -+t_nmi: NMI_TRAP /* Level 15 (NMI) */ -+t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ -+t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ -+t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) -+t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ -+t_uflsh:SKIP_TRAP(0x25, unimp_flush) /* Unimplemented FLUSH inst. */ -+t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) -+t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ -+t_dacce:SRMMU_DFAULT /* Data Access Error */ -+t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ -+t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ -+t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ -+t_bad2d: BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) -+ BAD_TRAP(0x30) BAD_TRAP(0x31) BAD_TRAP(0x32) BAD_TRAP(0x33) -+ BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) BAD_TRAP(0x37) -+ BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) -+t_iaccm:BAD_TRAP(0x3c) /* Instr Access MMU-Miss */ -+ BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) -+ BAD_TRAP(0x40) BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) -+ BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) BAD_TRAP(0x47) -+ BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) -+ BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) -+ BAD_TRAP(0x50) BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) -+ BAD_TRAP(0x54) BAD_TRAP(0x55) BAD_TRAP(0x56) BAD_TRAP(0x57) -+ BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) BAD_TRAP(0x5b) -+ BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) -+ BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) -+ BAD_TRAP(0x64) BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) -+ BAD_TRAP(0x68) BAD_TRAP(0x69) BAD_TRAP(0x6a) BAD_TRAP(0x6b) -+ BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) BAD_TRAP(0x6f) -+ BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) -+ BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) -+ BAD_TRAP(0x78) BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) -+ BAD_TRAP(0x7c) BAD_TRAP(0x7d) BAD_TRAP(0x7e) BAD_TRAP(0x7f) -+t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ -+t_sbkpt:BREAKPOINT_TRAP /* Software Breakpoint/KGDB */ -+t_divz: BAD_TRAP(0x82) /* Divide by zero trap */ -+t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ -+t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ -+t_rchk: BAD_TRAP(0x85) /* Range Check */ -+t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ -+t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ -+t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ -+t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ -+t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) -+ BAD_TRAP(0x8e) BAD_TRAP(0x8f) -+t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ -+t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) -+ BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) -+ BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) -+t_getcc:GETCC_TRAP /* Get Condition Codes */ -+t_setcc:SETCC_TRAP /* Set Condition Codes */ -+t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) -+ BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) -+t_slowi:INDIRECT_SOLARIS_SYSCALL(156) -+ BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) -+ BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) -+ BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) -+ BAD_TRAP(0xb4) BAD_TRAP(0xb5) BAD_TRAP(0xb6) BAD_TRAP(0xb7) -+ BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) BAD_TRAP(0xbb) -+ BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) -+t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) -+ BAD_TRAP(0xc4) BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) -+ BAD_TRAP(0xc8) BAD_TRAP(0xc9) BAD_TRAP(0xca) BAD_TRAP(0xcb) -+ BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) BAD_TRAP(0xcf) -+ BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) -+t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) -+ BAD_TRAP(0xd8) BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) -+ BAD_TRAP(0xdc) BAD_TRAP(0xdd) BAD_TRAP(0xde) BAD_TRAP(0xdf) -+ BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) BAD_TRAP(0xe3) -+ BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) -+t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) -+ BAD_TRAP(0xec) BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) -+ BAD_TRAP(0xf0) BAD_TRAP(0xf1) BAD_TRAP(0xf2) BAD_TRAP(0xf3) -+ BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) BAD_TRAP(0xf7) -+ BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) -+t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd) -+dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ -+dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ -+ -+stub_trap: -+ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ -+ set 0x00ffffff, %g4 -+ sta %g4, [%g5] ASI_M_BYPASS -+1: ba 1b; nop -+ -+ .section ".bss" -+ .align 8 -+bss_start: -+ .align 0x1000 ! PAGE_SIZE -+ .globl C_LABEL(bootup_user_stack) -+ .type bootup_user_stack,#object -+ .size bootup_user_stack,0x2000 -+C_LABEL(bootup_user_stack): .skip 0x2000 -+ -+ .section ".text" -+ .register %g2, #scratch -+ .register %g3, #scratch -+ .register %g6, #scratch -+ .register %g7, #scratch -+ -+goprol: -+ ! %g1 contains end of memory -+ set PHYS_JJ_EEPROM + 0x30, %g1 -+ lda [%g1] ASI_M_BYPASS, %g1 -+ ! map PROLDATA to PROLBASE+PROLSIZE to end of ram -+ set PROLSIZE+0x1000-PROLDATA+PROLBASE, %g2 ! add 0x1000 for temp tables -+ sub %g1, %g2, %g2 ! start of private memory -+ srl %g2, 0x4, %g7 ! ctx table at s+0x0 -+ add %g2, 0x400, %g3 ! l1 table at s+0x400 -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x400, %g2 ! s+0x400 -+ add %g2, 0x800, %g3 ! l2 table for ram (00xxxxxx) at s+0x800 -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x500, %g3 ! l2 table for rom (ffxxxxxx) at s+0x900 -+ add %g2, 0x3fc, %g2 ! s+0x7fc -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x4, %g2 ! s+0x800 -+ set ((7 << 2) | 2), %g3 ! 7 = U: --- S: RWX (main memory) -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x200, %g3 ! l3 table for rom at s+0xa00 -+ add %g2, 0x1d0, %g2 ! s+0x9d0 -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x30, %g2 ! s+0xa00 -+ -+ set PROLBASE, %g3 -+ set 0x1000, %g5 -+ set (PROLDATA-PROLBASE)/0x1000, %g6 ! # of .text pages -+1: srl %g3, 0x4, %g4 -+ or %g4, ((7 << 2) | 2), %g4 ! 4 = U: --X S: --X (rom, execute only) -+ sta %g4, [%g2] ASI_M_BYPASS -+ add %g2, 4, %g2 -+ add %g3, %g5, %g3 -+ deccc %g6 -+ bne 1b -+ nop -+#if 0 -+ set (PROLDATA-PROLRODATA)/0x1000, %g6 ! # of .rodata pages -+1: srl %g3, 0x4, %g4 -+ or %g4, ((0 << 2) | 2), %g4 ! 0 = U: R-- S: R-- (rom, read only) -+ sta %g4, [%g2] ASI_M_BYPASS -+ add %g2, 4, %g2 -+ add %g3, %g5, %g3 -+ deccc %g6 -+ bne 1b -+ nop -+#endif -+ set (PROLBASE+PROLSIZE-PROLDATA)/0x1000, %g6 ! # of .bss pages -+ set 0x1000, %g4 -+ sll %g7, 0x4, %g3 -+ add %g4, %g3, %g3 -+1: srl %g3, 0x4, %g4 -+ or %g4, ((7 << 2) | 2), %g4 ! 5 = U: R-- S: RW- (data area, read/write) -+ sta %g4, [%g2] ASI_M_BYPASS -+ add %g2, 4, %g2 -+ add %g3, %g5, %g3 -+ deccc %g6 -+ bne 1b -+ nop -+ -+ mov %g1, %g3 -+ -+ set AC_M_CTPR, %g2 -+ sta %g7, [%g2] ASI_M_MMUREGS ! set ctx table ptr -+ set 1, %g1 -+ sta %g1, [%g0] ASI_M_MMUREGS ! enable mmu -+ -+ /* -+ * The code which enables traps is a simplified version of -+ * kernel head.S. -+ * -+ * We know number of windows as 8 so we do not calculate them. -+ * The deadwood is here for any case. -+ */ -+ -+ /* Turn on Supervisor, EnableFloating, and all the PIL bits. -+ * Also puts us in register window zero with traps off. -+ */ -+ set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 -+ wr %g2, 0x0, %psr -+ WRITE_PAUSE -+ -+ /* I want a kernel stack NOW! */ -+ set C_LABEL(bootup_user_stack), %g1 -+ set (0x2000 - REGWIN_SZ), %g2 -+ add %g1, %g2, %sp -+ mov 0, %fp /* And for good luck */ -+ -+ /* Zero out our BSS section. */ -+ set C_LABEL(bss_start) , %o0 ! First address of BSS -+ set C_LABEL(end) , %o1 ! Last address of BSS -+ ba 2f -+ nop -+1: -+ st %g0, [%o0] -+2: -+ subcc %o0, %o1, %g0 -+ bl 1b -+ add %o0, 0x4, %o0 -+ -+ mov 2, %g1 -+ wr %g1, 0x0, %wim ! make window 1 invalid -+ WRITE_PAUSE -+ -+#if 0 -+ wr %g0, 0x0, %wim -+ WRITE_PAUSE -+ save -+ rd %psr, %g3 -+ restore -+ and %g3, PSR_CWP, %g3 -+ add %g3, 0x1, %g3 -+#else -+ or %g0, 8, %g3 -+#endif -+ -+#if 0 -+ sethi %hi( C_LABEL(cputyp) ), %o0 -+ st %g7, [%o0 + %lo( C_LABEL(cputyp) )] -+ -+ sethi %hi( C_LABEL(nwindows) ), %g4 -+ st %g3, [%g4 + %lo( C_LABEL(nwindows) )] -+ -+ sub %g3, 0x1, %g3 -+ sethi %hi( C_LABEL(nwindowsm1) ), %g4 -+ st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )] -+#endif -+ -+ /* Here we go, start using Linux's trap table... */ -+ set C_LABEL(trapbase), %g3 -+ wr %g3, 0x0, %tbr -+ WRITE_PAUSE -+ -+ /* Finally, turn on traps so that we can call c-code. */ -+ rd %psr, %g3 -+ wr %g3, 0x0, %psr -+ WRITE_PAUSE -+ -+ wr %g3, PSR_ET, %psr -+ WRITE_PAUSE -+ -+ .globl prolmain -+ call C_LABEL(prolmain) -+ nop -+ -+3: -+ b 3b -+ nop -+ -+/* -+ * Memory access trap handler -+ * %l0 program %psr from trap table entry -+ * %l1 program %pc from hardware -+ * %l2 program %npc from hardware -+ * %l3 program %wim from trap table entry -+ * %l4 -+ * %l5 -+ * %l6 -+ * %l7 text flag from trap table entry -+ */ -+ -+ .section ".text" -+ .globl srmmu_fault -+C_LABEL(srmmu_fault): -+ -+ set AC_M_SFAR, %l6 -+ set AC_M_SFSR, %l5 -+ lda [%l6] ASI_M_MMUREGS, %l6 -+ lda [%l5] ASI_M_MMUREGS, %l5 -+ -+ set ignore_fault, %l5 -+ ld [%l5], %l5 -+ subcc %l5, %g0, %g0 /* NULL pointer trap faults always */ -+ be 3f -+ nop -+ subcc %l5, %l6, %g0 -+ be 2f -+ nop -+3: -+ -+ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ -+ set 0x00ffffff, %g4 -+ sta %g4, [%g5] ASI_M_BYPASS -+ add %g5, 8, %g5 /* On right side */ -+ sta %g4, [%g5] ASI_M_BYPASS -+1: ba 1b; nop -+ -+2: -+ set C_LABEL(fault_ignored), %l5 -+ mov 1, %l6 -+ st %l6, [%l5] -+ -+ /* -+ * Skip the faulting instruction. -+ * I think it works when next instruction is a branch even. -+ */ -+ or %l2, 0, %l1 -+ add %l2, 4, %l2 -+ -+ wr %l0, 0, %psr -+ WRITE_PAUSE -+ jmp %l1 -+ rett %l2 -+ -+/* -+ * Slow external versions of st_bypass and ld_bypass. -+ * rconsole.c uses inlines. We call these in places which are not speed -+ * critical, to avoid compiler bugs. -+ */ -+ .globl C_LABEL(st_bypass) -+C_LABEL(st_bypass): -+ retl -+ sta %o1, [%o0] ASI_M_BYPASS -+ .globl C_LABEL(ld_bypass) -+C_LABEL(ld_bypass): -+ retl -+ lda [%o0] ASI_M_BYPASS, %o0 -+ .globl C_LABEL(sth_bypass) -+C_LABEL(sth_bypass): -+ retl -+ stha %o1, [%o0] ASI_M_BYPASS -+ .globl C_LABEL(ldh_bypass) -+C_LABEL(ldh_bypass): -+ retl -+ lduha [%o0] ASI_M_BYPASS, %o0 -+ .globl C_LABEL(stb_bypass) -+C_LABEL(stb_bypass): -+ retl -+ stba %o1, [%o0] ASI_M_BYPASS -+ .globl C_LABEL(ldb_bypass) -+C_LABEL(ldb_bypass): -+ retl -+ lduba [%o0] ASI_M_BYPASS, %o0 -diff -ruN proll_18.orig/qemu/main.c proll-patch-15/qemu/main.c ---- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/main.c 2005-08-14 10:07:48.000000000 +0000 -@@ -0,0 +1,185 @@ -+/** -+ ** Proll (PROM replacement) -+ ** Copyright 1999 Pete Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+#include -+ -+// #include -+#include -+#include "pgtsrmmu.h" -+#include "iommu.h" /* Typical SBus IOMMU for sun4m */ -+#include "phys_jj.h" -+#include "vconsole.h" -+#include "version.h" -+#include /* __P() */ -+#include /* init_net() */ -+#include /* we are a provider for part of this. */ -+#include /* myipaddr */ -+#include -+#include /* our own prototypes */ -+ -+void *init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, const char *cmdline, char boot_device, int nographic); -+int vcon_zs_init(struct vconterm *t, unsigned int a0); -+int vcon_zs_write(struct vconterm *t, char *data, int leng); -+int vcon_zs_getch(struct vconterm *t); -+void esp_probe(); -+int esp_boot(int unit); -+static void init_idprom(void); -+ -+struct vconterm dp0; -+struct mem cmem; /* Current memory, virtual */ -+struct mem cio; /* Current I/O space */ -+struct phym pmem; /* Current phys. mem. */ -+struct iommu ciommu; /* Our IOMMU on sun4m */ -+ -+static struct { -+ const char id[16]; -+ unsigned int version; -+ char pad1[0x1c]; // Pad to 0x30 -+ unsigned int ram_size; -+ char boot_device; -+ unsigned int load_addr, kernel_size; -+ unsigned int cmdline, cmdline_len; -+ char pad2[0x0c]; // Pad to 0x54 -+ unsigned short width, height, depth; -+} *hw_idprom; -+ -+int ignore_fault, fault_ignored; -+void *printk_fn, *getch_fn; -+unsigned int q_height, q_width; -+ -+/* -+ */ -+void prolmain() -+{ -+ static char fname[14]; -+ static struct banks bb; -+ unsigned int hiphybas; -+ const void *romvec; -+ unsigned int ram_size; -+ char nographic, bootdev; -+ -+ nographic = ldb_bypass(PHYS_JJ_EEPROM + 0x2F); -+ if (!nographic) { -+ q_width = ldh_bypass(PHYS_JJ_EEPROM + 0x54); -+ q_height = ldh_bypass(PHYS_JJ_EEPROM + 0x56); -+ vcon_init(&dp0, PHYS_JJ_TCX_FB); -+ printk_fn = vcon_write; -+ getch_fn = vcon_getch; -+ } -+ else { -+ vcon_zs_init(&dp0, 0x71100004); -+ printk_fn = vcon_zs_write; -+ getch_fn = vcon_zs_getch; -+ } -+ -+ -+ printk("PROLL %s QEMU\n", PROLL_VERSION_STRING); -+ ram_size = ld_bypass(PHYS_JJ_EEPROM + 0x30); -+ printk("%d MB total\n", ram_size/(1024*1024)); -+ -+ bb.nbanks = 1; -+ bb.bankv[0].start = 0; -+ bb.bankv[0].length = ram_size; -+ -+ hiphybas = ram_size - PROLSIZE; -+ -+ mem_init(&cmem, (char *) &_end, (char *)(PROLBASE+PROLSIZE)); -+ makepages(&pmem, hiphybas); -+ init_mmu_swift((unsigned int)pmem.pctp - PROLBASE + hiphybas); -+ -+ mem_init(&cio, (char *)(PROLBASE+PROLSIZE), -+ (char *)(PROLBASE+PROLSIZE+IOMAPSIZE)); -+ -+ iommu_init(&ciommu, hiphybas); -+ -+ /* -+ */ -+ init_idprom(); -+ printk("NVRAM: id %s version %d\n", hw_idprom->id, hw_idprom->version); -+ if (!nographic) -+ printk("Prom console: TCX %dx%d\n", q_width, q_height); -+ else -+ printk("Prom console: serial\n"); -+ sched_init(); -+ le_probe(); -+ init_net(); -+ esp_probe(); -+ -+ bootdev = hw_idprom->boot_device; -+ printk("Boot device: %c\n", bootdev); -+ if (hw_idprom->kernel_size > 0) { -+ printk("Kernel already loaded\n"); -+ } else if (bootdev == 'n') { -+ if (bootp() != 0) fatal(); -+ /* -+ * boot_rec.bp_file cannot be used because system PROM -+ * uses it to locate ourselves. If we load from boot_rec.bp_file, -+ * we will loop reloading PROLL over and over again. -+ * Thus we use traditional PROLL scheme HEXIPADDR.PROL (single L). -+ */ -+ xtoa(myipaddr, fname, 8); -+ fname[9] = '.'; -+ fname[10] = 'P'; -+ fname[11] = 'R'; -+ fname[12] = 'O'; -+ fname[13] = 'L'; -+ fname[14] = 0; -+ -+ if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); -+ } else if (bootdev == 'c') { -+ if (esp_boot(0) != 0) fatal(); -+ } else if (bootdev == 'd') { -+ if (esp_boot(2) != 0) fatal(); -+ } -+ -+ romvec = init_openprom_qemu(bb.nbanks, bb.bankv, hiphybas, -+ (void *)hw_idprom->cmdline, hw_idprom->boot_device, nographic); -+ -+ printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", -+ PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, -+ (int)cio.start, (int)cio.curp); -+ -+ { -+ void (*entry)(const void *, int, int, int, int) = (void *) hw_idprom->load_addr; -+ printk("Kernel loaded at 0x%x, size %dK, command line = '%s'\n", -+ *entry, hw_idprom->kernel_size/1024, hw_idprom->cmdline); -+ entry(romvec, 0, 0, 0, 0); -+ } -+ -+ mem_fini(&cmem); -+ vcon_fini(&dp0); -+} -+ -+/* -+ * dvma_alloc over iommu_alloc. -+ */ -+void *dvma_alloc(int size, unsigned int *pphys) -+{ -+ return iommu_alloc(&ciommu, size, pphys); -+} -+ -+/* -+ */ -+void udelay(__attribute__((unused)) unsigned long usecs) -+{ -+ // Qemu hardware is perfect and does not need any delays! -+} -+ -+static void init_idprom() -+{ -+ void *va_prom; -+ -+ if ((va_prom = map_io(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE)) == NULL) { -+ printk("init_idprom: cannot map eeprom\n"); -+ fatal(); -+ } -+ bcopy(va_prom + PHYS_JJ_IDPROM_OFF, idprom, IDPROM_SIZE); -+ /* -+ * hw_idprom is not used anywhere. -+ * It's just as we hate to leave hanging pointers (I/O page here). -+ */ -+ hw_idprom = va_prom; -+} -+ -diff -ruN proll_18.orig/qemu/openprom.c proll-patch-15/qemu/openprom.c ---- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/openprom.c 2005-11-07 20:11:04.000000000 +0000 -@@ -0,0 +1,910 @@ -+/* -+ * PROM interface support -+ * Copyright 1996 The Australian National University. -+ * Copyright 1996 Fujitsu Laboratories Limited -+ * Copyright 1999 Pete A. Zaitcev -+ * This software may be distributed under the terms of the Gnu -+ * Public License version 2 or later -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "phys_jj.h" -+ -+//#define DEBUG_OBP -+ -+#define PAGE_SIZE 4096 -+ -+struct property { -+ const char *name; -+ const char *value; -+ int length; -+}; -+ -+struct node { -+ const struct property *properties; -+ /* short */ const int sibling; -+ /* short */ const int child; -+}; -+ -+static int obp_nextnode(int node); -+static int obp_child(int node); -+static int obp_proplen(int node, char *name); -+static int obp_getprop(int node, char *name, char *val); -+static int obp_setprop(int node, char *name, char *val, int len); -+static const char *obp_nextprop(int node, char *name); -+ -+static char obp_idprom[IDPROM_SIZE]; -+static const struct property null_properties = { NULL, NULL, -1 }; -+static const int prop_true = -1; -+ -+static struct property propv_root[7]; -+ -+static const struct property propv_root_templ[] = { -+ {"name", "SUNW,SparcStation-5", sizeof("SUNW,SparcStation-5") }, -+ {"idprom", obp_idprom, IDPROM_SIZE}, -+ {"banner-name", "SparcStation", sizeof("SparcStation")}, -+ {"compatible", "sun4m", 6}, -+}; -+ -+static const int prop_iommu_reg[] = { -+ 0x0, 0x10000000, 0x00000300, -+}; -+static const struct property propv_iommu[] = { -+ {"name", "iommu", sizeof("iommu")}, -+ {"reg", (char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_sbus_ranges[] = { -+ 0x0, 0x0, 0x0, 0x30000000, 0x10000000, -+ 0x1, 0x0, 0x0, 0x40000000, 0x10000000, -+ 0x2, 0x0, 0x0, 0x50000000, 0x10000000, -+ 0x3, 0x0, 0x0, 0x60000000, 0x10000000, -+ 0x4, 0x0, 0x0, 0x70000000, 0x10000000, -+}; -+static const struct property propv_sbus[] = { -+ {"name", "sbus", 5}, -+ {"ranges", (char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)}, -+ {"device_type", "hierarchical", sizeof("hierarchical") }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_tcx_regs[] = { -+ 0x2, 0x00800000, 0x00100000, -+ 0x2, 0x02000000, 0x00000001, -+ 0x2, 0x04000000, 0x00800000, -+ 0x2, 0x06000000, 0x00800000, -+ 0x2, 0x0a000000, 0x00000001, -+ 0x2, 0x0c000000, 0x00000001, -+ 0x2, 0x0e000000, 0x00000001, -+ 0x2, 0x00700000, 0x00001000, -+ 0x2, 0x00200000, 0x00000004, -+ 0x2, 0x00300000, 0x0000081c, -+ 0x2, 0x00000000, 0x00010000, -+ 0x2, 0x00240000, 0x00000004, -+ 0x2, 0x00280000, 0x00000001, -+}; -+ -+#if 1 /* Zaitcev */ -+static const int pixfreq = 0x03dfd240; -+static const int hbporch = 0xa0; -+static const int vfreq = 0x3c; -+#endif -+#if 0 /* Kevin Boone - 70Hz refresh */ -+static const int pixfreq = 0x047868C0; -+static const int hbporch = 0x90; -+static const int vfreq = 0x46; -+#endif -+ -+static const int vbporch = 0x1d; -+static const int vsync = 0x6; -+static const int hsync = 0x88; -+static const int vfporch = 0x3; -+static const int hfporch = 0x18; -+static const int height = 0x300; -+static const int width = 0x400; -+static const int linebytes = 0x400; -+static const int depth = 24; -+static const int tcx_intr[] = { 5, 0 }; -+static const int tcx_interrupts = 5; -+static const struct property propv_sbus_tcx[] = { -+ {"name", "SUNW,tcx", sizeof("SUNW,tcx")}, -+ {"vbporch", (char*)&vbporch, sizeof(int)}, -+ {"hbporch", (char*)&hbporch, sizeof(int)}, -+ {"vsync", (char*)&vsync, sizeof(int)}, -+ {"hsync", (char*)&hsync, sizeof(int)}, -+ {"vfporch", (char*)&vfporch, sizeof(int)}, -+ {"hfporch", (char*)&hfporch, sizeof(int)}, -+ {"pixfreq", (char*)&pixfreq, sizeof(int)}, -+ {"vfreq", (char*)&vfreq, sizeof(int)}, -+ {"height", (char*)&height, sizeof(int)}, -+ {"width", (char*)&width, sizeof(int)}, -+ {"linebytes", (char*)&linebytes, sizeof(int)}, -+ {"depth", (char*)&depth, sizeof(int)}, -+ {"reg", (char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)}, -+ {"tcx-8-bit", 0, -1}, -+ {"intr", (char*)&tcx_intr[0], sizeof(tcx_intr)}, -+ {"interrupts", (char*)&tcx_interrupts, sizeof(tcx_interrupts)}, -+ {"device_type", "display", sizeof("display")}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_cs4231_reg[] = { -+ 0x3, 0x0C000000, 0x00000040 -+}; -+static const int cs4231_interrupts = 5; -+static const int cs4231_intr[] = { 5, 0 }; -+ -+static const struct property propv_sbus_cs4231[] = { -+ {"name", "SUNW,CS4231", sizeof("SUNW,CS4231") }, -+ {"intr", (char*)&cs4231_intr[0], sizeof(cs4231_intr) }, -+ {"interrupts", (char*)&cs4231_interrupts, sizeof(cs4231_interrupts) }, -+ {"reg", (char*)&prop_cs4231_reg[0], sizeof(prop_cs4231_reg) }, -+ {"device_type", "serial", sizeof("serial") }, -+ {"alias", "audio", sizeof("audio") }, -+ {NULL, NULL, -1} -+}; -+ -+static const int cpu_nctx = NCTX_SWIFT; -+static const int cpu_cache_line_size = 0x20; -+static const int cpu_cache_nlines = 0x200; -+static const struct property propv_cpu[] = { -+ {"name", "STP1012PGA", sizeof("STP1012PGA") }, -+ {"device_type", "cpu", 4 }, -+ {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, -+ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, -+ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_obio_ranges[] = { -+ 0x0, 0x0, 0x0, 0x71000000, 0x01000000, -+}; -+static const struct property propv_obio[] = { -+ {"name", "obio", 5 }, -+ {"ranges", (char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) }, -+ {"device_type", "hierarchical", sizeof("hierarchical") }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_auxio_reg[] = { -+ 0x0, 0x00900000, 0x00000001, -+}; -+static const struct property propv_obio_auxio[] = { -+ {"name", "auxio", sizeof("auxio") }, -+ {"reg", (char*)&prop_auxio_reg[0], sizeof(prop_auxio_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_int_reg[] = { -+ 0x0, 0x00e00000, 0x00000010, -+ 0x0, 0x00e10000, 0x00000010, -+}; -+static const struct property propv_obio_int[] = { -+ {"name", "interrupt", sizeof("interrupt")}, -+ {"reg", (char*)&prop_int_reg[0], sizeof(prop_int_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_cnt_reg[] = { -+ 0x0, 0x00d00000, 0x00000010, -+ 0x0, 0x00d10000, 0x00000010, -+}; -+static const struct property propv_obio_cnt[] = { -+ {"name", "counter", sizeof("counter")}, -+ {"reg", (char*)&prop_cnt_reg[0], sizeof(prop_cnt_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_eeprom_reg[] = { -+ 0x0, 0x00200000, 0x00002000, -+}; -+static const struct property propv_obio_eep[] = { -+ {"name", "eeprom", sizeof("eeprom")}, -+ {"reg", (char*)&prop_eeprom_reg[0], sizeof(prop_eeprom_reg) }, -+ {"model", "mk48t08", sizeof("mk48t08")}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_su_reg[] = { -+ 0x0, 0x003002f8, 0x00000008, -+}; -+static const struct property propv_obio_su[] = { -+ {"name", "su", sizeof("su")}, -+ {"reg", (char*)&prop_su_reg[0], sizeof(prop_su_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_zs_intr[] = { 0x2c, 0x0 }; -+static const int prop_zs_reg[] = { -+ 0x0, 0x00000000, 0x00000008, -+}; -+static void *prop_zs_addr; -+static const int prop_zs_slave = 1; -+static const struct property propv_obio_zs[] = { -+ {"name", "zs", sizeof("zs")}, -+ {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, -+ {"slave", (char*)&prop_zs_slave, sizeof(prop_zs_slave) }, -+ {"device_type", "serial", sizeof("serial") }, -+ {"intr", (char*)&prop_zs_intr[0], sizeof(prop_zs_intr) }, -+ {"address", (char*)&prop_zs_addr, sizeof(prop_zs_addr) }, -+ {"keyboard", (char*)&prop_true, 0}, -+ {"mouse", (char*)&prop_true, 0}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_zs1_intr[] = { 0x2c, 0x0 }; -+static const int prop_zs1_reg[] = { -+ 0x0, 0x00100000, 0x00000008, -+}; -+static void *prop_zs1_addr; -+static const int prop_zs1_slave = 0; -+static const struct property propv_obio_zs1[] = { -+ {"name", "zs", sizeof("zs")}, -+ {"reg", (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) }, -+ {"slave", (char*)&prop_zs1_slave, sizeof(prop_zs1_slave) }, -+ {"device_type", "serial", sizeof("serial") }, -+ {"intr", (char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) }, -+ {"address", (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_ledma_reg[] = { -+ 0x4, 0x08400010, 0x00000020, -+}; -+static const int prop_ledma_burst = 0x3f; -+static const struct property propv_sbus_ledma[] = { -+ {"name", "ledma", sizeof("ledma")}, -+ {"reg", (char*)&prop_ledma_reg[0], sizeof(prop_ledma_reg) }, -+ {"burst-sizes", (char*)&prop_ledma_burst, sizeof(int) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_le_reg[] = { -+ 0x4, 0x08c00000, 0x00000004, -+}; -+static const int prop_le_busmaster_regval = 0x7; -+static const int prop_le_intr[] = { 0x26, 0x0 }; -+static const struct property propv_sbus_ledma_le[] = { -+ {"name", "le", sizeof("le")}, -+ {"reg", (char*)&prop_le_reg[0], sizeof(prop_le_reg) }, -+ {"busmaster-regval", (char*)&prop_le_busmaster_regval, sizeof(int)}, -+ {"intr", (char*)&prop_le_intr[0], sizeof(prop_le_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_espdma_reg[] = { -+ 0x4, 0x08400000, 0x00000010, -+}; -+ -+static const struct property propv_sbus_espdma[] = { -+ {"name", "espdma", sizeof("espdma")}, -+ {"reg", (char*)&prop_espdma_reg[0], sizeof(prop_espdma_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_esp_reg[] = { -+ 0x4, 0x08800000, 0x00000040, -+}; -+static const int prop_esp_intr[] = { 0x24, 0x0 }; -+static const struct property propv_sbus_espdma_esp[] = { -+ {"name", "esp", sizeof("esp")}, -+ {"reg", (char*)&prop_esp_reg[0], sizeof(prop_esp_reg) }, -+ {"intr", (char*)&prop_esp_intr[0], sizeof(prop_esp_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_bpp_reg[] = { -+ 0x4, 0x0c800000, 0x0000001c, -+}; -+static const int prop_bpp_intr[] = { 0x33, 0x0 }; -+static const struct property propv_sbus_bpp[] = { -+ {"name", "SUNW,bpp", sizeof("SUNW,bpp")}, -+ {"reg", (char*)&prop_bpp_reg[0], sizeof(prop_bpp_reg) }, -+ {"intr", (char*)&prop_bpp_intr[0], sizeof(prop_bpp_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_apc_reg[] = { -+ 0x4, 0x0a000000, 0x00000010, -+}; -+static const struct property propv_sbus_apc[] = { -+ {"name", "xxxpower-management", sizeof("xxxpower-management")}, -+ {"reg", (char*)&prop_apc_reg[0], sizeof(prop_apc_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_fd_intr[] = { 0x2b, 0x0 }; -+static const int prop_fd_reg[] = { -+ 0x0, 0x00400000, 0x0000000f, -+}; -+static const struct property propv_obio_fd[] = { -+ {"name", "SUNW,fdtwo", sizeof("SUNW,fdtwo")}, -+ {"reg", (char*)&prop_fd_reg[0], sizeof(prop_fd_reg) }, -+ {"device_type", "block", sizeof("block") }, -+ {"intr", (char*)&prop_fd_intr[0], sizeof(prop_fd_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_pw_intr[] = { 0x22, 0x0 }; -+static const int prop_pw_reg[] = { -+ 0x0, 0x00910000, 0x00000001, -+}; -+static const struct property propv_obio_pw[] = { -+ {"name", "power", sizeof("power")}, -+ {"reg", (char*)&prop_pw_reg[0], sizeof(prop_pw_reg) }, -+ {"intr", (char*)&prop_pw_intr[0], sizeof(prop_pw_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_cf_reg[] = { -+ 0x0, 0x00800000, 0x00000001, -+}; -+static const struct property propv_obio_cf[] = { -+ {"name", "slavioconfig", sizeof("slavioconfig")}, -+ {"reg", (char*)&prop_cf_reg[0], sizeof(prop_cf_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const struct property propv_options[] = { -+ {"name", "options", sizeof("options")}, -+ {"screen-#columns", "80", sizeof("80")}, -+ {"screen-#rows", "25", sizeof("25")}, -+ {"tpe-link-test?", (char *)&prop_true, 0}, -+ {"ttya-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, -+ {"ttya-ignore-cd", (char *)&prop_true, 0}, -+ {"ttya-rts-dtr-off", 0, -1}, -+ {"ttyb-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, -+ {"ttyb-ignore-cd", (char *)&prop_true, 0}, -+ {"ttyb-rts-dtr-off", 0, -1}, -+ {NULL, NULL, -1} -+}; -+ -+static int prop_mem_reg[3]; -+static int prop_mem_avail[3]; -+ -+static const struct property propv_memory[] = { -+ {"name", "memory", sizeof("memory")}, -+ {"reg", (char*)&prop_mem_reg[0], sizeof(prop_mem_reg) }, -+ {"available", (char*)&prop_mem_avail[0], sizeof(prop_mem_avail) }, -+ {NULL, NULL, -1} -+}; -+ -+static int prop_vmem_avail[6]; -+ -+static const struct property propv_vmemory[] = { -+ {"name", "virtual-memory", sizeof("virtual-memory")}, -+ {"available", (char*)&prop_vmem_avail[0], sizeof(prop_vmem_avail) }, -+ {NULL, NULL, -1} -+}; -+ -+static const struct node nodes[] = { -+ { &null_properties, 1, 0 }, /* 0 = big brother of root */ -+ { propv_root, 0, 2 }, /* 1 "/" */ -+ { propv_iommu, 12, 3 }, /* 2 "/iommu" */ -+ { propv_sbus, 0, 4 }, /* 3 "/iommu/sbus" */ -+ { propv_sbus_tcx, 5, 0 }, /* 4 "/iommu/sbus/SUNW,tcx" */ -+ { propv_sbus_ledma, 7, 6 }, /* 5 "/iommu/sbus/ledma" */ -+ { propv_sbus_ledma_le, 0, 0 }, /* 6 "/iommu/sbus/ledma/le" */ -+ { propv_sbus_cs4231, 8, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ -+ { propv_sbus_bpp, 9, 0 }, /* 8 "/iommu/sbus/SUNW,bpp */ -+ { propv_sbus_espdma, 11, 10 }, /* 9 "/iommu/sbus/espdma" */ -+ { propv_sbus_espdma_esp, 0, 0 }, /* 10 "/iommu/sbus/espdma/esp" */ -+ { propv_sbus_apc, 0, 0 }, /* 11 "/iommu/sbus/power-management */ -+ { propv_cpu, 13, 0 }, /* 12 "/STP1012PGA" */ -+ { propv_obio, 23, 14 }, /* 13 "/obio" */ -+ { propv_obio_int, 15, 0 }, /* 14 "/obio/interrupt" */ -+ { propv_obio_cnt, 16, 0 }, /* 15 "/obio/counter" */ -+ { propv_obio_eep, 17, 0 }, /* 16 "/obio/eeprom" */ -+ { propv_obio_auxio, 18, 0 }, /* 17 "/obio/auxio" */ -+ { propv_obio_zs1, 19, 0 }, /* 18 "/obio/zs@0,100000" -+ Must be before zs@0,0! */ -+ { propv_obio_zs, 20, 0 }, /* 19 "/obio/zs@0,0" */ -+ { propv_obio_fd, 21, 0 }, /* 20 "/obio/SUNW,fdtwo" */ -+ { propv_obio_pw, 22, 0 }, /* 21 "/obio/power" */ -+ { propv_obio_cf, 0, 0 }, /* 22 "/obio/slavioconfig@0,800000" */ -+ { propv_options, 24, 0 }, /* 23 "/options" */ -+ { propv_memory, 25, 0 }, /* 24 "/memory" */ -+ { propv_vmemory, 0, 0 }, /* 25 "/virtual-memory" */ -+}; -+ -+static struct linux_mlist_v0 totphys[MAX_BANKS]; -+static struct linux_mlist_v0 totmap[1]; -+static struct linux_mlist_v0 totavail[MAX_BANKS]; -+ -+static struct linux_mlist_v0 *ptphys; -+static struct linux_mlist_v0 *ptmap; -+static struct linux_mlist_v0 *ptavail; -+ -+static const struct linux_nodeops nodeops0 = { -+ obp_nextnode, /* int (*no_nextnode)(int node); */ -+ obp_child, /* int (*no_child)(int node); */ -+ obp_proplen, /* int (*no_proplen)(int node, char *name); */ -+ obp_getprop, /* int (*no_getprop)(int node,char *name,char *val); */ -+ obp_setprop, /* int (*no_setprop)(int node, char *name, -+ char *val, int len); */ -+ obp_nextprop /* char * (*no_nextprop)(int node, char *name); */ -+}; -+ -+static struct linux_arguments_v0 obp_arg; -+static const struct linux_arguments_v0 * const obp_argp = &obp_arg; -+ -+static void (*synch_hook)(void); -+static char obp_stdin, obp_stdout; -+static int obp_fd_stdin, obp_fd_stdout; -+ -+static int obp_nbgetchar(void); -+static int obp_nbputchar(int ch); -+static void obp_reboot(char *); -+static void obp_abort(void); -+static void obp_halt(void); -+static int obp_devopen(char *str); -+static int obp_devclose(int dev_desc); -+static int obp_devread(int dev_desc, char *buf, int nbytes); -+static int obp_devwrite(int dev_desc, char *buf, int nbytes); -+static int obp_devseek(int dev_desc, int hi, int lo); -+static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); -+static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size); -+static void obp_dumb_munmap(char *va, unsigned int size); -+static int obp_inst2pkg(int dev_desc); -+ -+static void doublewalk(unsigned ptab1, unsigned va) -+{ -+unsigned int proc_tablewalk(int ctx, unsigned int va); -+unsigned int mem_tablewalk(unsigned int pa, unsigned int va); -+ -+ proc_tablewalk(0, va); -+ if (ptab1 != 0) mem_tablewalk(ptab1, va); -+} -+ -+static struct linux_romvec romvec0; -+ -+struct fd { -+ int unit, part; -+ int offset; -+ int (*pread)(int dev_desc, int offset, char *buf, unsigned int nbytes); -+ int (*pwrite)(int dev_desc, int offset, char *buf, unsigned int nbytes); -+} fd_table[16]; -+ -+static int fd_index; -+static int con_pread(int dev_desc, int offset, char *buf, unsigned int nbytes); -+static int con_pwrite(int dev_desc, int offset, char *buf, unsigned int nbytes); -+ -+void * -+init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, -+ const char *cmdline, char boot_device, int nographic) -+{ -+ int i; -+ -+ /* -+ * Avoid data segment allocations -+ */ -+ ptphys = totphys; -+ ptmap = totmap; -+ ptavail = totavail; -+ /* -+ * Form memory descriptors. -+ */ -+ for (i = 0; i < bankc; i++) { -+ totphys[i].theres_more = &totphys[i+1]; -+ totphys[i].start_adr = (char*) bankv[i].start; -+ totphys[i].num_bytes = bankv[i].length; -+ } -+ totphys[i-1].theres_more = 0; -+ -+ /* -+ * XXX Merged in normal PROM when full banks touch. -+ */ -+ for (i = 0; i < bankc; i++) { -+ unsigned bankbase = bankv[i].start; -+ unsigned banksize = bankv[i].length; -+ if (hiphybas > bankbase && -+ hiphybas < bankbase + banksize) { -+ banksize = hiphybas - bankbase; -+ } -+ totavail[i].theres_more = &totavail[i+1]; -+ totavail[i].start_adr = (char*) bankbase; -+ totavail[i].num_bytes = banksize; -+ } -+ totavail[i-1].theres_more = 0; -+ -+ totmap[0].theres_more = 0; -+ totmap[0].start_adr = (char*) PROLBASE; -+ totmap[0].num_bytes = PROLSIZE; -+ prop_mem_reg[0] = 0; -+ prop_mem_reg[1] = 0; -+ prop_mem_reg[2] = bankv[0].length; -+ prop_mem_avail[0] = 0; -+ prop_mem_avail[1] = 0; -+ prop_mem_avail[2] = hiphybas; -+ prop_vmem_avail[0] = 0; -+ prop_vmem_avail[1] = 0; -+ prop_vmem_avail[2] = PROLBASE-1; -+ prop_vmem_avail[3] = 0; -+ prop_vmem_avail[4] = 0xffe00000; -+ prop_vmem_avail[5] = 0x00200000; -+ -+ /* -+ * idprom -+ */ -+ bcopy(idprom, obp_idprom, IDPROM_SIZE); -+ -+ // Linux wants a R/W romvec table -+ romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; -+ romvec0.pv_romvers = 3; -+ romvec0.pv_plugin_revision = 77; -+ romvec0.pv_printrev = 0x10203; -+ romvec0.pv_v0mem.v0_totphys = &ptphys; -+ romvec0.pv_v0mem.v0_prommap = &ptmap; -+ romvec0.pv_v0mem.v0_available = &ptavail; -+ romvec0.pv_nodeops = &nodeops0; -+ romvec0.pv_bootstr = (void *)doublewalk; -+ romvec0.pv_v0devops.v0_devopen = &obp_devopen; -+ romvec0.pv_v0devops.v0_devclose = &obp_devclose; -+ romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev; -+ romvec0.pv_stdin = &obp_stdin; -+ romvec0.pv_stdout = &obp_stdout; -+ romvec0.pv_getchar = obp_nbgetchar; -+ romvec0.pv_putchar = (void (*)(int))obp_nbputchar; -+ romvec0.pv_nbgetchar = obp_nbgetchar; -+ romvec0.pv_nbputchar = obp_nbputchar; -+ romvec0.pv_reboot = obp_reboot; -+ romvec0.pv_printf = (void (*)(const char *fmt, ...))printk; -+ romvec0.pv_abort = obp_abort; -+ romvec0.pv_halt = obp_halt; -+ romvec0.pv_synchook = &synch_hook; -+ romvec0.pv_v0bootargs = &obp_argp; -+ romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg; -+ romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap; -+ romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap; -+ romvec0.pv_v2devops.v2_dev_open = obp_devopen; -+ romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose; -+ romvec0.pv_v2devops.v2_dev_read = obp_devread; -+ romvec0.pv_v2devops.v2_dev_write = obp_devwrite; -+ romvec0.pv_v2devops.v2_dev_seek = obp_devseek; -+ obp_arg.boot_dev_ctrl = 0; -+ obp_arg.boot_dev_unit = '0'; -+ obp_arg.argv[0] = "sd(0,0,0):d"; -+ switch(boot_device) { -+ default: -+ case 'a': -+ obp_arg.argv[0] = "fd()"; -+ obp_arg.boot_dev[0] = 'f'; -+ obp_arg.boot_dev[1] = 'd'; -+ break; -+ case 'd': -+ obp_arg.boot_dev_unit = '2'; -+ obp_arg.argv[0] = "sd(0,2,0):d"; -+ // Fall through -+ case 'c': -+ obp_arg.boot_dev[0] = 's'; -+ obp_arg.boot_dev[1] = 'd'; -+ break; -+ case 'n': -+ obp_arg.argv[0] = "le()"; -+ obp_arg.boot_dev[0] = 'l'; -+ obp_arg.boot_dev[1] = 'e'; -+ break; -+ } -+ obp_arg.argv[1] = cmdline; -+ romvec0.pv_v2bootargs.bootpath = &obp_arg.argv[0]; -+ romvec0.pv_v2bootargs.bootargs = &cmdline; -+ romvec0.pv_v2bootargs.fd_stdin = &obp_fd_stdin; -+ romvec0.pv_v2bootargs.fd_stdout = &obp_fd_stdout; -+ -+ bcopy(propv_root_templ, propv_root, sizeof(propv_root_templ)); -+ propv_root[4].name = "stdin-path"; -+ propv_root[5].name = "stdout-path"; -+ obp_fd_stdin = 0; -+ obp_fd_stdout = 1; -+ fd_table[0].pread = con_pread; -+ fd_table[0].pwrite = con_pwrite; -+ fd_table[1].pread = con_pread; -+ fd_table[1].pwrite = con_pwrite; -+ fd_index = 2; -+ if (nographic) { -+ obp_stdin = PROMDEV_TTYA; -+ propv_root[4].value = "/obio/zs@0,100000:a"; -+ propv_root[4].length = sizeof("/obio/zs@0,100000:a"); -+ fd_table[0].unit = 18; -+ obp_stdout = PROMDEV_TTYA; -+ propv_root[5].value = "/obio/zs@0,100000:a"; -+ propv_root[5].length = sizeof("/obio/zs@0,100000:a"); -+ fd_table[1].unit = 18; -+ } else { -+ obp_stdin = PROMDEV_KBD; -+ propv_root[4].value = "/obio/zs@0,0"; -+ propv_root[4].length = sizeof("/obio/zs@0,0"); -+ fd_table[0].unit = 19; -+ obp_stdout = PROMDEV_SCREEN; -+ propv_root[5].value = "/iommu/sbus/SUNW,tcx"; -+ propv_root[5].length = sizeof("/iommu/sbus/SUNW,tcx"); -+ fd_table[1].unit = 4; -+ } -+ prop_zs_addr = map_io(0x71000000, 8); -+ prop_zs1_addr = map_io(0x71100000, 8); -+ return &romvec0; -+} -+ -+static const struct property *find_property(int node,char *name) -+{ -+ const struct property *prop = &nodes[node].properties[0]; -+ while (prop && prop->name) { -+ if (bcmp(prop->name, name, 128) == 0) return prop; -+ prop++; -+ } -+ return NULL; -+} -+ -+static int obp_nextnode(int node) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_nextnode(%d) = %d\n", node, nodes[node].sibling); -+#endif -+ return nodes[node].sibling; -+} -+ -+static int obp_child(int node) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_child(%d) = %d\n", node, nodes[node].child); -+#endif -+ return nodes[node].child; -+} -+ -+static int obp_proplen(int node, char *name) -+{ -+ const struct property *prop = find_property(node,name); -+ if (prop) { -+#ifdef DEBUG_OBP -+ printk("obp_proplen(%d, %s) = %d\n", node, name, prop->length); -+#endif -+ return prop->length; -+ } -+#ifdef DEBUG_OBP -+ printk("obp_proplen(%d, %s) (no prop)\n", node, name); -+#endif -+ return -1; -+} -+ -+static int obp_getprop(int node, char *name, char *value) -+{ -+ const struct property *prop; -+ -+ if (!name) { -+ // NULL name means get first property -+#ifdef DEBUG_OBP -+ printk("obp_getprop(%d, %x (NULL)) = %s\n", node, name, -+ nodes[node].properties[0].name); -+#endif -+ return (int)nodes[node].properties[0].name; -+ } -+ prop = find_property(node,name); -+ if (prop) { -+ memcpy(value,prop->value,prop->length); -+#ifdef DEBUG_OBP -+ printk("obp_getprop(%d, %s) = %s\n", node, name, value); -+#endif -+ return prop->length; -+ } -+#ifdef DEBUG_OBP -+ printk("obp_getprop(%d, %s): not found\n", node, name); -+#endif -+ return -1; -+} -+ -+static int obp_setprop(__attribute__((unused)) int node, -+ __attribute__((unused)) char *name, -+ __attribute__((unused)) char *value, -+ __attribute__((unused)) int len) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_setprop(%d, %s) = %s (%d)\n", node, name, value, len); -+#endif -+ return -1; -+} -+ -+static const char *obp_nextprop(int node,char *name) -+{ -+ const struct property *prop; -+ -+ if (!name || *name == '\0') { -+ // NULL name means get first property -+#ifdef DEBUG_OBP -+ printk("obp_nextprop(%d, NULL) = %s\n", node, -+ nodes[node].properties[0].name); -+#endif -+ return nodes[node].properties[0].name; -+ } -+ prop = find_property(node,name); -+ if (prop && prop[1].name) { -+#ifdef DEBUG_OBP -+ printk("obp_nextprop(%d, %s) = %s\n", node, name, prop[1].name); -+#endif -+ return prop[1].name; -+ } -+#ifdef DEBUG_OBP -+ printk("obp_nextprop(%d, %s): not found\n", node, name); -+#endif -+ return ""; -+} -+ -+extern int (*getch_fn)(struct vconterm *v); -+ -+static int obp_nbgetchar(void) { -+ extern struct vconterm dp0; -+ return getch_fn(&dp0); -+} -+ -+static int obp_nbputchar(int ch) { -+ printk("%c", ch); -+ return 0; -+} -+ -+static void obp_reboot(char *str) { -+ printk("rebooting (%s)\n", str); -+ stb_bypass(0x71f00000, 1); -+ for (;;) {} -+} -+ -+static void obp_abort() { -+ printk("abort, power off\n"); -+ stb_bypass(0x71910000, 1); -+ for (;;) {} -+} -+ -+static void obp_halt() { -+ printk("halt, power off\n"); -+ stb_bypass(0x71910000, 1); -+ for (;;) {} -+} -+ -+extern void *esp_read(int unit, int part, int offset, short len); -+ -+static int esp_pread(int dev_desc, int offset, char *buf, unsigned int nbytes) -+{ -+ unsigned int i; -+ void *src; -+ -+ for(i = 0; i < nbytes; i += 512) { -+ src = esp_read(fd_table[dev_desc].unit, fd_table[dev_desc].part, (offset + i) / 512, 512); -+ memcpy(&buf[i], src, 512); -+ } -+ return nbytes; -+} -+ -+static int con_pread(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes) -+{ -+ unsigned int i; -+ -+ for(i = 0; i < nbytes; i ++) { -+ buf[i] = obp_nbgetchar(); -+ } -+ return nbytes; -+} -+ -+static int con_pwrite(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes) -+{ -+ unsigned int i; -+ -+ for(i = 0; i < nbytes; i ++) { -+ obp_nbputchar(buf[i]); -+ } -+ return nbytes; -+} -+ -+#define isnum(c) ((c >= '0') && (c < '9')) -+#define ctoi(c) (c - '0') -+ -+static int obp_devopen(char *str) { -+#ifdef DEBUG_OBP -+ printk("obp_devopen(%s)\n", str); -+#endif -+ if (str[0] == 's' && str[1] == 'd' && str[4] == ',') { -+ unsigned int target; -+ -+ if (str[5] < 7) -+ target = str[5]; -+ else if (isnum(str[6]) && isnum(str[5])) { -+ target = (ctoi(str[5]) * 10 + ctoi(str[6])) & 7; -+ } -+ else { -+ target = ctoi(str[5]) & 7; -+ } -+ fd_table[fd_index].unit = target; -+ fd_table[fd_index].part = str[10] - 'a'; -+ fd_table[fd_index].pread = esp_pread; -+ return fd_index++; // XXX -+ } -+ return 0; -+} -+ -+static int obp_devclose(__attribute__((unused)) int dev_desc) { -+#ifdef DEBUG_OBP -+ printk("obp_devclose %d\n", dev_desc); -+#endif -+ fd_index--; // XXX -+ return 0; -+} -+ -+static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_rdblkdev: fd %d, num_blks %d, offset %d, buf 0x%x\n", dev_desc, num_blks, offset, buf); -+#endif -+ return fd_table[dev_desc].pread(dev_desc, offset, buf, num_blks * 512); -+} -+ -+static char *obp_dumb_mmap(char *va, __attribute__((unused)) int which_io, -+ unsigned int pa, unsigned int size) -+{ -+ unsigned int npages; -+ unsigned int off; -+ unsigned int mva; -+ -+#ifdef DEBUG_OBP -+ printk("obp_dumb_mmap: virta %x, which_io %d, paddr %x, sz %d\n", va, which_io, pa, size); -+#endif -+ off = pa & (PAGE_SIZE-1); -+ npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE; -+ pa &= ~(PAGE_SIZE-1); -+ -+ mva = (unsigned int) va; -+ while (npages-- != 0) { -+ map_page(pmem.pl1, mva, pa, 1, pmem.pbas); -+ mva += PAGE_SIZE; -+ pa += PAGE_SIZE; -+ } -+ return va; -+} -+ -+static void obp_dumb_munmap(__attribute__((unused)) char *va, -+ __attribute__((unused)) unsigned int size) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_dumb_munmap: virta %x, sz %d\n", va, size); -+#endif -+} -+ -+static int obp_devread(int dev_desc, char *buf, int nbytes) -+{ -+ int ret; -+#ifdef DEBUG_OBP -+ printk("obp_devread: fd %d, nbytes %d\n", dev_desc, nbytes); -+#endif -+ ret = fd_table[dev_desc].pread(dev_desc, fd_table[dev_desc].offset, buf, nbytes); -+ fd_table[dev_desc].offset += nbytes; -+ return ret; -+} -+ -+static int obp_devwrite(int dev_desc, char *buf, int nbytes) -+{ -+ int ret; -+#ifdef DEBUG_OBP -+ printk("obp_devwrite: fd %d, buf %s, nbytes %d\n", dev_desc, buf, nbytes); -+#endif -+ ret = fd_table[dev_desc].pwrite(dev_desc, fd_table[dev_desc].offset, buf, nbytes); -+ fd_table[dev_desc].offset += nbytes; -+ return ret; -+} -+ -+static int obp_devseek(int dev_desc, __attribute__((unused)) int hi, int lo) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_devseek: fd %d, hi %d, lo %d\n", dev_desc, hi, lo); -+#endif -+ fd_table[dev_desc].offset = lo; -+ return 0; -+} -+ -+static int obp_inst2pkg(int dev_desc) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_inst2pkg: fd %d\n", dev_desc); -+#endif -+ return fd_table[dev_desc].unit; -+} -diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch-15/qemu/system_qemu.c ---- proll_18.orig/qemu/system_qemu.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/system_qemu.c 2005-04-16 06:16:20.000000000 +0000 -@@ -0,0 +1,430 @@ -+/** -+ ** Proll (PROM replacement) -+ ** system.c: shared miscallenea. -+ ** Copyright 1999 Pete Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+#include -+#include -+#include -+#ifndef NULL -+#define NULL ((void*)0) -+#endif -+ -+#include "pgtsrmmu.h" -+ -+#include "vconsole.h" -+#include /* Local copy of 2.2 style include */ -+#include /* __P() */ -+#include /* init_net() */ -+#include /* we are a provider for part of this. */ -+#include /* myipaddr */ -+#include -+#include /* our own prototypes */ -+ -+/* -+ * We export this. -+ */ -+char idprom[IDPROM_SIZE]; -+ -+ -+/* -+ * Create an I/O mapping to pa[size]. -+ * Returns va of the mapping or 0 if unsuccessful. -+ */ -+void * -+map_io(unsigned pa, int size) -+{ -+ void *va; -+ unsigned int npages; -+ unsigned int off; -+ unsigned int mva; -+ -+ off = pa & (PAGE_SIZE-1); -+ npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE; -+ pa &= ~(PAGE_SIZE-1); -+ -+ va = mem_alloc(&cio, npages*PAGE_SIZE, PAGE_SIZE); -+ if (va == 0) return va; -+ -+ mva = (unsigned int) va; -+ /* printk("map_io: va 0x%x pa 0x%x off 0x%x npages %d\n", va, pa, off, npages); */ /* P3 */ -+ while (npages-- != 0) { -+ map_page(pmem.pl1, mva, pa, 1, pmem.pbas); -+ mva += PAGE_SIZE; -+ pa += PAGE_SIZE; -+ } -+ -+ return (void *)((unsigned int)va + off); -+} -+ -+/* -+ * Tablewalk routine used for testing. -+ * Returns PTP/PTE. -+ */ -+unsigned int -+proc_tablewalk(int ctx, unsigned int va) -+{ -+ unsigned int pa1; -+ -+ __asm__ __volatile__ ("lda [%1] %2, %0" : -+ "=r" (pa1) : -+ "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS)); -+ /* printk(" ctpr %x ctx %x\n", pa1, ctx); */ /* P3 */ -+ pa1 <<= 4; -+ pa1 = ld_bypass(pa1 + (ctx << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ return mem_tablewalk((pa1 & 0xFFFFFFF0) << 4, va); -+ -+invalid: -+ printk(" invalid %x\n", pa1); -+ return 0; -+} -+ -+/* -+ * Walk the tables in memory, starting at physical address pa. -+ */ -+unsigned int -+mem_tablewalk(unsigned int pa, unsigned int va) -+{ -+ unsigned int pa1; -+ -+ printk("pa %x va %x", pa, va); -+ pa1 = ld_bypass(pa + (((va&0xFF000000)>>24) << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ printk(" l1 %x", pa1); -+ pa1 <<= 4; pa1 &= 0xFFFFFF00; -+ pa1 = ld_bypass(pa1 + (((va&0x00FC0000)>>18) << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ printk(" l2 %x", pa1); -+ pa1 <<= 4; pa1 &= 0xFFFFFF00; -+ pa1 = ld_bypass(pa1 + (((va&0x0003F000)>>12) << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ printk(" l3 %x", pa1); -+ printk(" off %x\n", va&0x00000FFF); -+ return pa1; -+invalid: -+ printk(" invalid %x\n", pa1); -+ return 0; -+} -+ -+/* -+ * Make CPU page tables. -+ * Returns pointer to context table. -+ * Here we ignore memory allocation errors which "should not happen" -+ * because we cannot print anything anyways if memory initialization fails. -+ */ -+void makepages(struct phym *t, unsigned int highbase) -+{ -+ unsigned int *ctp, *l1, pte; -+ int i; -+ unsigned int pa, va; -+ -+ ctp = mem_zalloc(&cmem, NCTX_SWIFT*sizeof(int), NCTX_SWIFT*sizeof(int)); -+ l1 = mem_zalloc(&cmem, 256*sizeof(int), 256*sizeof(int)); -+ -+ pte = SRMMU_ET_PTD | (((unsigned int)l1 - PROLBASE + highbase) >> 4); -+ for (i = 0; i < NCTX_SWIFT; i++) { -+ ctp[i] = pte; -+ } -+ -+ pa = PROLBASE; -+ for (va = PROLBASE; va < PROLDATA; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ pa = highbase + PROLDATA - PROLBASE; -+ for (va = PROLDATA; va < PROLBASE + PROLSIZE; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ -+ /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ -+ pa = 0; -+ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ -+ t->pctp = ctp; -+ t->pl1 = l1; -+ t->pbas = highbase; -+} -+ -+/* -+ * Create a memory mapping from va to epa in page table pgd. -+ * highbase is used for v2p translation. -+ */ -+int -+map_page(unsigned int *pgd, unsigned int va, -+ unsigned int epa, int type, unsigned int highbase) -+{ -+ unsigned int pte; -+ unsigned int *p; -+ unsigned int pa; -+ -+ pte = pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)]; -+ if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { -+ p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PMD*sizeof(int), -+ SRMMU_PTRS_PER_PMD*sizeof(int)); -+ if (p == 0) goto drop; -+ pte = SRMMU_ET_PTD | -+ (((unsigned int)p - PROLBASE + highbase) >> 4); -+ pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)] = pte; -+ /* barrier() */ -+ } -+ -+ pa = ((pte & 0xFFFFFFF0) << 4); -+ pa += (((va)>>SRMMU_PMD_SHIFT & (SRMMU_PTRS_PER_PMD-1)) << 2); -+ pte = ld_bypass(pa); -+ if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { -+ p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PTE*sizeof(int), -+ SRMMU_PTRS_PER_PTE*sizeof(int)); -+ if (p == 0) goto drop; -+ pte = SRMMU_ET_PTD | -+ (((unsigned int)p - PROLBASE + highbase) >> 4); -+ st_bypass(pa, pte); -+ } -+ -+ pa = ((pte & 0xFFFFFFF0) << 4); -+ pa += (((va)>>PAGE_SHIFT & (SRMMU_PTRS_PER_PTE-1)) << 2); -+ -+ pte = SRMMU_ET_PTE | ((epa & PAGE_MASK) >> 4); -+ if (type) { /* I/O */ -+ pte |= SRMMU_REF; -+ /* SRMMU cannot make Supervisor-only, but not exectutable */ -+ pte |= SRMMU_PRIV; -+ } else { /* memory */ -+ pte |= SRMMU_REF|SRMMU_CACHE; -+ pte |= SRMMU_PRIV; /* Supervisor only access */ -+ } -+ st_bypass(pa, pte); -+ return 0; -+ -+drop: -+ return -1; -+} -+ -+/* -+ * Switch page tables. -+ */ -+void -+init_mmu_swift(unsigned int ctp_phy) -+{ -+ unsigned int addr; -+ -+ /* -+ * Flush cache -+ */ -+ for (addr = 0; addr < 0x2000; addr += 0x10) { -+ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : -+ "r" (addr), "i" (ASI_M_DATAC_TAG)); -+ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : -+ "r" (addr<<1), "i" (ASI_M_TXTC_TAG)); -+ } -+ -+ /* -+ * Switch ctx table -+ */ -+ ctp_phy >>= 4; -+ /* printk("done flushing, switching to %x\n", ctp_phy); */ -+ __asm__ __volatile__ ("sta %0, [%1] %2\n\t" : : -+ "r" (ctp_phy), "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS)); -+ -+ /* -+ * Flush old page table references -+ */ -+ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : -+ "r" (0x400), "i" (ASI_M_FLUSH_PROBE) : "memory"); -+} -+ -+/* -+ * add_timer, del_timer -+ * This should go into sched.c, but we have it split for different archs. -+ */ -+struct timer_list_head { -+ struct timer_list *head, *tail; -+}; -+ -+static struct timer_list_head timers; /* Anonymous heap of timers */ -+ -+void add_timer(struct timer_list *timer) { -+ struct timer_list *p; -+ if (timer->prev != NULL || timer->next != NULL) { -+ printk("bug: kernel timer added twice at 0x%x.\n", -+ __builtin_return_address(0)); -+ return; -+ } -+ if ((p = timers.tail) != NULL) { -+ timer->prev = p; -+ p->next = timer; -+ timers.tail = timer; -+ } else { -+ timers.head = timer; -+ timers.tail = timer; -+ } -+ return; -+} -+ -+int del_timer(struct timer_list *timer) { -+ struct timer_list *p; -+ int ret; -+ -+ if (timers.head == timer) timers.head = timer->next; -+ if (timers.tail == timer) timers.tail = timer->prev; -+ if ((p = timer->prev) != NULL) p->next = timer->next; -+ if ((p = timer->next) != NULL) p->prev = timer->prev; -+ ret = timer->next != 0 || timer->prev != 0; -+ timer->next = NULL; -+ timer->prev = NULL; -+ return ret; -+} -+ -+void run_timers() { -+ struct timer_list *p; -+ -+ p = timers.head; -+ while (p != NULL) { -+ if (p->expires < jiffies) { -+ del_timer(p); /* XXX make nonstatic member */ -+ (*p->function)(p->data); -+ p = timers.head; -+ } else { -+ p = p->next; -+ } -+ } -+} -+ -+/* -+ * Allocate memory. This is reusable. -+ */ -+void mem_init(struct mem *t, char *begin, char *limit) -+{ -+ t->start = begin; -+ t->uplim = limit; -+ t->curp = begin; -+} -+ -+void mem_fini(struct mem *t) -+{ -+ t->curp = 0; -+} -+ -+void *mem_alloc(struct mem *t, int size, int align) -+{ -+ char *p; -+ -+ p = (char *)((((unsigned int)t->curp) + (align-1)) & ~(align-1)); -+ if (p >= t->uplim || p + size > t->uplim) return 0; -+ t->curp = p + size; -+ return p; -+} -+ -+void *mem_zalloc(struct mem *t, int size, int align) -+{ -+ char *p; -+ -+ if ((p = mem_alloc(t, size, align)) != 0) memset(p, 0, size); -+ return p; -+} -+ -+/* -+ * Library functions -+ */ -+void *memset(void *s, int c, size_t len) -+{ -+ void *p = s; -+ -+ while (len--) { -+ *(char *)s = c; -+ s++; -+ } -+ return p; -+} -+ -+void bcopy(const void *f, void *t, int len) { -+ while (len--) { -+ *(char *)t = *(char *)f; -+ f++; -+ t++; -+ } -+} -+ -+/* Comparison is 7-bit */ -+int bcmp(const void *s1, const void *s2, int len) -+{ -+ int i; -+ char ch; -+ -+ while (len--) { -+ ch = *(char *)s1; -+ i = ch - *(char *)s2; -+ s1++; -+ s2++; -+ if (i != 0) -+ return i; -+ if (ch == 0) -+ return 0; -+ } -+ return 0; -+} -+ -+int strlen(const char *s) { -+ const char *p; -+ for (p = s; *p != 0; p++) { } -+ return p - s; -+} -+ -+extern void *printk_fn; -+ -+void printk(char *fmt, ...) -+{ -+ struct prf_fp { -+ void *xfp; -+ void (*write)(void *, char *, int); -+ } prfa; -+ extern void prf(struct prf_fp *, char *fmt, va_list adx); -+ va_list x1; -+ -+ va_start(x1, fmt); -+ prfa.xfp = &dp0; -+ prfa.write = printk_fn; -+ prf(&prfa, fmt, x1); -+ va_end(x1); -+} -+ -+void fatal() -+{ -+ printk("fatal."); -+loop: goto loop; -+} -+ -+/* -+ * Get the highest bit number from the mask. -+ */ -+int highc(int mask, int size) -+{ -+ int m1; -+ -+ m1 = 1 << size; -+ while (size != 0) { -+ size--; -+ m1 >>= 1; -+ if (m1 & mask) break; -+ } -+ return size; -+} -+ -+/* -+ */ -+unsigned int ld_bp_swap(unsigned int ptr) { -+ unsigned int n; -+ n = ld_bypass(ptr); -+ n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); -+ return n; -+} -+ -+void st_bp_swap(unsigned int ptr, unsigned int n) { -+ n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); -+ st_bypass(ptr, n); -+}; -diff -ruN proll_18.orig/src/arp.c proll-patch-15/src/arp.c ---- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 -+++ proll-patch-15/src/arp.c 2005-08-14 10:10:11.000000000 +0000 -@@ -45,7 +45,7 @@ - #endif - static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ - static int next_arp; /* next table entry */ --static t_ipaddr def_gw = IP_ANY; /* default routing */ -+static t_ipaddr def_gw; /* default routing */ - - - -@@ -100,10 +100,7 @@ - * - * ARP receiver routine - */ --static int arp_recv(buf, bufsize, addr) --unsigned char *buf; --int bufsize; --unsigned char *addr; -+static int arp_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr) - { - register struct arphdr *ahp = (struct arphdr *)buf; - -@@ -144,7 +141,7 @@ - * - * Resolve IP address and return pointer to hardware address. - */ --unsigned char *ip_resolve(ip) -+const unsigned char *ip_resolve(ip) - t_ipaddr ip; - { - int i; -@@ -230,14 +227,11 @@ - */ - int init_arp() - { -- /* Set name of module for error messages */ -- net_module_name = "arp"; -- - #ifndef NOARP - /* Register ARP packet type and set send buffer pointer */ - if ((arpbuf = (struct arphdr *)reg_type(htons(ETH_P_ARP), arp_recv)) == NULL) - return(FALSE); - #endif -- -+ def_gw = IP_ANY; - return(TRUE); - } -diff -ruN proll_18.orig/src/arp.h proll-patch-15/src/arp.h ---- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 -+++ proll-patch-15/src/arp.h 2004-11-13 15:50:49.000000000 +0000 -@@ -104,7 +104,7 @@ - extern int init_arp __P((void)); - - /* Resolve IP address and return pointer to hardware address */ --extern unsigned char *ip_resolve __P((t_ipaddr ip)); -+extern const unsigned char *ip_resolve __P((t_ipaddr ip)); - - /* Add a new antry to the ARP cache */ - extern void addcache __P((unsigned char *ha, t_ipaddr ip)); -diff -ruN proll_18.orig/src/bootp.c proll-patch-15/src/bootp.c ---- proll_18.orig/src/bootp.c 1999-12-15 17:20:30.000000000 +0000 -+++ proll-patch-15/src/bootp.c 2005-08-14 10:16:09.000000000 +0000 -@@ -151,7 +151,7 @@ - while (TRUE) { - boot_xid = get_ticks() + random(); - bootp_send(); -- i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout, CHR_ESC); -+ i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout); - if (i < 0) { /* user pressed ESC */ - printf("\nAborted\n"); - return(1); -diff -ruN proll_18.orig/src/esp.c proll-patch-15/src/esp.c ---- proll_18.orig/src/esp.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/esp.c 2005-08-15 18:42:46.000000000 +0000 -@@ -0,0 +1,305 @@ -+#include /* == */ -+#include /* __P for netpriv.h */ -+#include /* dmaga */ -+#include -+ -+#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ -+#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ -+#define PHYS_JJ_ESP_IRQ 4 -+#define BUFSIZE 4096 -+/* -+ * XXX Crude -+ */ -+struct esp_dma { -+ struct sparc_dma_registers *regs; -+ enum dvma_rev revision; -+}; -+ -+struct esp_regs { -+ unsigned int regs[16]; -+}; -+ -+struct esp_private { -+ int active; /* initialized */ -+ int inst; /* iface number */ -+ -+ volatile struct esp_regs *ll; -+ __u32 buffer_dvma; -+ unsigned int irq; /* device IRQ number */ -+ int interrupt; -+ -+ struct esp_dma *espdma; /* If set this points to espdma */ -+ -+ unsigned char *buffer; -+ struct disk_info { -+ unsigned int hw_sector; -+ unsigned int part_offset[8]; -+ } disk[8]; -+}; -+ -+static void esp_interrupt(void *dev_id) -+{ -+ struct esp_private *lp = (struct esp_private *)dev_id; -+ -+ lp->interrupt = 1; -+ /* Acknowledge all the interrupt sources ASAP */ -+ -+ lp->interrupt = 0; -+} -+ -+static int esp_open (void *dev) -+{ -+ struct esp_private *lp = (struct esp_private *)dev; -+ int status = 0; -+ -+ if (request_irq(lp->irq, &esp_interrupt, (void *)dev)) { -+ printk ("Esp: Can't get irq %d\n", lp->irq); -+ return -1; -+ } -+ -+ /* On the 4m, setup the espdma to provide the upper bits for buffers */ -+ if (lp->espdma) -+ lp->espdma->regs->dma_test = ((__u32) lp->buffer_dvma) & 0xff000000; -+ -+ return status; -+} -+ -+static int esp_close (void *dev) -+{ -+ struct esp_private *lp = (struct esp_private *)dev; -+ -+ free_irq (lp->irq, (void *) dev); -+ return 0; -+} -+ -+static int -+esp_init(struct esp_private *esp, struct esp_dma *espdma, int irq) -+{ -+ volatile struct esp_regs *ll; -+ -+ /* Get the IO region */ -+ ll = map_io(PHYS_JJ_ESP, sizeof (struct esp_regs)); -+ if (ll == 0) return -1; -+ -+ esp->buffer = dvma_alloc(BUFSIZE, &esp->buffer_dvma); -+ esp->ll = ll; -+ esp->espdma = espdma; -+ esp->irq = irq; -+ -+ // Chip reset -+ stb_bypass((int)ll + 3*2, 2); -+ return 0; -+} -+ -+static int espdma_init(struct esp_dma *espdma) -+{ -+ void *p; -+ -+ /* Hardcode everything for MrCoffee. */ -+ if ((p = map_io(PHYS_JJ_ESPDMA, 0x10)) == 0) { -+ printk("espdma_init: cannot map registers\n"); -+ return -1; -+ } -+ espdma->regs = p; -+ -+ printk("dma1: "); -+ -+ switch((espdma->regs->cond_reg)&DMA_DEVICE_ID) { -+ case DMA_VERS0: -+ espdma->revision=dvmarev0; -+ printk("Revision 0 "); -+ break; -+ case DMA_ESCV1: -+ espdma->revision=dvmaesc1; -+ printk("ESC Revision 1 "); -+ break; -+ case DMA_VERS1: -+ espdma->revision=dvmarev1; -+ printk("Revision 1 "); -+ break; -+ case DMA_VERS2: -+ espdma->revision=dvmarev2; -+ printk("Revision 2 "); -+ break; -+ case DMA_VERHME: -+ espdma->revision=dvmahme; -+ printk("HME DVMA gate array "); -+ break; -+ case DMA_VERSPLUS: -+ espdma->revision=dvmarevplus; -+ printk("Revision 1 PLUS "); -+ break; -+ default: -+ printk("unknown dma version %x", -+ (espdma->regs->cond_reg)&DMA_DEVICE_ID); -+ /* espdma->allocated = 1; */ -+ break; -+ } -+ printk("\n"); -+ return 0; -+} -+ -+static struct esp_dma espdma0; -+static struct esp_private esp; -+/* -+ * Find all the esp cards on the system and initialize them -+ */ -+void esp_probe () -+{ -+ if (espdma_init(&espdma0) != 0) { -+ return; -+ } -+ -+ if (esp_init(&esp, &espdma0, PHYS_JJ_ESP_IRQ) != 0) { -+ printk("esp_probe: esp0 init failed\n"); -+ return; -+ } -+ return; -+} -+ -+void esp_read_capacity(int unit) -+{ -+ // Set SCSI target -+ stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); -+ // Set DMA address -+ st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma); -+ // Set DMA length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 10); -+ stb_bypass(PHYS_JJ_ESP + 1*4, 0); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); -+ // Setup command = Read Capacity -+ esp.buffer[0] = 0x80; -+ esp.buffer[1] = 0x25; -+ esp.buffer[2] = 0x00; -+ esp.buffer[3] = 0x00; -+ esp.buffer[4] = 0x00; -+ esp.buffer[5] = 0x00; -+ esp.buffer[6] = 0x00; -+ esp.buffer[7] = 0x00; -+ esp.buffer[8] = 0x00; -+ esp.buffer[9] = 0x00; -+ esp.buffer[10] = 0x00; -+ // Set ATN, issue command -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2); -+ -+ // Set DMA length = 512 * read length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 0); -+ stb_bypass(PHYS_JJ_ESP + 1*4, 8 & 0xff); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); -+ // Transfer -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0x90); -+ esp.disk[unit].hw_sector = (esp.buffer[4] << 24) | (esp.buffer[5] << 16) | (esp.buffer[6] << 8) | esp.buffer[7]; -+} -+ -+// offset is multiple of 512, len in bytes -+void *esp_read(int unit, int part, int offset, short len) -+{ -+ int pos, hw_sect, sect_offset, spb; -+ -+ // Set SCSI target -+ stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); -+ // Set DMA address -+ st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma); -+ // Set DMA length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 10); -+ stb_bypass(PHYS_JJ_ESP + 1*4, 0); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); -+ hw_sect = esp.disk[unit].hw_sector; -+ offset += esp.disk[unit].part_offset[part]; -+ spb = hw_sect / 512; -+ sect_offset = offset / spb; -+ pos = (offset - sect_offset * spb) * 512; -+ len /= 512; -+ //printk("Read unit %d, offset %d -> offset %d, pos %d, hw_sect %d\n", unit, offset, sect_offset, pos, hw_sect); -+ // Setup command = Read(10) -+ esp.buffer[0] = 0x80; -+ esp.buffer[1] = 0x28; -+ esp.buffer[2] = 0x00; -+ esp.buffer[3] = (sect_offset >> 24) & 0xff; -+ esp.buffer[4] = (sect_offset >> 16) & 0xff; -+ esp.buffer[5] = (sect_offset >> 8) & 0xff; -+ esp.buffer[6] = sect_offset & 0xff; -+ esp.buffer[7] = 0x00; -+ esp.buffer[8] = (len >> 8) & 0xff; -+ esp.buffer[9] = len & 0xff; -+ // Set ATN, issue command -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2); -+ -+ // Set DMA length = sector size * read length -+ stb_bypass(PHYS_JJ_ESP + 0*4, (len * hw_sect) & 0xff); -+ stb_bypass(PHYS_JJ_ESP + 1*4, ((len * hw_sect) >> 8) & 0xff); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); -+ // Transfer -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0x90); -+ return esp.buffer + pos; -+} -+ -+// Sparc boot sequence can be found in SILO docs, -+// first-isofs/README.SILO_ISOFS -+int esp_boot(int unit) -+{ -+ struct sun_disklabel { -+ unsigned char info[128]; /* Informative text string */ -+ unsigned char spare0[14]; -+ struct sun_info { -+ unsigned char spare1; -+ unsigned char id; -+ unsigned char spare2; -+ unsigned char flags; -+ } infos[8]; -+ unsigned char spare[246]; /* Boot information etc. */ -+ short rspeed; /* Disk rotational speed */ -+ short pcylcount; /* Physical cylinder count */ -+ short sparecyl; /* extra sects per cylinder */ -+ unsigned char spare2[4]; /* More magic... */ -+ short ilfact; /* Interleave factor */ -+ short ncyl; /* Data cylinder count */ -+ short nacyl; /* Alt. cylinder count */ -+ short ntrks; /* Tracks per cylinder */ -+ short nsect; /* Sectors per track */ -+ unsigned char spare3[4]; /* Even more magic... */ -+ struct sun_partition { -+ int start_cylinder; -+ int num_sectors; -+ } partitions[8]; -+ short magic; /* Magic number */ -+ short csum; /* Label xor'd checksum */ -+ } *label; -+ unsigned int i, offset; -+ void *src, *dst; -+ -+ printk("Loading partition table from target %d:\n", unit); -+ // Chip reset -+ stb_bypass(PHYS_JJ_ESP + 3*4, 2); -+ -+ esp_open(&esp); -+ esp_read_capacity(unit); -+ -+ label = esp_read(unit, 0, 0, 512); -+ printk("hw sector: %d, CHS: %d/%d/%d, partitions:\n", esp.disk[unit].hw_sector, -+ label->ncyl, label->ntrks, label->nsect); -+ for (i = 0; i < 8; i++) { -+ printk("%c: %d + %d, id %x, flags %x\n", 'a' + i, label->partitions[i].start_cylinder, -+ label->partitions[i].num_sectors, label->infos[i].id, label->infos[i].flags); -+ esp.disk[unit].part_offset[i] = label->partitions[3].start_cylinder * label->ntrks * label->nsect; -+ } -+ offset = 1; -+ printk("booting sd(0,%d,0):d (offset %d)\n", unit, offset); -+ // Skip a.out header (0x20) -+ dst = (void *)0x4000; -+ src = esp_read(unit, 3, offset, 512); -+ src = (void *)((unsigned int) src + 0x20); -+ memcpy(dst, src, 512 - 0x20); -+ dst = (void *)0x4000 + 512 - 0x20; -+ for (i = 1; i < 7680/512; i++) { -+ src = esp_read(unit, 3, offset + i, 512); -+ memcpy(dst, src, 512); -+ dst += 512; -+ } -+ esp_close(&esp); -+ return 0; -+} -diff -ruN proll_18.orig/src/hconsole.c proll-patch-15/src/hconsole.c ---- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 -+++ proll-patch-15/src/hconsole.c 2005-11-09 18:46:34.000000000 +0000 -@@ -29,6 +29,10 @@ - struct raster r_master; /* For a case of resize, whole fb */ - struct raster r_0; /* malloc() erzatz */ - -+#ifdef QEMU -+extern unsigned int q_height, q_width; -+#endif -+ - int hcon_init(struct hconsole *t, unsigned int a0) - { - struct raster *q, *r; -@@ -42,7 +46,11 @@ - * No probing sequence or argument passing, hardcode everything. XXX - */ - raster8_cons_a(q, 768, 1024, (char *)a0); -+#ifndef QEMU - raster_cons_2(r, q, 768-(24*11)-1, 1024-(8*80)-1, (24*11), (8*80)); -+#else -+ raster_cons_2(r, q, 0, 0, q_height, q_width); -+#endif - t->r_ = r; - t->r0_ = q; - t->f_ = &f_master; -@@ -67,7 +75,7 @@ - return 0; - } - --void hcon_fini (struct hconsole *t) -+void hcon_fini (__attribute((unused)) struct hconsole *t) - { - return; - } -@@ -77,12 +85,12 @@ - { - struct rfont *f = t->f_; - -- if (sy < 0 || sy >= t->ydim_) return -1; -- if (sx < 0 || sx >= t->xdim_) return -1; -+ if (sy < 0 || (unsigned)sy >= t->ydim_) return -1; -+ if (sx < 0 || (unsigned)sx >= t->xdim_) return -1; - if (height < 0) return -1; -- if (sy + height > t->ydim_) height = t->ydim_ - sy; -+ if ((unsigned)sy + (unsigned)height > t->ydim_) height = t->ydim_ - sy; - if (width < 0) return -1; -- if (sx + width > t->xdim_) width = t->xdim_ - sx; -+ if ((unsigned)sx + (unsigned)width > t->xdim_) width = t->xdim_ - sx; - - /* XXX Clear with correct background color */ - (*t->r_->clear_)(t->r_, -@@ -107,10 +115,10 @@ - char c0 = c; - RC_color rfg, rbg; - -- if (y < 0 || y >= t->ydim_) return -1; -- if (x < 0 || x >= t->xdim_) return -1; -+ if (y < 0 || (unsigned)y >= t->ydim_) return -1; -+ if (x < 0 || (unsigned)x >= t->xdim_) return -1; - -- if (t->curson_ && t->ypos_ == y && t->xpos_ == x) { -+ if (t->curson_ && t->ypos_ == (unsigned)y && t->xpos_ == (unsigned)x) { - rfg = t->bg_; rbg = t->fg_; - } else { - rfg = t->fg_; rbg = t->bg_; -@@ -126,9 +134,9 @@ - { - struct rfont *f = t->f_; - -- if (y < 0 || y >= t->ydim_) return -1; -- if (x < 0 || x >= t->xdim_) return -1; -- if (x + count >= t->xdim_) count = t->xdim_ - x; -+ if (y < 0 || (unsigned)y >= t->ydim_) return -1; -+ if (x < 0 || (unsigned)x >= t->xdim_) return -1; -+ if ((unsigned)x + (unsigned)count >= t->xdim_) count = t->xdim_ - x; - - (*t->r_->render_)(t->r_, y*f->height_, x*f->width_, - s, count, t->bg_, t->fg_, f); -@@ -200,8 +208,8 @@ - - rc = 0; - if (dir == SM_UP) { -- if (d < 0 || d >= t->ydim_) return -1; -- if (b <= d || b > t->ydim_) return -1; -+ if (d < 0 || (unsigned)d >= t->ydim_) return -1; -+ if (b <= d || (unsigned)b > t->ydim_) return -1; - if (d + count >= b) count = b - d; - if (d + count >= b) count = b - d; - (*t->r_->yscroll_)(t->r_, -@@ -213,8 +221,8 @@ - count*f->height_, raster_qwidth(t->r_), - t->bg_); - } else if (dir == SM_DOWN) { -- if (d < 0 || d >= t->ydim_) return -1; -- if (b <= d || b > t->ydim_) return -1; -+ if (d < 0 || (unsigned)d >= t->ydim_) return -1; -+ if (b <= d || (unsigned)b > t->ydim_) return -1; - if (d + count >= b) count = b - d; - (*t->r_->yscroll_)(t->r_, - d*f->height_, 0, -diff -ruN proll_18.orig/src/hme.c proll-patch-15/src/hme.c ---- proll_18.orig/src/hme.c 2002-07-23 05:52:52.000000000 +0000 -+++ proll-patch-15/src/hme.c 2005-04-16 06:16:20.000000000 +0000 -@@ -655,10 +655,10 @@ - unsigned int flags, - unsigned int addr) - { -- __asm__ __volatile__(" -- stwa %3, [%0] %2 -- stwa %4, [%1] %2 --" : /* no outputs */ -+ __asm__ __volatile__( -+ "stwa %3, [%0] %2\n\t" -+ "stwa %4, [%1] %2\n\t" -+ : /* no outputs */ - : "r" (&rp->rx_addr), "r" (&rp->rx_flags), - "i" (ASI_PL), "r" (addr), "r" (flags)); - } -@@ -667,10 +667,10 @@ - unsigned int flags, - unsigned int addr) - { -- __asm__ __volatile__(" -- stwa %3, [%0] %2 -- stwa %4, [%1] %2 --" : /* no outputs */ -+ __asm__ __volatile__( -+ "stwa %3, [%0] %2\n\t" -+ "stwa %4, [%1] %2\n\t" -+ : /* no outputs */ - : "r" (&tp->tx_addr), "r" (&tp->tx_flags), - "i" (ASI_PL), "r" (addr), "r" (flags)); - } -@@ -2404,7 +2404,7 @@ - TXD(("[%d]", elem)); - this = &txbase[elem]; - #ifdef __sparc_v9__ -- __asm__ __volatile__("lduwa [%1] %2, %0" -+ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" - : "=r" (flags) - : "r" (&this->tx_flags), "i" (ASI_PL)); - #else -@@ -2447,7 +2447,7 @@ - RXD(("RX<")); - this = &rxbase[elem]; - #ifdef __sparc_v9__ -- __asm__ __volatile__("lduwa [%1] %2, %0" -+ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" - : "=r" (flags) - : "r" (&this->rx_flags), "i" (ASI_PL)); - #else -@@ -2530,7 +2530,7 @@ - elem = NEXT_RX(elem); - this = &rxbase[elem]; - #ifdef __sparc_v9__ -- __asm__ __volatile__("lduwa [%1] %2, %0" -+ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" - : "=r" (flags) - : "r" (&this->rx_flags), "i" (ASI_PL)); - #else -diff -ruN proll_18.orig/src/iommu.c proll-patch-15/src/iommu.c ---- proll_18.orig/src/iommu.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch-15/src/iommu.c 2005-08-14 10:08:17.000000000 +0000 -@@ -36,7 +36,7 @@ - unsigned int pa, ba; - unsigned int npages; - unsigned int mva, mpa; -- int i; -+ unsigned int i; - unsigned int *iopte; - - npages = (size + (PAGE_SIZE-1)) / PAGE_SIZE; -diff -ruN proll_18.orig/src/lat7_2.bm proll-patch-15/src/lat7_2.bm ---- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 -+++ proll-patch-15/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 -@@ -1,6 +1,6 @@ - #define lat7_2_width 128 - #define lat7_2_height 88 --static unsigned char lat7_2_bits[] = { -+static unsigned const char lat7_2_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, - 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, -diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch-15/src/lat7_2_swapped.bm ---- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 -@@ -0,0 +1,121 @@ -+#define lat7_2_width 128 -+#define lat7_2_height 88 -+static unsigned const char lat7_2_bits[] = { -+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x00, 0x48, -+ 0x48, 0x78, 0x48, 0x5f, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x78, 0x40, -+ 0x70, 0x40, 0x4f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x30, 0x40, 0x40, -+ 0x40, 0x3e, 0x09, 0x0e, 0x0a, 0x09, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, -+ 0x7f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x0e, 0x0a, 0x0e, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, -+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x44, 0x64, 0x54, 0x4c, 0x54, 0x10, 0x10, -+ 0x10, 0x1f, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x1f, 0x04, 0x04, 0x04, -+ 0x04, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, -+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, -+ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, -+ 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, -+ 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, -+ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, -+ 0x06, 0x0c, 0x18, 0x30, 0x18, 0x6c, 0x36, 0x18, 0x0c, 0x00, 0x00, 0x60, -+ 0x30, 0x18, 0x0c, 0x18, 0x36, 0x6c, 0x18, 0x30, 0x00, 0x00, 0x7f, 0x36, -+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x7e, -+ 0x18, 0x7e, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x78, -+ 0x30, 0x72, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, -+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, -+ 0x00, 0x00, 0x00, 0x66, 0x66, 0x22, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x00, 0x00, 0x00, -+ 0x00, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, -+ 0x72, 0x56, 0x6c, 0x18, 0x36, 0x6a, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x18, -+ 0x24, 0x28, 0x30, 0x4a, 0x44, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x18, -+ 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x18, -+ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x7e, 0x3c, -+ 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, -+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, -+ 0x00, 0x3c, 0x46, 0x4e, 0x5a, 0x72, 0x62, 0x3c, 0x00, 0x00, 0x00, 0x00, -+ 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, -+ 0x66, 0x06, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -+ 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, -+ 0x66, 0x7e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x60, 0x7c, 0x66, -+ 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x66, -+ 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x06, 0x0c, 0x18, 0x30, -+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, -+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, -+ 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -+ 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -+ 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x5e, -+ 0x56, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x66, -+ 0x7e, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x66, -+ 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, -+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x62, 0x7e, 0x00, -+ 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, -+ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, -+ 0x00, 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -+ 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, -+ 0x46, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, -+ 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, -+ 0x60, 0x60, 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x77, 0x7f, -+ 0x6b, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0x7e, 0x6e, -+ 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, -+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x6e, 0x3c, 0x02, -+ 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x00, 0x00, -+ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, -+ 0x00, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, -+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, -+ 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, -+ 0x63, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, -+ 0x18, 0x3c, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, -+ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x0c, 0x18, 0x30, -+ 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, -+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, -+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, -+ 0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, -+ 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, -+ 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -+ 0x7e, 0x60, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, -+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, -+ 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, -+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x1c, 0x00, -+ 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, -+ 0x00, 0x00, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x00, 0x00, 0x00, -+ 0x00, 0x60, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x76, 0x7f, 0x6b, 0x6b, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, -+ 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, -+ 0x66, 0x66, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x72, 0x60, -+ 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x3c, 0x06, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x78, 0x30, 0x30, 0x36, 0x1c, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x6b, 0x6b, 0x6b, 0x36, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x00, -+ 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, -+ 0x18, 0x30, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, -+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x0c, -+ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00}; -diff -ruN proll_18.orig/src/le.c proll-patch-15/src/le.c ---- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch-15/src/le.c 2005-04-16 06:16:20.000000000 +0000 -@@ -185,8 +185,6 @@ - unsigned short rap; /* register address port */ - }; - --int sparc_lance_debug = 2; -- - /* The Lance uses 24 bit addresses */ - /* On the Sun4c the DVMA will provide the remaining bytes for us */ - /* On the Sun4m we have to instruct the ledma to provide them */ -@@ -771,7 +769,7 @@ - /* Clear the slack of the packet, do I need this? */ - /* For a firewall its a good idea - AC */ - if (len != skblen) -- bzero((char *) &ib->tx_buf [entry][skblen], len - skblen); -+ memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); - - /* Now, give the packet to the lance */ - ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); -diff -ruN proll_18.orig/src/net.h proll-patch-15/src/net.h ---- proll_18.orig/src/net.h 1999-12-15 17:20:17.000000000 +0000 -+++ proll-patch-15/src/net.h 2005-08-14 10:17:02.000000000 +0000 -@@ -124,7 +124,7 @@ - extern int udp_open __P((t_ipaddr daddr, int source, int dest)); - - /* Read from a UDP socket */ --extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch)); -+extern int udp_read(char *buf, unsigned int bufsize, int timeout); - - /* Write to a UDP socket */ - extern int udp_write __P((char *buf, int writelen)); -diff -ruN proll_18.orig/src/netinit.c proll-patch-15/src/netinit.c ---- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 -+++ proll-patch-15/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 -@@ -49,13 +49,20 @@ - unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ - t_ipaddr myipaddr; /* my own IP address */ - t_ipaddr mynetmask; /* my own netmask */ -- char *net_module_name; /* name of init module */ - t_ipaddr servaddr; /* IP of RARP&TFTP server */ - - /* Broadcast hardware address */ --unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -+const unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - -+unsigned int seed; -+ -+/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ -+short int random() -+{ -+ seed = (seed + 23968)*0x015A4E35 >> 1; -+ return seed & 0x7FFF; -+} - - /* - ************************************************************************** -@@ -104,10 +111,17 @@ - */ - void init_net() - { -+ /* Avoid data segment allocations */ -+ seed = 151; -+ - /* Initialize the different network layer modules */ - init_packet(); -- if (!init_arp() || !init_udp()) { -- printf("\nERROR: init_%s\n", net_module_name); -+ if (!init_arp()) { -+ printf("\nERROR: init_arp\n"); -+ fatal(); -+ } -+ if (!init_udp()) { -+ printf("\nERROR: init_udp\n"); - fatal(); - } - } -diff -ruN proll_18.orig/src/netpriv.h proll-patch-15/src/netpriv.h ---- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 -+++ proll-patch-15/src/netpriv.h 2005-08-14 10:12:20.000000000 +0000 -@@ -83,7 +83,7 @@ - */ - struct device *dev; - char *data; -- int len; -+ unsigned int len; - int protocol; - unsigned char ip_summed; - }; -@@ -130,10 +130,9 @@ - * - */ - extern unsigned char myhwaddr[ETH_ALEN]; /* my own hardware address */ --extern unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ -+extern const unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ - extern t_ipaddr myipaddr; /* my own IP address */ - extern t_ipaddr mynetmask; /* netmask for my network */ --extern char *net_module_name; /* initialized module's name */ - extern t_ipaddr servaddr; /* server IP address */ - - -@@ -150,7 +149,7 @@ - extern unsigned char *reg_type __P((int typeval, int (* receive)())); - - /* Write a packet to the network */ --extern int write_packet __P((int bufsize, int typeval, unsigned char *addr)); -+extern int write_packet __P((int bufsize, int typeval, const unsigned char *addr)); - - /* Empty read buffer */ - extern void empty_buf __P((void)); -diff -ruN proll_18.orig/src/openprom.h proll-patch-15/src/openprom.h ---- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 -+++ proll-patch-15/src/openprom.h 2005-05-13 16:23:14.000000000 +0000 -@@ -54,29 +54,29 @@ - }; - - struct linux_mem_v0 { -- struct linux_mlist_v0 **v0_totphys; -- struct linux_mlist_v0 **v0_prommap; -- struct linux_mlist_v0 **v0_available; /* What we can use */ -+ struct linux_mlist_v0 * const *v0_totphys; -+ struct linux_mlist_v0 * const *v0_prommap; -+ struct linux_mlist_v0 * const *v0_available; /* What we can use */ - }; - - /* Arguments sent to the kernel from the boot prompt. */ - struct linux_arguments_v0 { -- char *argv[8]; -+ const char *argv[8]; - char args[100]; - char boot_dev[2]; - int boot_dev_ctrl; - int boot_dev_unit; - int dev_partition; -- char *kernel_file_name; -+ const char *kernel_file_name; - void *aieee1; /* XXX */ - }; - - /* V2 and up boot things. */ - struct linux_bootargs_v2 { -- char **bootpath; -- char **bootargs; -- int *fd_stdin; -- int *fd_stdout; -+ const char **bootpath; -+ const char **bootargs; -+ const int *fd_stdin; -+ const int *fd_stdout; - }; - - /* The top level PROM vector. */ -@@ -91,13 +91,13 @@ - struct linux_mem_v0 pv_v0mem; - - /* Node operations. */ -- struct linux_nodeops *pv_nodeops; -+ const struct linux_nodeops *pv_nodeops; - - char **pv_bootstr; - struct linux_dev_v0_funcs pv_v0devops; - -- char *pv_stdin; -- char *pv_stdout; -+ const char *pv_stdin; -+ const char *pv_stdout; - #define PROMDEV_KBD 0 /* input from keyboard */ - #define PROMDEV_SCREEN 0 /* output to screen */ - #define PROMDEV_TTYA 1 /* in/out to ttya */ -@@ -127,7 +127,7 @@ - void (*v2_eval)(char *str); - } pv_fortheval; - -- struct linux_arguments_v0 **pv_v0bootargs; -+ const struct linux_arguments_v0 * const *pv_v0bootargs; - - /* Get ether address. */ - unsigned int (*pv_enaddr)(int d, char *enaddr); -@@ -175,7 +175,7 @@ - int (*no_proplen)(int node, char *name); - int (*no_getprop)(int node, char *name, char *val); - int (*no_setprop)(int node, char *name, char *val, int len); -- char * (*no_nextprop)(int node, char *name); -+ const char * (*no_nextprop)(int node, char *name); - }; - - /* More fun PROM structures for device probing. */ -diff -ruN proll_18.orig/src/packet.c proll-patch-15/src/packet.c ---- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 -+++ proll-patch-15/src/packet.c 2005-08-14 10:12:49.000000000 +0000 -@@ -41,7 +41,7 @@ - int aligner; - } wbuf; - static struct sk_buff *rskb; --static int nqskb = 0; -+static int nqskb; - - - void init_packet() -@@ -62,6 +62,8 @@ - for (i = 0; i < MAXSKBS; i++) { - skev[i].skb.allocn = i; - } -+ -+ nqskb = 0; - } - - unsigned char *reg_type(int ptype, int (*func)()) -@@ -81,7 +83,7 @@ - return wbuf.s; - } - --int write_packet(int leng, int type, unsigned char *dst) -+int write_packet(int leng, int type, const unsigned char *dst) - { - struct sk_buff *skb; - unsigned char *s; -@@ -209,12 +211,12 @@ - /* - */ - void --eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, int base) -+eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, __attribute__((unused)) int base) - { - bcopy(src, dest->data, len); - } - --unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) -+unsigned short eth_type_trans(struct sk_buff *skb, __attribute__((unused)) struct device *dev) - { - unsigned char *s = skb->data + 12; - return s[0] << 8 | s[1]; /* Network order word */ -diff -ruN proll_18.orig/src/printf.c proll-patch-15/src/printf.c ---- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 -+++ proll-patch-15/src/printf.c 2005-08-14 10:07:26.000000000 +0000 -@@ -19,7 +19,7 @@ - static void printn(struct prf_fp *, unsigned long, unsigned int); - static void putchar(char, struct prf_fp *); - --static char hextab[] = "0123456789ABCDEF"; -+static const char hextab[] = "0123456789ABCDEF"; - - /* - * Scaled down version of C Library printf. -@@ -41,7 +41,7 @@ - void - prf(struct prf_fp *filog, char *fmt, va_list adx) - { -- register c; -+ register int c; - char *s; - - for(;;) { -@@ -60,7 +60,7 @@ - putchar(va_arg(adx,unsigned), filog); - } else if(c == 's') { - s = va_arg(adx,char*); -- while(c = *s++) -+ while((c = *s++)) - putchar(c,filog); - } else if (c == 'l' || c == 'O') { - printn(filog, (long)va_arg(adx,long), c=='l'?10:8); -@@ -77,10 +77,6 @@ - char prbuf[24]; - register char *cp; - -- if (b == 10 && n < 0) { -- putchar('-',filog); -- n = (~n) + 1; /* n = -n */ -- } - cp = prbuf; - do - *cp++ = hextab[(unsigned int)(n%b)]; -diff -ruN proll_18.orig/src/rconsole.c proll-patch-15/src/rconsole.c ---- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 -+++ proll-patch-15/src/rconsole.c 2005-08-14 10:25:53.000000000 +0000 -@@ -28,12 +28,18 @@ - * move to California. Only plain lat7 survived. - * I recreated lat7-1 changes in lat7-2. --zaitcev - */ -+#ifdef ORIG - #include "lat7_2.bm" /* lat7_1.bm */ -+#else -+#include "lat7_2_swapped.bm" /* lat7_1.bm */ -+#endif - #define LAT7_NCHARS 128 - #define LAT7_HEIGHT 11 - #define LAT7_WIDTH 8 - -+#ifdef ORIG - static Rf_scan lat7_body[ LAT7_NCHARS*LAT7_HEIGHT ]; -+#endif - - #if 1 - /* -@@ -46,18 +52,18 @@ - #endif - - static __inline__ void stfb_w(void *ptr, unsigned int data) { -- __asm__ __volatile__ ("sta %0, [%1] %2" : : -+ __asm__ __volatile__ ("sta %0, [%1] %2\n\t" : : - "r" (data), "r" (ptr), "i" (ASI_M_BYPASS)); - } - - static __inline__ void stfb_b(void *ptr, unsigned int data) { -- __asm__ __volatile__ ("stba %0, [%1] %2" : : -+ __asm__ __volatile__ ("stba %0, [%1] %2\n\t" : : - "r" (data), "r" (ptr), "i" (ASI_M_BYPASS)); - } - - static __inline__ unsigned int ldfb_w(void *ptr) { - unsigned int data; -- __asm__ __volatile__ ("lda [%1] %2, %0" : -+ __asm__ __volatile__ ("lda [%1] %2, %0\n\t" : - "=r" (data) : - "r" (ptr), "i" (ASI_M_BYPASS)); - return data; -@@ -65,7 +71,7 @@ - - static __inline__ unsigned int ldfb_b(void *ptr) { - unsigned int data; -- __asm__ __volatile__ ("lduba [%1] %2, %0" : -+ __asm__ __volatile__ ("lduba [%1] %2, %0\n\t" : - "=r" (data) : - "r" (ptr), "i" (ASI_M_BYPASS)); - return data; -@@ -94,6 +100,7 @@ - - #endif - -+#ifdef ORIG - static inline int swapbits(int w0) - { - int w1 = 0; -@@ -105,13 +112,16 @@ - } - return w1; - } -+#endif - - void font_cons_7(struct rfont *p) - { -+#ifdef ORIG - int x; - int col = 0; - int row = 0; - int erow = 0; -+ - for (x = 0; x < LAT7_NCHARS*LAT7_HEIGHT; x++ ) { - lat7_body[ (erow * lat7_2_width/8 + col) * LAT7_HEIGHT + row ] = - swapbits(lat7_2_bits[x]) & 0xFF; -@@ -124,6 +134,9 @@ - } - } - p->body_ = lat7_body; -+#else -+ p->body_ = lat7_2_bits; -+#endif - p->nchars_ = LAT7_NCHARS; - p->width_ = LAT7_WIDTH; - p->height_ = LAT7_HEIGHT; -@@ -175,7 +188,7 @@ - r->render_ = p->render_; - } - --void raster_dest(struct raster *r) -+void raster_dest(__attribute((unused)) struct raster *r) - { - } - -diff -ruN proll_18.orig/src/rconsole.h proll-patch-15/src/rconsole.h ---- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 -+++ proll-patch-15/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 -@@ -13,10 +13,10 @@ - */ - - #define RF_MAXWIDTH 16 --typedef unsigned short Rf_scan; /* __w16 to be used */ -+typedef unsigned char Rf_scan; /* __w16 to be used */ - - struct rfont { -- Rf_scan *body_; -+ const Rf_scan *body_; - int nchars_; /* 128 for ASCII ... 65536 for Unicode */ - int width_; /* [Pixels]. Maximum size is 16. */ - int height_; /* [Pixels == scan lines]. */ -diff -ruN proll_18.orig/src/romlib.h proll-patch-15/src/romlib.h ---- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 -+++ proll-patch-15/src/romlib.h 2005-04-16 20:32:49.000000000 +0000 -@@ -72,13 +72,13 @@ - */ - #define memcpy(dst, src, len) bcopy(src, dst, len) - #define memcmp(x1, x2, len) bcmp(x1, x2, len) --#define memset(p, len, zero) bzero(p, len) --extern void bcopy(void *b1, void *b2, int length); --extern int bcmp(void *b1, void *b2, int length); --extern void bzero(void *b, int c); -+extern void bcopy(const void *b1, void *b2, int length); -+extern int bcmp(const void *b1, const void *b2, int length); -+typedef unsigned int size_t; -+extern void *memset(void *p, int c, size_t len); - /* gcc complains about "conflicting types for builtin function strlen". */ - #define strlen(s) ssize(s) --extern int ssize(char *s); -+extern int ssize(const char *s); - - - /* -diff -ruN proll_18.orig/src/sched_4m.c proll-patch-15/src/sched_4m.c ---- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 -+++ proll-patch-15/src/sched_4m.c 2005-08-14 10:18:14.000000000 +0000 -@@ -108,7 +108,7 @@ - static int set_bolt; /* Tick counter limit */ - static struct handsc hndv[16]; - --static unsigned int intr_to_mask[16] = { -+static unsigned const int intr_to_mask[16] = { - 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; -@@ -130,7 +130,7 @@ - int /* 0 - not expired yet; <>0 - timer expired */ - chk_timeout() - { -- int lim = (((1000000/HZ) + 1) << 10); -+ unsigned int lim = (((1000000/HZ) + 1) << 10); - unsigned int clear; - unsigned int intc; - int n; -@@ -182,7 +182,7 @@ - struct handsc *hndp; - unsigned int mask; - -- if (irq < 0 || irq >= 16) { -+ if (irq == 0 || irq >= 16) { - printk("request_irq: bad irq %d\n", irq); - return -1; - } -@@ -207,7 +207,7 @@ - { - struct handsc *hndp; - -- if (irq < 0 || irq >= 16) { -+ if (irq == 0 || irq >= 16) { - printk("free_irq: bad irq %d\n", irq); - return; - } -diff -ruN proll_18.orig/src/swap.c proll-patch-15/src/swap.c ---- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/swap.c 2004-11-13 15:50:49.000000000 +0000 -@@ -0,0 +1,21 @@ -+// Convert the lat7 font so that no conversion is needed at runtime. -+#define ORIG -+#include "rconsole.c" -+ -+#include -+ -+int main() -+{ -+ struct rfont p; -+ int i; -+ -+ font_cons_7(&p); -+ -+ printf(" "); -+ for (i = 0; i < LAT7_NCHARS*LAT7_HEIGHT; i++) { -+ printf("0x%02x, ", p.body_[i]); -+ if ((i % 12) == 11) -+ printf("\n "); -+ } -+ printf("\n"); -+} -diff -ruN proll_18.orig/src/system.c proll-patch-15/src/system.c ---- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch-15/src/system.c 2005-04-16 06:16:20.000000000 +0000 -@@ -298,8 +298,8 @@ - } - - /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ -- pa = PAGE_SIZE; -- for (va = PAGE_SIZE; va < LOWMEMSZ; va += PAGE_SIZE) { -+ pa = 0; -+ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { - map_page(l1, va, pa, 0, highbase); - pa += PAGE_SIZE; - } -@@ -507,30 +507,44 @@ - { - char *p; - -- if ((p = mem_alloc(t, size, align)) != 0) bzero(p, size); -+ if ((p = mem_alloc(t, size, align)) != 0) memset(p, 0, size); - return p; - } - - /* - * Library functions - */ --void bzero(void *s, int len) { -- while (len--) *((char *)s)++ = 0; -+void *memset(void *s, int c, size_t len) -+{ -+ void *p = s; -+ -+ while (len--) { -+ *(char *)s = c; -+ s++; -+ } -+ return p; - } - --void bcopy(void *f, void *t, int len) { -- while (len--) *((char *)t)++ = *((char *)f)++; -+void bcopy(const void *f, void *t, int len) { -+ while (len--) { -+ *(char *)t = *(char *)f; -+ f++; -+ t++; -+ } - } - - /* Comparison is 7-bit */ --int bcmp(void *s1, void *s2, int len) -+int bcmp(const void *s1, const void *s2, int len) - { - int i; - char ch; - - while (len--) { -- ch = *((char *)s1)++; -- if ((i = ch - *((char *)s2)++) != 0) -+ ch = *(char *)s1; -+ i = ch - *(char *)s2; -+ s1++; -+ s2++; -+ if (i != 0) - return i; - if (ch == 0) - return 0; -@@ -538,8 +552,8 @@ - return 0; - } - --int strlen(char *s) { -- char *p; -+int strlen(const char *s) { -+ const char *p; - for (p = s; *p != 0; p++) { } - return p - s; - } -@@ -560,14 +574,6 @@ - va_end(x1); - } - --/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ --short int random() --{ -- static unsigned int seed = 151; -- seed = (seed + 23968)*0x015A4E35 >> 1; -- return seed & 0x7FFF; --} -- - void fatal() - { - printk("fatal."); -diff -ruN proll_18.orig/src/system.h proll-patch-15/src/system.h ---- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 -+++ proll-patch-15/src/system.h 2005-04-16 06:16:20.000000000 +0000 -@@ -16,7 +16,7 @@ - #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ - #define NCTX_SWIFT 0x100 - --#define MAX_BANKS 3 /* Allocation for all machines */ -+#define MAX_BANKS 8 /* Allocation for all machines */ - - #ifndef __ASSEMBLY__ - struct bank { -@@ -164,10 +164,10 @@ - - extern __inline__ void setipl(unsigned long __orig_psr) - { -- __asm__ __volatile__(" -- wr %0, 0x0, %%psr -- nop; nop; nop --" : /* no outputs */ -+ __asm__ __volatile__( -+ "wr %0, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : /* no outputs */ - : "r" (__orig_psr) - : "memory", "cc"); - } -@@ -176,13 +176,13 @@ - { - unsigned long tmp; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- or %0, %1, %0 -- wr %0, 0x0, %%psr -- nop; nop; nop --" : "=r" (tmp) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "or %0, %1, %0\n\t" -+ "wr %0, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : "=r" (tmp) - : "i" (PSR_PIL) - : "memory"); - } -@@ -191,13 +191,13 @@ - { - unsigned long tmp; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- andn %0, %1, %0 -- wr %0, 0x0, %%psr -- nop; nop; nop --" : "=r" (tmp) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "andn %0, %1, %0\n\t" -+ "wr %0, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : "=r" (tmp) - : "i" (PSR_PIL) - : "memory"); - } -@@ -214,18 +214,18 @@ - { - unsigned long retval; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- and %0, %2, %%g1 -- and %1, %2, %%g2 -- xorcc %%g1, %%g2, %%g0 -- be 1f -- nop -- wr %0, %2, %%psr -- nop; nop; nop; --1: --" : "=r" (retval) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "and %0, %2, %%g1\n\t" -+ "and %1, %2, %%g2\n\t" -+ "xorcc %%g1, %%g2, %%g0\n\t" -+ "be 1f\n\t" -+ "nop\n\t" -+ "wr %0, %2, %%psr\n\t" -+ "nop; nop; nop;\n\t" -+ "1:\n\t" -+ : "=r" (retval) - : "r" (__new_psr), "i" (PSR_PIL) - : "g1", "g2", "memory", "cc"); - -@@ -236,13 +236,13 @@ - { - unsigned long retval; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- or %0, %1, %%g1 -- wr %%g1, 0x0, %%psr -- nop; nop; nop --" : "=r" (retval) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "or %0, %1, %%g1\n\t" -+ "wr %%g1, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : "=r" (retval) - : "i" (PSR_PIL) - : "g1", "memory"); - -diff -ruN proll_18.orig/src/tftp.c proll-patch-15/src/tftp.c ---- proll_18.orig/src/tftp.c 2002-09-13 21:53:34.000000000 +0000 -+++ proll-patch-15/src/tftp.c 2005-08-14 10:16:15.000000000 +0000 -@@ -127,7 +127,7 @@ - int len; - - /* Read packet with timeout */ -- len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT, CHR_ESC); -+ len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT); - if (len == 0) { - printf("TFTP: Timeout\n"); - return(ERR_TIMEOUT); -diff -ruN proll_18.orig/src/udp.c proll-patch-15/src/udp.c ---- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 -+++ proll-patch-15/src/udp.c 2005-08-14 10:17:19.000000000 +0000 -@@ -76,12 +76,9 @@ - * - * Open a new UDP socket. - */ --int udp_open(daddr, source, dest) --t_ipaddr daddr; --int source; --int dest; -+int udp_open(t_ipaddr daddr, int source, int dest) - { -- register unsigned char *addr; -+ const unsigned char *addr; - - /* Set global variables */ - usource = source; -@@ -101,16 +98,13 @@ - * - * IP receiver routine - */ --static int ip_recv(buf, bufsize, addr) --unsigned char *buf; --int bufsize; --unsigned char *addr; -+static int ip_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr) - { - struct iphdr *ipp = ((struct iphdr *)buf); - struct udphdr *udpp = ((struct udphdr *)(buf + IP_MIN_HSIZE)); - struct udp_pseudo psehdr; - -- int size; -+ unsigned int size; - t_ipaddr dadr; - - #ifdef DEBUG -@@ -194,13 +188,9 @@ - * - * Read one packet from a UDP socket - */ --int udp_read(buf, bufsize, timeout, abortch) --char *buf; --int bufsize; --int timeout; --char abortch; -+int udp_read(char *buf, unsigned int bufsize, int timeout) - { -- int len; -+ unsigned int len; - - /* Wait until we get something */ - set_timeout(timeout); -@@ -299,9 +289,6 @@ - */ - int init_udp() - { -- /* Set module name for error handling */ -- net_module_name = "udp"; -- - /* Register IP packet type and set write buffer pointer */ - if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) - return(FALSE); -diff -ruN proll_18.orig/src/udp.h proll-patch-15/src/udp.h ---- proll_18.orig/src/udp.h 2001-12-24 05:12:34.000000000 +0000 -+++ proll-patch-15/src/udp.h 2005-08-14 10:16:40.000000000 +0000 -@@ -53,7 +53,7 @@ - extern int udp_open __P((t_ipaddr daddr, int source, int dest)); - - /* Read from a UDP socket */ --extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch)); -+extern int udp_read(char *buf, unsigned int bufsize, int timeout); - - /* Write to a UDP socket */ - extern int udp_write __P((char *buf, int writelen)); -diff -ruN proll_18.orig/src/vcons_zs.c proll-patch-15/src/vcons_zs.c ---- proll_18.orig/src/vcons_zs.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/vcons_zs.c 2005-08-14 10:25:51.000000000 +0000 -@@ -0,0 +1,68 @@ -+/** -+ ** Console over 'zs' (Zilog serial port) -+ ** Copyright 1999 Pete Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+ -+#include "vconsole.h" -+#include -+ -+#define ZS_DATA 0x02 -+ -+int vcon_zs_init(struct vconterm *t, unsigned int a0) -+{ -+ -+ t->impl = (void *) a0; -+ -+ t->vc_x = 0; t->vc_y = 0; -+ t->backp = 0; t->backc = 0; -+ -+ stb_bypass(a0, 3); // reg 3 -+ stb_bypass(a0, 1); // enable rx -+ -+ stb_bypass(a0, 5); // reg 5 -+ stb_bypass(a0, 8); // enable tx -+ -+ return 0; -+} -+ -+int vcon_zs_putch(struct vconterm *t, char c) -+{ -+ unsigned zs_ptr = (unsigned) t->impl; -+ -+ //while ((ldb_bypass(zs_ptr + ZS_LSR) & 0x60) != 0x60) { } -+ stb_bypass(zs_ptr + ZS_DATA, c); -+ return 0; -+} -+ -+int vcon_zs_write(struct vconterm *t, char *data, int leng) -+{ -+ while (leng != 0) { -+ leng--; -+ vcon_zs_putch(t, *data++); -+ } -+ return leng; -+} -+ -+int vcon_zs_read(struct vconterm *t, char *data, __attribute((unused)) int leng) -+{ -+ unsigned zs_ptr = (unsigned) t->impl; -+ -+ while ((ldb_bypass(zs_ptr) & 1) != 1) { } -+ *data = ldb_bypass(zs_ptr + ZS_DATA); -+ return 0; -+} -+ -+int vcon_zs_getch(struct vconterm *t) -+{ -+ unsigned zs_ptr = (unsigned) t->impl; -+ -+ while ((ldb_bypass(zs_ptr) & 1) != 1) { } -+ return ldb_bypass(zs_ptr + ZS_DATA) & 0xff; -+} -+ -+void vcon_zs_fini(__attribute((unused)) struct vconterm *t) -+{ -+ /* violent crash in the end */ -+ ; -+} -diff -ruN proll_18.orig/src/vconsole.c proll-patch-15/src/vconsole.c ---- proll_18.orig/src/vconsole.c 1999-11-08 03:10:28.000000000 +0000 -+++ proll-patch-15/src/vconsole.c 2005-08-14 10:24:49.000000000 +0000 -@@ -7,12 +7,17 @@ - #include "vconsole.h" - - #include "hconsole.h" -+#include - - static void vcon_i_cursfeed(struct vconterm *t); - static void vcon_i_backflush(struct vconterm *t); - - struct hconsole hcons0; - -+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, -+ EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, -+ ESpalette }; -+ - int vcon_init(struct vconterm *t, unsigned int a0) - { - struct hconsole *hconp; -@@ -25,11 +30,49 @@ - - t->vc_x = 0; t->vc_y = 0; - t->backp = 0; t->backc = 0; -+ t->vc_state = ESnormal; - - hcon_clear(hconp, 0, 0, hconp->ydim_, hconp->xdim_); - return 0; - } - -+/* -+ * gotoxy() must verify all boundaries, because the arguments -+ * might also be negative. If the given position is out of -+ * bounds, the cursor is placed at the nearest margin. -+ */ -+static void gotoxy(struct vconterm *vc, int new_x, int new_y) -+{ -+ int max_x, max_y; -+ struct hconsole *hconp = vc->impl; -+ -+ max_x = hcon_qxdim(hconp); -+ max_y = hcon_qydim(hconp); -+ -+ if (new_x < 0) -+ vc->vc_x = 0; -+ else { -+ if (new_x >= max_x) -+ vc->vc_x = max_x - 1; -+ else -+ vc->vc_x = new_x; -+ } -+ -+ if (new_y < 0) -+ vc->vc_y = 0; -+ else if (new_y >= max_y) -+ vc->vc_y = max_y - 1; -+ else -+ vc->vc_y = new_y; -+ -+} -+ -+/* for absolute user moves, when decom is set */ -+static void gotoxay(struct vconterm *t, int new_x, int new_y) -+{ -+ gotoxy(t, new_x, new_y); -+} -+ - int vcon_write(struct vconterm *t, char *data, int leng) - { - int l = leng; -@@ -40,29 +83,101 @@ - if (l <= 0) break; - c = *data++; --l; - -- switch (c) { -- case 0x07: /* Bell */ -- vcon_i_backflush(t); -- break; -- case 0x0A: /* Linefeed */ -- vcon_i_backflush(t); -- vcon_i_cursfeed(t); -+ switch(t->vc_state) { -+ case ESesc: -+ t->vc_state = ESnormal; -+ switch (c) { -+ case '[': -+ t->vc_state = ESsquare; -+ break; -+ case 'M': -+ hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); -+ break; -+ default: -+ //printk("Unhandled escape code '%c'\n", c); -+ break; -+ } - break; -- case 0x0D: /* Return */ -- vcon_i_backflush(t); -- t->vc_x = 0; -+ case ESsquare: -+ for(t->vc_npar = 0 ; t->vc_npar < NPAR ; t->vc_npar++) -+ t->vc_par[t->vc_npar] = 0; -+ t->vc_npar = 0; -+ t->vc_state = ESgetpars; -+ case ESgetpars: -+ if (c==';' && t->vc_nparvc_npar++; -+ break; -+ } else if (c>='0' && c<='9') { -+ t->vc_par[t->vc_npar] *= 10; -+ t->vc_par[t->vc_npar] += c-'0'; -+ break; -+ } else t->vc_state=ESgotpars; -+ case ESgotpars: -+ t->vc_state = ESnormal; -+ switch(c) { -+ case 'H': case 'f': -+ if (t->vc_par[0]) t->vc_par[0]--; -+ if (t->vc_par[1]) t->vc_par[1]--; -+ gotoxay(t, t->vc_par[1], t->vc_par[0]); -+ break; -+ case 'J': -+ if (t->vc_par[0] == 0) { -+ //erase from cursor to end of display -+ hcon_clear(hconp, t->vc_y, t->vc_x, hconp->ydim_, hconp->xdim_); -+ } -+ break; -+ case 'M': -+ hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); -+ break; -+ case 'm': -+ break; -+ default: -+#if 0 -+ printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n", -+ c, t->vc_par[0], t->vc_par[1], t->vc_par[2], t->vc_par[3], t->vc_par[4]); -+#endif -+ break; -+ } - break; - default: -- if (t->backp == 0) { -- t->backc = 1; -- t->backp = data-1; -- } else { -- t->backc++; -- } -- if (t->vc_x + t->backc >= hcon_qxdim(hconp)) { -+ t->vc_state = ESnormal; -+ switch (c) { -+ case 0x07: /* Bell */ -+ vcon_i_backflush(t); -+ break; -+ case 0x08: /* BS */ -+ vcon_i_backflush(t); -+ if (t->vc_x > 0) -+ t->vc_x--; -+ break; -+ case 0x0A: /* Linefeed */ - vcon_i_backflush(t); -- t->vc_x = 0; - vcon_i_cursfeed(t); -+ break; -+ case 0x0D: /* Return */ -+ vcon_i_backflush(t); -+ t->vc_x = 0; -+ break; -+ case 24: case 26: -+ vcon_i_backflush(t); -+ t->vc_state = ESnormal; -+ break; -+ case 27: -+ vcon_i_backflush(t); -+ t->vc_state = ESesc; -+ break; -+ default: -+ if (t->backp == 0) { -+ t->backc = 1; -+ t->backp = data-1; -+ } else { -+ t->backc++; -+ } -+ if ((unsigned int)t->vc_x + t->backc >= hcon_qxdim(hconp)) { -+ vcon_i_backflush(t); -+ t->vc_x = 0; -+ vcon_i_cursfeed(t); -+ } - } - } - } -@@ -73,7 +188,7 @@ - static void vcon_i_cursfeed(struct vconterm *t) { - struct hconsole *hconp = t->impl; - -- if (++t->vc_y >= hcon_qydim(hconp)) { -+ if ((unsigned int)++t->vc_y >= hcon_qydim(hconp)) { - t->vc_y = hcon_qydim(hconp)-1; - hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); - } -@@ -90,22 +205,75 @@ - t->backp = 0; t->backc = 0; - } - --int vcon_putch(struct vconterm *t, char c) -+int vcon_putch(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char c) - { - return -1; - } - --int vcon_read(struct vconterm *t, char *data, int leng) -+int vcon_read(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char *data, __attribute__((unused)) int leng) - { - return 0; - } - --int vcon_getch(struct vconterm *t) -+static const unsigned char sunkbd_keycode[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 8, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\\', 13, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ ' ', -+}; -+ -+static const unsigned char sunkbd_keycode_shifted[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 8, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', 13, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ ' ', -+}; -+ -+static int shiftstate; -+ -+int vcon_getch(__attribute__((unused)) struct vconterm *t) - { -- return -1; -+ int ch; -+ -+ while ((ldb_bypass(0x71000004) & 1) != 1) { } -+ do { -+ ch = ldb_bypass(0x71000006) & 0xff; -+ if (ch == 99) -+ shiftstate |= 1; -+ else if (ch == 110) -+ shiftstate |= 2; -+ else if (ch == 227) -+ shiftstate &= ~1; -+ else if (ch == 238) -+ shiftstate &= ~2; -+ //printk("getch: %d\n", ch); -+ } -+ while ((ch & 0x80) == 0 || ch == 238 || ch == 227); // Wait for key release -+ //printk("getch rel: %d\n", ch); -+ ch &= 0x7f; -+ if (shiftstate) -+ ch = sunkbd_keycode_shifted[ch]; -+ else -+ ch = sunkbd_keycode[ch]; -+ //printk("getch xlate: %d\n", ch); -+ return ch; - } - --void vcon_fini(struct vconterm *t) -+void vcon_fini(__attribute__((unused)) struct vconterm *t) - { - /* violent crash in the end */ - ; -diff -ruN proll_18.orig/src/vconsole.h proll-patch-15/src/vconsole.h ---- proll_18.orig/src/vconsole.h 1999-11-08 00:58:13.000000000 +0000 -+++ proll-patch-15/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 -@@ -6,6 +6,8 @@ - #ifndef VCONSOLE_H - #define VCONSOLE_H - -+#define NPAR 16 -+ - struct vconterm { - void *impl; - -@@ -13,6 +15,8 @@ - int backc; /* Same, count */ - - int vc_x, vc_y; /* XXX Make vcon_xxx() to use cellmap->xpos_ */ -+ int vc_state; -+ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ - }; - - int vcon_init(struct vconterm *t, unsigned int a0); From ae5534e54e593ea9dab82f555b2593d06b089e1b Mon Sep 17 00:00:00 2001 From: "chris@kneesaa.uk.xensource.com" Date: Mon, 7 Aug 2006 18:28:50 +0100 Subject: [PATCH 111/111] [qemu patches] Update patches for changesets 10957:08a11694b109 - 10959:06e2a95d3395. Signed-off-by: Christian Limpach --- tools/ioemu/patches/acpi-poweroff-support | 10 +- tools/ioemu/patches/acpi-support | 159 +++++++++--------- tools/ioemu/patches/acpi-timer-support | 4 +- tools/ioemu/patches/domain-destroy | 27 +-- tools/ioemu/patches/domain-reset | 18 +- tools/ioemu/patches/domain-timeoffset | 48 +++--- tools/ioemu/patches/hypervisor-pit | 24 +-- tools/ioemu/patches/ide-hd-multithread | 27 +-- tools/ioemu/patches/ioemu-ia64 | 34 ++-- tools/ioemu/patches/qemu-64bit | 38 ++--- tools/ioemu/patches/qemu-allow-disable-sdl | 8 +- tools/ioemu/patches/qemu-bugfixes | 30 +--- tools/ioemu/patches/qemu-cleanup | 28 +-- tools/ioemu/patches/qemu-dm | 140 +++++++-------- tools/ioemu/patches/qemu-fix-memset-args | 6 +- .../qemu-fix-write-to-disk-synchronous | 26 +-- tools/ioemu/patches/qemu-hvm-banner | 6 +- tools/ioemu/patches/qemu-init-vgabios | 8 +- tools/ioemu/patches/qemu-logging | 31 ++-- tools/ioemu/patches/qemu-no-apic | 22 +-- tools/ioemu/patches/qemu-nobios | 21 +-- tools/ioemu/patches/qemu-smp | 22 +-- tools/ioemu/patches/qemu-target-i386-dm | 64 +++---- tools/ioemu/patches/qemu-timer | 16 +- tools/ioemu/patches/serial-non-block | 6 +- tools/ioemu/patches/series | 1 - tools/ioemu/patches/shadow-vram | 16 +- tools/ioemu/patches/shared-vram | 38 ++--- tools/ioemu/patches/support-xm-console | 8 +- tools/ioemu/patches/vnc-access-monitor-vt | 21 +-- tools/ioemu/patches/vnc-cleanup | 24 +-- tools/ioemu/patches/vnc-fixes | 127 ++++++++------ tools/ioemu/patches/vnc-start-vncviewer | 54 +++--- tools/ioemu/patches/vnc-title-domain-name | 8 +- tools/ioemu/patches/xen-build | 71 ++++---- tools/ioemu/patches/xen-domain-name | 36 ++-- tools/ioemu/patches/xen-domid | 20 +-- tools/ioemu/patches/xen-mm | 31 ++-- tools/ioemu/patches/xen-network | 14 +- .../patches/xenstore-block-device-config | 88 +++++----- tools/ioemu/patches/xenstore-write-vnc-port | 16 +- 41 files changed, 709 insertions(+), 687 deletions(-) diff --git a/tools/ioemu/patches/acpi-poweroff-support b/tools/ioemu/patches/acpi-poweroff-support index 73dd7bb50f..9bec3091a6 100644 --- a/tools/ioemu/patches/acpi-poweroff-support +++ b/tools/ioemu/patches/acpi-poweroff-support @@ -1,10 +1,10 @@ Index: ioemu/hw/piix4acpi.c =================================================================== ---- ioemu.orig/hw/piix4acpi.c 2006-07-12 11:35:03.574468946 +0100 -+++ ioemu/hw/piix4acpi.c 2006-07-12 11:35:03.631461806 +0100 +--- ioemu.orig/hw/piix4acpi.c 2006-08-06 02:30:29.288761563 +0100 ++++ ioemu/hw/piix4acpi.c 2006-08-06 02:30:42.131331446 +0100 @@ -45,6 +45,10 @@ #define GBL_RLS (1 << 2) - #define SLP_EN (1 << 13) + #define SLP_EN (1 << 13) +/* Bits of PM1a register define here */ +#define SLP_TYP_MASK 0x1C00 @@ -13,7 +13,7 @@ Index: ioemu/hw/piix4acpi.c typedef struct AcpiDeviceState AcpiDeviceState; AcpiDeviceState *acpi_device_table; -@@ -270,7 +274,14 @@ +@@ -190,7 +194,14 @@ s->pm1_control = (val<<8)||(s->pm1_control); /* printf("acpiPm1ControlP1_writeb \n addr %x val:%x\n", addr, val); */ @@ -29,7 +29,7 @@ Index: ioemu/hw/piix4acpi.c static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr) { -@@ -337,7 +348,14 @@ +@@ -257,7 +268,14 @@ s->pm1_control = val; /* printf("acpiPm1Control_writew \n addr %x val:%x\n", addr, val); */ diff --git a/tools/ioemu/patches/acpi-support b/tools/ioemu/patches/acpi-support index c0b422bf5d..98eee53d82 100644 --- a/tools/ioemu/patches/acpi-support +++ b/tools/ioemu/patches/acpi-support @@ -1,94 +1,50 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-03 19:19:39.000000000 +0100 -+++ ioemu/Makefile.target 2006-08-04 10:35:36.445703379 +0100 -@@ -335,6 +335,7 @@ - VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +--- ioemu.orig/Makefile.target 2006-08-06 02:23:23.000000000 +0100 ++++ ioemu/Makefile.target 2006-08-07 17:38:47.698306442 +0100 +@@ -357,6 +357,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o - VL_OBJS+= cirrus_vga.o mixeng.o parallel.o + VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o + VL_OBJS+= usb-uhci.o +VL_OBJS+= piix4acpi.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-03 19:19:39.000000000 +0100 -+++ ioemu/hw/pc.c 2006-08-04 10:38:05.559415853 +0100 -@@ -566,6 +566,9 @@ +--- ioemu.orig/hw/pc.c 2006-08-06 02:23:45.000000000 +0100 ++++ ioemu/hw/pc.c 2006-08-07 17:42:00.939426374 +0100 +@@ -572,6 +572,9 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; +/* PIIX4 acpi pci configuration space, func 3 */ -+extern void pci_piix4_acpi_init(PCIBus *bus); ++extern void pci_piix4_acpi_init(PCIBus *bus, int devfn); + #ifdef HAS_AUDIO static void audio_init (PCIBus *pci_bus) { -@@ -867,6 +870,10 @@ +@@ -874,11 +877,15 @@ cmos_init(ram_size, boot_device, bs_table, timeoffset); + /* using PIIX4 acpi model */ + if (pci_enabled && acpi_enabled) -+ pci_piix4_acpi_init(pci_bus); ++ pci_piix4_acpi_init(pci_bus, piix3_devfn + 3); + if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, usb_root_ports); - usb_attach(usb_root_ports[0], vm_usb_hub); -Index: ioemu/hw/pci.c -=================================================================== ---- ioemu.orig/hw/pci.c 2006-08-03 19:19:35.000000000 +0100 -+++ ioemu/hw/pci.c 2006-08-03 19:19:39.000000000 +0100 -@@ -1697,7 +1697,7 @@ - static uint32_t pci_bios_io_addr; - static uint32_t pci_bios_mem_addr; - /* host irqs corresponding to PCI irqs A-D */ --static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; -+static uint8_t pci_irqs[4] = { 10, 11, 10, 11 }; - - static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) - { -@@ -1750,12 +1750,22 @@ - pci_set_io_region_addr(d, 3, 0x374); - } - break; -+ case 0x0680: -+ if (vendor_id == 0x8086 && device_id == 0x7113) { -+ // PIIX4 ACPI PM -+ pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 -+ pci_config_writew(d, 0x22, 0x0000); -+ goto default_map; -+ } -+ break; -+ - case 0x0300: - if (vendor_id != 0x1234) - goto default_map; - /* VGA: map frame buffer to default Bochs VBE address */ - pci_set_io_region_addr(d, 0, 0xE0000000); - break; -+ - case 0x0800: - /* PIC */ - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); -@@ -1800,6 +1810,13 @@ - pic_irq = pci_irqs[pin]; - pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); + usb_uhci_init(pci_bus, piix3_devfn + 2); + } + +- if (pci_enabled && acpi_enabled) { ++ if (pci_enabled && acpi_enabled && 0) { + piix4_pm_init(pci_bus, piix3_devfn + 3); } -+ if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) { -+ // PIIX4 ACPI PM -+ pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 -+ pci_config_writew(d, 0x22, 0x0000); -+ pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9 -+ pci_config_writew(d, 0x3d, 0x0001); -+ } - } - /* Index: ioemu/hw/piix4acpi.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/hw/piix4acpi.c 2006-08-04 10:35:36.762666604 +0100 ++++ ioemu/hw/piix4acpi.c 2006-08-07 17:41:41.932577728 +0100 @@ -0,0 +1,388 @@ +/* + * PIIX4 ACPI controller emulation @@ -450,7 +406,7 @@ Index: ioemu/hw/piix4acpi.c + + +/* PIIX4 acpi pci configuration space, func 3 */ -+void pci_piix4_acpi_init(PCIBus *bus) ++void pci_piix4_acpi_init(PCIBus *bus, int devfn) +{ + PCIAcpiState *d; + uint8_t *pci_conf; @@ -458,7 +414,7 @@ Index: ioemu/hw/piix4acpi.c + /* register a function 3 of PIIX4 */ + d = (PCIAcpiState *)pci_register_device( + bus, "PIIX4 ACPI", sizeof(PCIAcpiState), -+ ((PCIDevice *)piix3_state)->devfn + 3, NULL, NULL); ++ devfn, NULL, NULL); + + acpi_state = d; + pci_conf = d->dev.config; @@ -480,18 +436,18 @@ Index: ioemu/hw/piix4acpi.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:35:36.697674145 +0100 -+++ ioemu/vl.c 2006-08-04 10:37:38.001608828 +0100 -@@ -166,6 +166,8 @@ - - time_t timeoffset = 0; - +--- ioemu.orig/vl.c 2006-08-06 02:23:45.000000000 +0100 ++++ ioemu/vl.c 2006-08-07 17:41:40.613727012 +0100 +@@ -156,7 +156,7 @@ + #else + #define MAX_CPUS 1 + #endif +-int acpi_enabled = 1; +int acpi_enabled = 0; -+ - char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; - extern int domid; + int fd_bootchk = 1; -@@ -4803,6 +4805,7 @@ + extern int vcpus; +@@ -5341,6 +5341,7 @@ "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" "-timeoffset time offset (in seconds) from local time\n" @@ -499,7 +455,7 @@ Index: ioemu/vl.c "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" -@@ -4894,6 +4897,7 @@ +@@ -5426,6 +5427,7 @@ QEMU_OPTION_d, QEMU_OPTION_vcpus, QEMU_OPTION_timeoffset, @@ -507,7 +463,7 @@ Index: ioemu/vl.c }; typedef struct QEMUOption { -@@ -4973,6 +4977,7 @@ +@@ -5509,6 +5511,7 @@ { "d", HAS_ARG, QEMU_OPTION_d }, { "vcpus", 1, QEMU_OPTION_vcpus }, { "timeoffset", HAS_ARG, QEMU_OPTION_timeoffset }, @@ -515,7 +471,7 @@ Index: ioemu/vl.c { NULL }, }; -@@ -5678,6 +5683,9 @@ +@@ -6256,6 +6259,9 @@ case QEMU_OPTION_timeoffset: timeoffset = strtol(optarg, NULL, 0); break; @@ -527,9 +483,9 @@ Index: ioemu/vl.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:35:36.629682033 +0100 -+++ ioemu/vl.h 2006-08-04 10:36:21.513475699 +0100 -@@ -159,6 +159,7 @@ +--- ioemu.orig/vl.h 2006-08-06 02:23:45.000000000 +0100 ++++ ioemu/vl.h 2006-08-07 17:38:47.847289567 +0100 +@@ -167,6 +167,7 @@ extern int kqemu_allowed; extern int win2k_install_hack; extern int usb_enabled; @@ -537,3 +493,46 @@ Index: ioemu/vl.h extern int smp_cpus; /* XXX: make it dynamic */ +Index: ioemu/hw/piix_pci.c +=================================================================== +--- ioemu.orig/hw/piix_pci.c 2006-08-06 02:29:41.000000000 +0100 ++++ ioemu/hw/piix_pci.c 2006-08-07 17:38:57.480198468 +0100 +@@ -241,7 +241,7 @@ + static uint32_t pci_bios_io_addr; + static uint32_t pci_bios_mem_addr; + /* host irqs corresponding to PCI irqs A-D */ +-static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; ++static uint8_t pci_irqs[4] = { 10, 11, 10, 11 }; + + static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) + { +@@ -336,6 +336,14 @@ + pci_set_io_region_addr(d, 3, 0x374); + } + break; ++ case 0x0680: ++ if (vendor_id == 0x8086 && device_id == 0x7113) { ++ /* PIIX4 ACPI PM */ ++ pci_config_writew(d, 0x20, 0x0000); /* NO smb bus IO enable in PIIX4 */ ++ pci_config_writew(d, 0x22, 0x0000); ++ goto default_map; ++ } ++ break; + case 0x0300: + if (vendor_id != 0x1234) + goto default_map; +@@ -386,6 +394,14 @@ + pic_irq = pci_irqs[pin]; + pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); + } ++ ++ if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) { ++ // PIIX4 ACPI PM ++ pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 ++ pci_config_writew(d, 0x22, 0x0000); ++ pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9 ++ pci_config_writew(d, 0x3d, 0x0001); ++ } + } + + /* diff --git a/tools/ioemu/patches/acpi-timer-support b/tools/ioemu/patches/acpi-timer-support index dabe65a276..3fcb8e489a 100644 --- a/tools/ioemu/patches/acpi-timer-support +++ b/tools/ioemu/patches/acpi-timer-support @@ -1,7 +1,7 @@ Index: ioemu/hw/piix4acpi.c =================================================================== ---- ioemu.orig/hw/piix4acpi.c 2006-08-04 10:57:28.922994985 +0100 -+++ ioemu/hw/piix4acpi.c 2006-08-04 11:35:15.177574467 +0100 +--- ioemu.orig/hw/piix4acpi.c 2006-08-06 02:24:54.262068457 +0100 ++++ ioemu/hw/piix4acpi.c 2006-08-06 02:30:29.288761563 +0100 @@ -24,31 +24,30 @@ */ diff --git a/tools/ioemu/patches/domain-destroy b/tools/ioemu/patches/domain-destroy index 033ee1bc52..a1ccde7c1b 100644 --- a/tools/ioemu/patches/domain-destroy +++ b/tools/ioemu/patches/domain-destroy @@ -1,7 +1,8 @@ -diff -r e1dce5114e92 monitor.c ---- a/monitor.c Mon Jun 26 16:04:15 2006 +0100 -+++ b/monitor.c Mon Jun 26 16:04:26 2006 +0100 -@@ -306,6 +306,7 @@ static void do_info_history (void) +Index: ioemu/monitor.c +=================================================================== +--- ioemu.orig/monitor.c 2006-08-06 02:22:01.487319736 +0100 ++++ ioemu/monitor.c 2006-08-06 02:23:02.269544103 +0100 +@@ -308,6 +308,7 @@ static void do_quit(void) { @@ -9,10 +10,11 @@ diff -r e1dce5114e92 monitor.c exit(0); } -diff -r e1dce5114e92 target-i386-dm/helper2.c ---- a/target-i386-dm/helper2.c Mon Jun 26 16:04:15 2006 +0100 -+++ b/target-i386-dm/helper2.c Mon Jun 26 16:04:26 2006 +0100 -@@ -483,5 +483,25 @@ int main_loop(void) +Index: ioemu/target-i386-dm/helper2.c +=================================================================== +--- ioemu.orig/target-i386-dm/helper2.c 2006-08-06 02:22:59.251880493 +0100 ++++ ioemu/target-i386-dm/helper2.c 2006-08-06 02:23:02.270543991 +0100 +@@ -483,5 +483,25 @@ shared_page->vcpu_iodata[send_vcpu].dm_eport); } } @@ -38,10 +40,11 @@ diff -r e1dce5114e92 target-i386-dm/helper2.c + xc_interface_close(xcHandle); + } +} -diff -r e1dce5114e92 vl.h ---- a/vl.h Mon Jun 26 16:04:15 2006 +0100 -+++ b/vl.h Mon Jun 26 16:04:26 2006 +0100 -@@ -1098,4 +1098,7 @@ void kqemu_record_dump(void); +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-08-06 02:22:59.255880047 +0100 ++++ ioemu/vl.h 2006-08-06 02:23:02.271543880 +0100 +@@ -1189,4 +1189,7 @@ void kqemu_record_dump(void); extern char domain_name[]; diff --git a/tools/ioemu/patches/domain-reset b/tools/ioemu/patches/domain-reset index f079669f9f..4ff8d90281 100644 --- a/tools/ioemu/patches/domain-reset +++ b/tools/ioemu/patches/domain-reset @@ -1,7 +1,7 @@ Index: ioemu/target-i386-dm/helper2.c =================================================================== ---- ioemu.orig/target-i386-dm/helper2.c 2006-07-27 11:16:57.527492229 +0100 -+++ ioemu/target-i386-dm/helper2.c 2006-07-27 11:16:59.381287013 +0100 +--- ioemu.orig/target-i386-dm/helper2.c 2006-08-06 02:21:15.779415007 +0100 ++++ ioemu/target-i386-dm/helper2.c 2006-08-06 02:22:59.251880493 +0100 @@ -123,6 +123,25 @@ /* called from main_cpu_reset */ void cpu_reset(CPUX86State *env) @@ -41,9 +41,9 @@ Index: ioemu/target-i386-dm/helper2.c /* Wait up to 10 msec. */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:59.317294097 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:59.384286681 +0100 -@@ -4412,7 +4412,7 @@ +--- ioemu.orig/vl.c 2006-08-06 02:22:56.618174081 +0100 ++++ ioemu/vl.c 2006-08-06 02:22:59.254880158 +0100 +@@ -4948,7 +4948,7 @@ } QEMUResetEntry; static QEMUResetEntry *first_reset_entry; @@ -54,9 +54,9 @@ Index: ioemu/vl.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-27 11:16:58.127425816 +0100 -+++ ioemu/vl.h 2006-07-27 11:16:59.384286681 +0100 -@@ -122,6 +122,7 @@ +--- ioemu.orig/vl.h 2006-08-06 02:22:01.501318175 +0100 ++++ ioemu/vl.h 2006-08-06 02:22:59.255880047 +0100 +@@ -130,6 +130,7 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque); void qemu_system_reset_request(void); @@ -64,7 +64,7 @@ Index: ioemu/vl.h void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); #if !defined(TARGET_SPARC) -@@ -131,6 +132,8 @@ +@@ -139,6 +140,8 @@ void qemu_system_powerdown(void); #endif diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset index ec526bb4ff..0ae6d3c789 100644 --- a/tools/ioemu/patches/domain-timeoffset +++ b/tools/ioemu/patches/domain-timeoffset @@ -1,7 +1,7 @@ Index: ioemu/hw/mc146818rtc.c =================================================================== ---- ioemu.orig/hw/mc146818rtc.c 2006-08-04 10:57:22.049787220 +0100 -+++ ioemu/hw/mc146818rtc.c 2006-08-04 10:57:28.677023336 +0100 +--- ioemu.orig/hw/mc146818rtc.c 2006-08-07 17:44:43.593604340 +0100 ++++ ioemu/hw/mc146818rtc.c 2006-08-07 17:44:47.594168708 +0100 @@ -178,10 +178,27 @@ } } @@ -46,9 +46,9 @@ Index: ioemu/hw/mc146818rtc.c static void rtc_copy_date(RTCState *s) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-04 10:57:28.406054568 +0100 -+++ ioemu/hw/pc.c 2006-08-04 10:57:28.678023221 +0100 -@@ -151,7 +151,7 @@ +--- ioemu.orig/hw/pc.c 2006-08-07 17:44:47.324198106 +0100 ++++ ioemu/hw/pc.c 2006-08-07 17:44:54.830380715 +0100 +@@ -159,7 +159,7 @@ } /* hd_table must contain 4 block drivers */ @@ -57,7 +57,7 @@ Index: ioemu/hw/pc.c { RTCState *s = rtc_state; int val; -@@ -162,6 +162,7 @@ +@@ -170,6 +170,7 @@ /* set the CMOS date */ time(&ti); @@ -65,7 +65,7 @@ Index: ioemu/hw/pc.c if (rtc_utc) tm = gmtime(&ti); else -@@ -613,7 +614,7 @@ +@@ -619,7 +620,7 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -74,7 +74,7 @@ Index: ioemu/hw/pc.c int pci_enabled) { #ifndef NOBIOS -@@ -864,7 +865,7 @@ +@@ -871,7 +872,7 @@ floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); @@ -82,8 +82,8 @@ Index: ioemu/hw/pc.c + cmos_init(ram_size, boot_device, bs_table, timeoffset); if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, usb_root_ports); -@@ -883,12 +884,13 @@ + usb_uhci_init(pci_bus, piix3_devfn + 2); +@@ -912,12 +913,13 @@ int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -99,7 +99,7 @@ Index: ioemu/hw/pc.c } static void pc_init_isa(uint64_t ram_size, int vga_ram_size, int boot_device, -@@ -896,12 +898,13 @@ +@@ -925,12 +927,13 @@ int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -117,9 +117,9 @@ Index: ioemu/hw/pc.c QEMUMachine pc_machine = { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:57:28.545038549 +0100 -+++ ioemu/vl.c 2006-08-04 10:57:28.680022990 +0100 -@@ -164,6 +164,8 @@ +--- ioemu.orig/vl.c 2006-08-07 17:44:47.464182863 +0100 ++++ ioemu/vl.c 2006-08-07 17:44:54.830380715 +0100 +@@ -163,6 +163,8 @@ int xc_handle; @@ -128,7 +128,7 @@ Index: ioemu/vl.c char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; extern int domid; -@@ -4800,6 +4802,7 @@ +@@ -5338,6 +5340,7 @@ #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" @@ -136,7 +136,7 @@ Index: ioemu/vl.c "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" -@@ -4890,6 +4893,7 @@ +@@ -5422,6 +5425,7 @@ QEMU_OPTION_d, QEMU_OPTION_vcpus, @@ -144,7 +144,7 @@ Index: ioemu/vl.c }; typedef struct QEMUOption { -@@ -4968,6 +4972,7 @@ +@@ -5504,6 +5508,7 @@ { "d", HAS_ARG, QEMU_OPTION_d }, { "vcpus", 1, QEMU_OPTION_vcpus }, @@ -152,7 +152,7 @@ Index: ioemu/vl.c { NULL }, }; -@@ -5670,6 +5675,9 @@ +@@ -6248,6 +6253,9 @@ vcpus = atoi(optarg); fprintf(logfile, "qemu: the number of cpus is %d\n", vcpus); break; @@ -162,7 +162,7 @@ Index: ioemu/vl.c } } } -@@ -6007,7 +6015,8 @@ +@@ -6489,7 +6497,8 @@ machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, @@ -170,13 +170,13 @@ Index: ioemu/vl.c + kernel_filename, kernel_cmdline, initrd_filename, + timeoffset); - gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); - qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); + /* init USB devices */ + if (usb_enabled) { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:57:28.411053992 +0100 -+++ ioemu/vl.h 2006-08-04 10:57:28.681022875 +0100 -@@ -556,7 +556,7 @@ +--- ioemu.orig/vl.h 2006-08-07 17:44:47.329197562 +0100 ++++ ioemu/vl.h 2006-08-07 17:44:54.830380715 +0100 +@@ -575,7 +575,7 @@ int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, diff --git a/tools/ioemu/patches/hypervisor-pit b/tools/ioemu/patches/hypervisor-pit index 1b5f9a1bdf..a783ff6756 100644 --- a/tools/ioemu/patches/hypervisor-pit +++ b/tools/ioemu/patches/hypervisor-pit @@ -1,20 +1,20 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-07-27 11:16:58.970332506 +0100 -+++ ioemu/Makefile.target 2006-07-27 11:16:59.758245283 +0100 -@@ -333,7 +333,7 @@ +--- ioemu.orig/Makefile.target 2006-08-06 02:22:26.380544784 +0100 ++++ ioemu/Makefile.target 2006-08-06 02:23:23.059226607 +0100 +@@ -354,7 +354,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8254.o pcspk.o pc.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o - VL_OBJS+= cirrus_vga.o mixeng.o parallel.o + VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o + VL_OBJS+= usb-uhci.o DEFINES += -DHAS_AUDIO - endif Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-27 11:16:59.036325200 +0100 -+++ ioemu/hw/pc.c 2006-07-27 11:16:59.759245173 +0100 +--- ioemu.orig/hw/pc.c 2006-08-06 02:22:35.588518336 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:23:07.875919141 +0100 @@ -38,7 +38,9 @@ static fdctrl_t *floppy_controller; @@ -25,7 +25,7 @@ Index: ioemu/hw/pc.c #ifndef CONFIG_DM static IOAPICState *ioapic; #endif /* !CONFIG_DM */ -@@ -803,8 +805,10 @@ +@@ -810,8 +812,10 @@ } #endif /* !CONFIG_DM */ isa_pic = pic_init(pic_irq_request, first_cpu); @@ -38,9 +38,9 @@ Index: ioemu/hw/pc.c pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:59.614261222 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:59.762244841 +0100 -@@ -5034,6 +5034,7 @@ +--- ioemu.orig/vl.c 2006-08-06 02:23:05.216215627 +0100 ++++ ioemu/vl.c 2006-08-06 02:23:07.878918807 +0100 +@@ -5570,6 +5570,7 @@ #ifdef HAS_AUDIO struct soundhw soundhw[] = { @@ -48,7 +48,7 @@ Index: ioemu/vl.c #ifdef TARGET_I386 { "pcspk", -@@ -5043,6 +5044,7 @@ +@@ -5579,6 +5580,7 @@ { .init_isa = pcspk_audio_init } }, #endif diff --git a/tools/ioemu/patches/ide-hd-multithread b/tools/ioemu/patches/ide-hd-multithread index 172fa146cc..cc64837b53 100644 --- a/tools/ioemu/patches/ide-hd-multithread +++ b/tools/ioemu/patches/ide-hd-multithread @@ -1,6 +1,7 @@ -diff -r d711aa4fa261 hw/ide.c ---- a/hw/ide.c Fri Jun 16 10:13:37 2006 +0200 -+++ b/hw/ide.c Fri Jun 16 10:30:28 2006 +0200 +Index: ioemu/hw/ide.c +=================================================================== +--- ioemu.orig/hw/ide.c 2006-08-06 02:03:50.520919718 +0100 ++++ ioemu/hw/ide.c 2006-08-06 02:23:41.153209614 +0100 @@ -22,6 +22,7 @@ * THE SOFTWARE. */ @@ -9,7 +10,7 @@ diff -r d711aa4fa261 hw/ide.c /* debug IDE devices */ //#define DEBUG_IDE -@@ -390,6 +391,48 @@ typedef struct PCIIDEState { +@@ -390,6 +391,48 @@ int type; /* see IDE_TYPE_xxx */ } PCIIDEState; @@ -58,7 +59,7 @@ diff -r d711aa4fa261 hw/ide.c static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb); static void padstr(char *str, const char *src, int len) -@@ -695,7 +738,9 @@ static int ide_read_dma_cb(IDEState *s, +@@ -695,7 +738,9 @@ } if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) { s->status = READY_STAT | SEEK_STAT; @@ -68,7 +69,7 @@ diff -r d711aa4fa261 hw/ide.c #ifdef DEBUG_IDE_ATAPI printf("dma status=0x%x\n", s->status); #endif -@@ -795,7 +840,11 @@ static int ide_write_dma_cb(IDEState *s, +@@ -795,7 +840,11 @@ qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); } else #endif @@ -80,7 +81,7 @@ diff -r d711aa4fa261 hw/ide.c return 0; } if (n > MAX_MULT_SECTORS) -@@ -1046,7 +1095,9 @@ static int ide_atapi_cmd_read_dma_cb(IDE +@@ -1046,7 +1095,9 @@ if (s->packet_transfer_size <= 0) { s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; @@ -90,7 +91,7 @@ diff -r d711aa4fa261 hw/ide.c #ifdef DEBUG_IDE_ATAPI printf("dma status=0x%x\n", s->status); #endif -@@ -2219,9 +2270,30 @@ static void ide_map(PCIDevice *pci_dev, +@@ -2103,9 +2154,30 @@ } } @@ -110,18 +111,18 @@ diff -r d711aa4fa261 hw/ide.c /* XXX: full callback usage to prepare non blocking I/Os support - error handling */ +#ifdef DMA_MULTI_THREAD - static void ide_dma_loop(BMDMAState *bm) ++static void ide_dma_loop(BMDMAState *bm) +{ + write(file_pipes[1], &bm, sizeof(bm)); +} +static void dma_thread_loop(BMDMAState *bm) +#else /* DMA_MULTI_THREAD */ -+static void ide_dma_loop(BMDMAState *bm) + static void ide_dma_loop(BMDMAState *bm) +#endif /* !DMA_MULTI_THREAD */ { struct { uint32_t addr; -@@ -2257,10 +2329,7 @@ static void ide_dma_loop(BMDMAState *bm) +@@ -2141,10 +2213,7 @@ } /* end of transfer */ the_end: @@ -133,7 +134,7 @@ diff -r d711aa4fa261 hw/ide.c } static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb) -@@ -2486,6 +2555,9 @@ void pci_cmd646_ide_init(PCIBus *bus, Bl +@@ -2370,6 +2439,9 @@ cmd646_set_irq, d, 0); ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], cmd646_set_irq, d, 1); @@ -143,7 +144,7 @@ diff -r d711aa4fa261 hw/ide.c } /* hd_table must contain 4 block drivers */ -@@ -2521,6 +2593,9 @@ void pci_piix3_ide_init(PCIBus *bus, Blo +@@ -2405,6 +2477,9 @@ pic_set_irq_new, isa_pic, 15); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); diff --git a/tools/ioemu/patches/ioemu-ia64 b/tools/ioemu/patches/ioemu-ia64 index bf8d4b04b5..23a7bbd402 100644 --- a/tools/ioemu/patches/ioemu-ia64 +++ b/tools/ioemu/patches/ioemu-ia64 @@ -1,7 +1,7 @@ Index: ioemu/hw/iommu.c =================================================================== ---- ioemu.orig/hw/iommu.c 2006-08-04 10:57:22.606723023 +0100 -+++ ioemu/hw/iommu.c 2006-08-04 10:57:27.489160251 +0100 +--- ioemu.orig/hw/iommu.c 2006-08-06 01:55:03.240628184 +0100 ++++ ioemu/hw/iommu.c 2006-08-06 02:18:54.843126039 +0100 @@ -82,7 +82,11 @@ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -16,8 +16,8 @@ Index: ioemu/hw/iommu.c Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-08-04 10:57:27.123202432 +0100 -+++ ioemu/cpu-all.h 2006-08-04 10:57:27.490160136 +0100 +--- ioemu.orig/cpu-all.h 2006-08-06 02:17:09.392881406 +0100 ++++ ioemu/cpu-all.h 2006-08-06 02:18:54.844125928 +0100 @@ -835,6 +835,31 @@ :"=m" (*(volatile long *)addr) :"dIr" (nr)); @@ -52,9 +52,9 @@ Index: ioemu/cpu-all.h /* memory API */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:57:27.419168318 +0100 -+++ ioemu/vl.c 2006-08-04 10:57:27.493159790 +0100 -@@ -5567,6 +5567,11 @@ +--- ioemu.orig/vl.c 2006-08-06 02:18:45.608155528 +0100 ++++ ioemu/vl.c 2006-08-06 02:18:54.847125593 +0100 +@@ -6140,6 +6140,11 @@ /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; @@ -66,7 +66,7 @@ Index: ioemu/vl.c #ifdef CONFIG_DM nr_pages = ram_size/PAGE_SIZE; -@@ -5578,6 +5583,7 @@ +@@ -6151,6 +6156,7 @@ exit(-1); } @@ -74,7 +74,7 @@ Index: ioemu/vl.c if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) { fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno); exit(-1); -@@ -5600,6 +5606,41 @@ +@@ -6173,6 +6179,41 @@ free(page_array); @@ -115,11 +115,11 @@ Index: ioemu/vl.c +#endif #else /* !CONFIG_DM */ - #ifdef CONFIG_SOFTMMU + phys_ram_base = qemu_vmalloc(phys_ram_size); Index: ioemu/target-i386-dm/exec-dm.c =================================================================== ---- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-04 10:57:26.738246803 +0100 -+++ ioemu/target-i386-dm/exec-dm.c 2006-08-04 10:57:27.493159790 +0100 +--- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-06 02:15:01.776108064 +0100 ++++ ioemu/target-i386-dm/exec-dm.c 2006-08-06 02:18:54.848125482 +0100 @@ -341,6 +341,23 @@ return io_mem_read[io_index >> IO_MEM_SHIFT]; } @@ -156,8 +156,8 @@ Index: ioemu/target-i386-dm/exec-dm.c memset(buf, 0xff, len); Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-08-04 10:57:26.651256830 +0100 -+++ ioemu/exec-all.h 2006-08-04 10:57:27.494159675 +0100 +--- ioemu.orig/exec-all.h 2006-08-06 02:14:09.796902750 +0100 ++++ ioemu/exec-all.h 2006-08-06 02:18:54.848125482 +0100 @@ -462,12 +462,13 @@ } #endif @@ -177,8 +177,8 @@ Index: ioemu/exec-all.h Index: ioemu/target-i386-dm/cpu.h =================================================================== ---- ioemu.orig/target-i386-dm/cpu.h 2006-08-04 10:57:26.737246918 +0100 -+++ ioemu/target-i386-dm/cpu.h 2006-08-04 10:57:27.494159675 +0100 +--- ioemu.orig/target-i386-dm/cpu.h 2006-08-06 02:15:01.776108064 +0100 ++++ ioemu/target-i386-dm/cpu.h 2006-08-06 02:18:54.848125482 +0100 @@ -80,7 +80,11 @@ /* helper2.c */ int main_loop(void); @@ -194,7 +194,7 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/ia64_intrinsic.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/ia64_intrinsic.h 2006-08-04 10:57:27.495159560 +0100 ++++ ioemu/ia64_intrinsic.h 2006-08-06 02:18:54.849125370 +0100 @@ -0,0 +1,276 @@ +#ifndef IA64_INTRINSIC_H +#define IA64_INTRINSIC_H diff --git a/tools/ioemu/patches/qemu-64bit b/tools/ioemu/patches/qemu-64bit index 584aa5755a..751dea99d8 100644 --- a/tools/ioemu/patches/qemu-64bit +++ b/tools/ioemu/patches/qemu-64bit @@ -1,7 +1,7 @@ Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-07-26 13:19:49.515051864 +0100 -+++ ioemu/cpu-all.h 2006-07-26 13:19:49.563046860 +0100 +--- ioemu.orig/cpu-all.h 2006-08-06 02:14:09.796902750 +0100 ++++ ioemu/cpu-all.h 2006-08-06 02:15:39.707879423 +0100 @@ -822,7 +822,7 @@ /* memory API */ @@ -13,9 +13,9 @@ Index: ioemu/cpu-all.h extern uint8_t *phys_ram_dirty; Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-26 13:19:49.516051760 +0100 -+++ ioemu/hw/pc.c 2006-07-26 13:19:49.564046755 +0100 -@@ -147,7 +147,7 @@ +--- ioemu.orig/hw/pc.c 2006-08-06 02:14:09.797902638 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:15:39.708879311 +0100 +@@ -155,7 +155,7 @@ } /* hd_table must contain 4 block drivers */ @@ -24,7 +24,7 @@ Index: ioemu/hw/pc.c { RTCState *s = rtc_state; int val; -@@ -604,7 +604,7 @@ +@@ -610,7 +610,7 @@ } /* PC hardware initialisation */ @@ -33,7 +33,7 @@ Index: ioemu/hw/pc.c DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, -@@ -853,7 +853,7 @@ +@@ -882,7 +882,7 @@ } } @@ -42,7 +42,7 @@ Index: ioemu/hw/pc.c DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, -@@ -866,7 +866,7 @@ +@@ -895,7 +895,7 @@ initrd_filename, 1); } @@ -53,9 +53,9 @@ Index: ioemu/hw/pc.c const char *kernel_filename, Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-26 13:19:49.552048007 +0100 -+++ ioemu/vl.c 2006-07-26 13:19:49.566046547 +0100 -@@ -123,7 +123,7 @@ +--- ioemu.orig/vl.c 2006-08-06 02:15:31.040845624 +0100 ++++ ioemu/vl.c 2006-08-06 02:15:39.711878977 +0100 +@@ -122,7 +122,7 @@ const char* keyboard_layout = NULL; int64_t ticks_per_sec; int boot_device = 'c'; @@ -64,7 +64,7 @@ Index: ioemu/vl.c int pit_min_timer_count = 0; int nb_nics; NICInfo nd_table[MAX_NICS]; -@@ -5320,7 +5320,7 @@ +@@ -5895,7 +5895,7 @@ help(); break; case QEMU_OPTION_m: @@ -75,9 +75,9 @@ Index: ioemu/vl.c if (ram_size > PHYS_RAM_MAX_SIZE) { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-26 13:19:49.552048007 +0100 -+++ ioemu/vl.h 2006-07-26 13:19:49.567046443 +0100 -@@ -138,7 +138,7 @@ +--- ioemu.orig/vl.h 2006-08-06 02:15:10.368150219 +0100 ++++ ioemu/vl.h 2006-08-06 02:15:39.711878977 +0100 +@@ -146,7 +146,7 @@ extern int xc_handle; extern int domid; @@ -86,7 +86,7 @@ Index: ioemu/vl.h extern int bios_size; extern int rtc_utc; extern int cirrus_vga_enabled; -@@ -542,7 +542,7 @@ +@@ -561,7 +561,7 @@ #ifndef QEMU_TOOL @@ -97,9 +97,9 @@ Index: ioemu/vl.h const char *kernel_filename, const char *kernel_cmdline, Index: ioemu/hw/vga.c =================================================================== ---- ioemu.orig/hw/vga.c 2006-07-26 13:19:49.549048319 +0100 -+++ ioemu/hw/vga.c 2006-07-26 13:20:17.956085603 +0100 -@@ -1293,7 +1293,8 @@ +--- ioemu.orig/hw/vga.c 2006-08-06 02:15:10.364150665 +0100 ++++ ioemu/hw/vga.c 2006-08-06 02:15:39.712878866 +0100 +@@ -1365,7 +1365,8 @@ static void vga_draw_graphic(VGAState *s, int full_update) { int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; diff --git a/tools/ioemu/patches/qemu-allow-disable-sdl b/tools/ioemu/patches/qemu-allow-disable-sdl index caa7105187..e9de6c032b 100644 --- a/tools/ioemu/patches/qemu-allow-disable-sdl +++ b/tools/ioemu/patches/qemu-allow-disable-sdl @@ -1,8 +1,8 @@ Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-08-03 19:19:38.000000000 +0100 -+++ ioemu/configure 2006-08-03 23:38:19.000000000 +0100 -@@ -226,8 +226,6 @@ +--- ioemu.orig/configure 2006-08-06 02:15:01.771108621 +0100 ++++ ioemu/configure 2006-08-06 02:42:26.213918476 +0100 +@@ -228,8 +228,6 @@ ;; --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" ;; @@ -11,7 +11,7 @@ Index: ioemu/configure --disable-gcc-check) check_gcc="no" ;; --disable-system) softmmu="no" -@@ -736,14 +734,6 @@ +@@ -758,14 +756,6 @@ target_user_only="yes" fi diff --git a/tools/ioemu/patches/qemu-bugfixes b/tools/ioemu/patches/qemu-bugfixes index 42d7d5f089..19f64c8925 100644 --- a/tools/ioemu/patches/qemu-bugfixes +++ b/tools/ioemu/patches/qemu-bugfixes @@ -1,8 +1,8 @@ Index: ioemu/console.c =================================================================== ---- ioemu.orig/console.c 2006-07-27 11:16:53.732912290 +0100 -+++ ioemu/console.c 2006-07-27 11:16:57.753467214 +0100 -@@ -449,7 +449,7 @@ +--- ioemu.orig/console.c 2006-08-06 02:03:45.803444993 +0100 ++++ ioemu/console.c 2006-08-06 02:15:48.546894051 +0100 +@@ -505,7 +505,7 @@ c++; } } @@ -11,7 +11,7 @@ Index: ioemu/console.c s->cells = cells; } -@@ -954,11 +954,21 @@ +@@ -1032,11 +1032,21 @@ return !active_console->text_console; } @@ -34,8 +34,8 @@ Index: ioemu/console.c static int color_inited; chr = qemu_mallocz(sizeof(CharDriverState)); -@@ -976,12 +986,7 @@ - +@@ -1058,12 +1068,7 @@ + if (!color_inited) { color_inited = 1; - for(j = 0; j < 2; j++) { @@ -48,23 +48,11 @@ Index: ioemu/console.c } s->y_displayed = 0; s->y_base = 0; -Index: ioemu/usb-linux.c -=================================================================== ---- ioemu.orig/usb-linux.c 2006-07-27 11:16:53.732912290 +0100 -+++ ioemu/usb-linux.c 2006-07-27 11:16:57.754467103 +0100 -@@ -26,6 +26,7 @@ - #if defined(__linux__) - #include - #include -+#define __user /* new versions of usbdevice_fs.h use this private attribute */ - #include - #include - Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:57.681475183 +0100 -+++ ioemu/vl.c 2006-07-27 11:17:33.279534373 +0100 -@@ -3201,6 +3201,7 @@ +--- ioemu.orig/vl.c 2006-08-06 02:15:39.711878977 +0100 ++++ ioemu/vl.c 2006-08-06 02:15:48.550893605 +0100 +@@ -3671,6 +3671,7 @@ if (net_tap_fd_init(vlan, fd)) ret = 0; } else { diff --git a/tools/ioemu/patches/qemu-cleanup b/tools/ioemu/patches/qemu-cleanup index 002d197995..033d9fcc55 100644 --- a/tools/ioemu/patches/qemu-cleanup +++ b/tools/ioemu/patches/qemu-cleanup @@ -1,8 +1,8 @@ Index: ioemu/hw/vga.c =================================================================== ---- ioemu.orig/hw/vga.c 2006-07-12 11:33:54.853085901 +0100 -+++ ioemu/hw/vga.c 2006-07-12 11:35:00.780818943 +0100 -@@ -1563,7 +1563,9 @@ +--- ioemu.orig/hw/vga.c 2006-08-06 02:03:51.906765409 +0100 ++++ ioemu/hw/vga.c 2006-08-06 02:15:10.364150665 +0100 +@@ -1622,7 +1622,9 @@ static void vga_save(QEMUFile *f, void *opaque) { VGAState *s = opaque; @@ -12,7 +12,7 @@ Index: ioemu/hw/vga.c qemu_put_be32s(f, &s->latch); qemu_put_8s(f, &s->sr_index); -@@ -1604,7 +1606,10 @@ +@@ -1663,7 +1665,10 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) { VGAState *s = opaque; @@ -26,8 +26,8 @@ Index: ioemu/hw/vga.c return -EINVAL; Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-12 11:35:00.708827963 +0100 -+++ ioemu/vl.c 2006-07-12 11:35:00.783818568 +0100 +--- ioemu.orig/vl.c 2006-08-06 02:15:01.774108287 +0100 ++++ ioemu/vl.c 2006-08-06 02:15:31.040845624 +0100 @@ -39,6 +39,7 @@ #include #include @@ -36,7 +36,7 @@ Index: ioemu/vl.c #include #include #ifdef _BSD -@@ -4777,7 +4778,9 @@ +@@ -5308,7 +5309,9 @@ QEMU_OPTION_d, QEMU_OPTION_hdachs, QEMU_OPTION_L, @@ -46,7 +46,7 @@ Index: ioemu/vl.c QEMU_OPTION_k, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, -@@ -4844,7 +4847,9 @@ +@@ -5379,7 +5382,9 @@ { "d", HAS_ARG, QEMU_OPTION_d }, { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, @@ -56,10 +56,10 @@ Index: ioemu/vl.c #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, { "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu }, -@@ -5274,9 +5279,11 @@ - case QEMU_OPTION_fdb: - fd_filename[1] = optarg; +@@ -5849,9 +5854,11 @@ + fd_bootchk = 0; break; + #endif +#ifdef USE_CODE_COPY case QEMU_OPTION_no_code_copy: code_copy_enabled = 0; @@ -70,9 +70,9 @@ Index: ioemu/vl.c fprintf(stderr, "qemu: too many network clients\n"); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-12 11:35:00.709827838 +0100 -+++ ioemu/vl.h 2006-07-12 11:35:00.784818442 +0100 -@@ -892,7 +892,7 @@ +--- ioemu.orig/vl.h 2006-08-06 02:15:01.775108175 +0100 ++++ ioemu/vl.h 2006-08-06 02:15:10.368150219 +0100 +@@ -957,7 +957,7 @@ unsigned long vram_offset, int vram_size, int width, int height); /* slavio_intctl.c */ diff --git a/tools/ioemu/patches/qemu-dm b/tools/ioemu/patches/qemu-dm index 5fa3eafc08..056ce40e3a 100644 --- a/tools/ioemu/patches/qemu-dm +++ b/tools/ioemu/patches/qemu-dm @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-07-14 15:50:41.320748096 +0100 -+++ ioemu/Makefile.target 2006-07-14 15:55:04.753733845 +0100 -@@ -285,7 +285,7 @@ +--- ioemu.orig/Makefile.target 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/Makefile.target 2006-08-06 02:14:09.794902973 +0100 +@@ -302,7 +302,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space @@ -13,8 +13,8 @@ Index: ioemu/Makefile.target VL_OBJS+=tap-win32.o Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-07-14 15:50:41.320748096 +0100 -+++ ioemu/configure 2006-07-14 15:55:04.753733845 +0100 +--- ioemu.orig/configure 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/configure 2006-08-06 02:14:09.795902861 +0100 @@ -75,8 +75,8 @@ bigendian="no" mingw32="no" @@ -26,7 +26,7 @@ Index: ioemu/configure adlib="no" oss="no" dsound="no" -@@ -727,6 +727,8 @@ +@@ -749,6 +749,8 @@ if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" fi @@ -37,8 +37,8 @@ Index: ioemu/configure target_user_only="yes" Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-07-14 15:50:30.488983278 +0100 -+++ ioemu/cpu-all.h 2006-07-14 15:55:04.544757636 +0100 +--- ioemu.orig/cpu-all.h 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/cpu-all.h 2006-08-06 02:14:09.796902750 +0100 @@ -690,7 +690,9 @@ void page_set_flags(target_ulong start, target_ulong end, int flags); void page_unprotect_range(target_ulong data, target_ulong data_size); @@ -64,8 +64,8 @@ Index: ioemu/cpu-all.h void cpu_dump_state(CPUState *env, FILE *f, Index: ioemu/disas.h =================================================================== ---- ioemu.orig/disas.h 2006-07-14 15:50:30.489983164 +0100 -+++ ioemu/disas.h 2006-07-14 15:50:41.334746500 +0100 +--- ioemu.orig/disas.h 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/disas.h 2006-08-06 02:14:09.796902750 +0100 @@ -1,6 +1,7 @@ #ifndef _QEMU_DISAS_H #define _QEMU_DISAS_H @@ -83,8 +83,8 @@ Index: ioemu/disas.h #endif /* _QEMU_DISAS_H */ Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-07-14 15:50:30.490983050 +0100 -+++ ioemu/exec-all.h 2006-07-14 15:50:41.335746386 +0100 +--- ioemu.orig/exec-all.h 2006-08-06 02:14:04.798459982 +0100 ++++ ioemu/exec-all.h 2006-08-06 02:14:09.796902750 +0100 @@ -509,7 +509,7 @@ extern int tb_invalidated_flag; @@ -105,17 +105,17 @@ Index: ioemu/exec-all.h return addr; Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-14 15:50:30.491982936 +0100 -+++ ioemu/hw/pc.c 2006-07-14 15:55:04.543757750 +0100 -@@ -65,6 +65,7 @@ - return qemu_get_clock(vm_clock); +--- ioemu.orig/hw/pc.c 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:14:09.797902638 +0100 +@@ -73,6 +73,7 @@ + } } +#ifndef CONFIG_DM /* IRQ handling */ int cpu_get_pic_interrupt(CPUState *env) { -@@ -81,6 +82,7 @@ +@@ -89,6 +90,7 @@ intno = pic_read_irq(isa_pic); return intno; } @@ -123,7 +123,7 @@ Index: ioemu/hw/pc.c static void pic_irq_request(void *opaque, int level) { -@@ -394,6 +396,7 @@ +@@ -400,6 +402,7 @@ /*************************************************/ @@ -131,7 +131,7 @@ Index: ioemu/hw/pc.c static void putb(uint8_t **pp, int val) { uint8_t *q; -@@ -540,6 +543,7 @@ +@@ -546,6 +549,7 @@ float_pointer_struct[10] = -mpf_checksum(float_pointer_struct, q - float_pointer_struct); } @@ -139,7 +139,7 @@ Index: ioemu/hw/pc.c static const int ide_iobase[2] = { 0x1f0, 0x170 }; -@@ -619,12 +623,14 @@ +@@ -626,12 +630,14 @@ /* init CPUs */ for(i = 0; i < smp_cpus; i++) { env = cpu_init(); @@ -154,7 +154,7 @@ Index: ioemu/hw/pc.c register_savevm("cpu", i, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); if (pci_enabled) { -@@ -683,6 +689,7 @@ +@@ -690,6 +696,7 @@ bochs_bios_init(); @@ -162,7 +162,7 @@ Index: ioemu/hw/pc.c if (linux_boot) { uint8_t bootsect[512]; uint8_t old_bootsect[512]; -@@ -738,6 +745,7 @@ +@@ -745,6 +752,7 @@ /* loader type */ stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); } @@ -170,7 +170,7 @@ Index: ioemu/hw/pc.c if (pci_enabled) { pci_bus = i440fx_init(); -@@ -776,9 +784,11 @@ +@@ -783,9 +791,11 @@ isa_pic = pic_init(pic_irq_request, first_cpu); pit = pit_init(0x40, 0); pcspk_init(pit); @@ -184,8 +184,8 @@ Index: ioemu/hw/pc.c if (serial_hds[i]) { Index: ioemu/hw/vga_int.h =================================================================== ---- ioemu.orig/hw/vga_int.h 2006-07-14 15:50:30.491982936 +0100 -+++ ioemu/hw/vga_int.h 2006-07-14 15:55:02.931941245 +0100 +--- ioemu.orig/hw/vga_int.h 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/hw/vga_int.h 2006-08-06 02:14:09.797902638 +0100 @@ -28,7 +28,7 @@ #define ST01_DISP_ENABLE 0x01 @@ -193,12 +193,12 @@ Index: ioemu/hw/vga_int.h -#define CONFIG_BOCHS_VBE +//#define CONFIG_BOCHS_VBE - #define VBE_DISPI_MAX_XRES 1024 - #define VBE_DISPI_MAX_YRES 768 + #define VBE_DISPI_MAX_XRES 1600 + #define VBE_DISPI_MAX_YRES 1200 Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-07-14 15:50:30.493982708 +0100 -+++ ioemu/monitor.c 2006-07-14 15:55:04.754733732 +0100 +--- ioemu.orig/monitor.c 2006-08-06 02:14:04.798459982 +0100 ++++ ioemu/monitor.c 2006-08-06 02:14:49.574468309 +0100 @@ -68,6 +68,12 @@ void term_flush(void) @@ -212,7 +212,7 @@ Index: ioemu/monitor.c if (term_outbuf_index > 0) { qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); term_outbuf_index = 0; -@@ -104,6 +110,7 @@ +@@ -106,6 +112,7 @@ va_end(ap); } @@ -220,7 +220,7 @@ Index: ioemu/monitor.c static int monitor_fprintf(FILE *stream, const char *fmt, ...) { va_list ap; -@@ -112,6 +119,7 @@ +@@ -114,6 +121,7 @@ va_end(ap); return 0; } @@ -228,7 +228,7 @@ Index: ioemu/monitor.c static int compare_cmd(const char *name, const char *list) { -@@ -225,6 +233,7 @@ +@@ -227,6 +235,7 @@ return mon_cpu; } @@ -236,7 +236,7 @@ Index: ioemu/monitor.c static void do_info_registers(void) { CPUState *env; -@@ -278,6 +287,7 @@ +@@ -280,6 +289,7 @@ { dump_exec_info(NULL, monitor_fprintf); } @@ -244,7 +244,7 @@ Index: ioemu/monitor.c static void do_info_history (void) { -@@ -375,6 +385,7 @@ +@@ -377,6 +387,7 @@ cpu_set_log(mask); } @@ -252,7 +252,7 @@ Index: ioemu/monitor.c static void do_savevm(const char *filename) { if (qemu_savevm(filename) < 0) -@@ -621,6 +632,7 @@ +@@ -623,6 +634,7 @@ #endif term_printf("\n"); } @@ -260,23 +260,23 @@ Index: ioemu/monitor.c static void do_sum(uint32_t start, uint32_t size) { -@@ -792,6 +804,7 @@ - } +@@ -841,6 +853,7 @@ + kbd_mouse_event(0, 0, 0, mouse_button_state); } +#ifndef CONFIG_DM static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index) { uint32_t val; -@@ -952,6 +965,7 @@ - } - } +@@ -1031,6 +1044,7 @@ + term_printf("kqemu support: not compiled\n"); #endif + } +#endif /* !CONFIG_DM */ - static void do_info_kqemu(void) - { -@@ -1045,6 +1059,7 @@ + #ifdef CONFIG_PROFILER + +@@ -1152,6 +1166,7 @@ "filename", "save screen into PPM image 'filename'" }, { "log", "s", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, @@ -284,7 +284,7 @@ Index: ioemu/monitor.c { "savevm", "F", do_savevm, "filename", "save the whole virtual machine state to 'filename'" }, { "loadvm", "F", do_loadvm, -@@ -1065,21 +1080,26 @@ +@@ -1172,21 +1187,26 @@ "/fmt expr", "print expression value (use $reg for CPU register access)", }, { "i", "/ii.", do_ioport_read, "/fmt addr", "I/O port read" }, @@ -308,10 +308,10 @@ Index: ioemu/monitor.c { "cpu", "i", do_cpu_set, "index", "set the default CPU" }, +#endif /* !CONFIG_DM */ - { NULL, NULL, }, - }; - -@@ -1090,10 +1110,12 @@ + { "mouse_move", "sss?", do_mouse_move, + "dx dy [dz]", "send mouse move events" }, + { "mouse_button", "i", do_mouse_button, +@@ -1208,10 +1228,12 @@ "", "show the network state" }, { "block", "", do_info_block, "", "show the block devices" }, @@ -324,7 +324,7 @@ Index: ioemu/monitor.c { "history", "", do_info_history, "", "show the command line history", }, { "irq", "", irq_info, -@@ -1102,6 +1124,7 @@ +@@ -1220,6 +1242,7 @@ "", "show i8259 (PIC) state", }, { "pci", "", pci_info, "", "show PCI info", }, @@ -332,15 +332,15 @@ Index: ioemu/monitor.c #if defined(TARGET_I386) { "tlb", "", tlb_info, "", "show virtual to physical memory mappings", }, -@@ -1110,6 +1133,7 @@ - #endif - { "jit", "", do_info_jit, +@@ -1230,6 +1253,7 @@ "", "show dynamic compiler info", }, -+#endif /* !CONFIG_DM */ { "kqemu", "", do_info_kqemu, "", "show kqemu information", }, ++#endif /* !CONFIG_DM */ { "usb", "", usb_info, -@@ -1123,6 +1147,7 @@ + "", "show guest USB devices", }, + { "usbhost", "", usb_host_info, +@@ -1243,6 +1267,7 @@ /*******************************************************************/ @@ -348,7 +348,7 @@ Index: ioemu/monitor.c static const char *pch; static jmp_buf expr_env; -@@ -1663,6 +1688,7 @@ +@@ -1786,6 +1811,7 @@ *pp = pch; return 0; } @@ -356,7 +356,7 @@ Index: ioemu/monitor.c static int get_str(char *buf, int buf_size, const char **pp) { -@@ -1729,8 +1755,10 @@ +@@ -1852,8 +1878,10 @@ return 0; } @@ -367,7 +367,7 @@ Index: ioemu/monitor.c #define MAX_ARGS 16 -@@ -1738,7 +1766,10 @@ +@@ -1861,7 +1889,10 @@ { const char *p, *pstart, *typestr; char *q; @@ -379,7 +379,7 @@ Index: ioemu/monitor.c term_cmd_t *cmd; char cmdname[256]; char buf[1024]; -@@ -1830,6 +1861,7 @@ +@@ -1953,6 +1984,7 @@ args[nb_args++] = str; } break; @@ -387,7 +387,7 @@ Index: ioemu/monitor.c case '/': { int count, format, size; -@@ -1962,6 +1994,7 @@ +@@ -2085,6 +2117,7 @@ } } break; @@ -395,7 +395,7 @@ Index: ioemu/monitor.c case '-': { int has_option; -@@ -1988,6 +2021,11 @@ +@@ -2111,6 +2144,11 @@ args[nb_args++] = (void *)has_option; } break; @@ -407,7 +407,7 @@ Index: ioemu/monitor.c default: bad_type: term_printf("%s: unknown type '%c'\n", cmdname, c); -@@ -2035,6 +2073,7 @@ +@@ -2161,6 +2199,7 @@ return; } @@ -415,7 +415,7 @@ Index: ioemu/monitor.c static void cmd_completion(const char *name, const char *list) { const char *p, *pstart; -@@ -2222,6 +2261,11 @@ +@@ -2354,6 +2393,11 @@ for(i = 0; i < nb_args; i++) qemu_free(args[i]); } @@ -429,9 +429,9 @@ Index: ioemu/monitor.c { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-14 15:50:30.496982366 +0100 -+++ ioemu/vl.c 2006-07-14 15:55:07.676401124 +0100 -@@ -423,12 +423,15 @@ +--- ioemu.orig/vl.c 2006-08-06 02:14:04.797460093 +0100 ++++ ioemu/vl.c 2006-08-06 02:14:09.802902081 +0100 +@@ -422,12 +422,15 @@ void hw_error(const char *fmt, ...) { va_list ap; @@ -447,7 +447,7 @@ Index: ioemu/vl.c for(env = first_cpu; env != NULL; env = env->next_cpu) { fprintf(stderr, "CPU #%d:\n", env->cpu_index); #ifdef TARGET_I386 -@@ -437,6 +440,7 @@ +@@ -436,6 +439,7 @@ cpu_dump_state(env, stderr, fprintf, 0); #endif } @@ -455,7 +455,7 @@ Index: ioemu/vl.c va_end(ap); abort(); } -@@ -3800,6 +3804,7 @@ +@@ -4336,6 +4340,7 @@ return ret; } @@ -463,7 +463,7 @@ Index: ioemu/vl.c /***********************************************************/ /* cpu save/restore */ -@@ -4234,6 +4239,25 @@ +@@ -4770,6 +4775,25 @@ } return 0; } @@ -489,7 +489,7 @@ Index: ioemu/vl.c /***********************************************************/ /* machine registration */ -@@ -5481,6 +5505,7 @@ +@@ -6054,6 +6078,7 @@ socket_init(); #endif @@ -497,7 +497,7 @@ Index: ioemu/vl.c /* init network clients */ if (nb_net_clients == 0) { /* if no clients, we use a default config */ -@@ -5490,6 +5515,7 @@ +@@ -6063,6 +6088,7 @@ "user"); nb_net_clients = 2; } diff --git a/tools/ioemu/patches/qemu-fix-memset-args b/tools/ioemu/patches/qemu-fix-memset-args index 6fa83c22e5..aa132293c4 100644 --- a/tools/ioemu/patches/qemu-fix-memset-args +++ b/tools/ioemu/patches/qemu-fix-memset-args @@ -1,8 +1,8 @@ Index: ioemu/audio/audio.c =================================================================== ---- ioemu.orig/audio/audio.c 2006-07-14 13:43:45.000000000 +0100 -+++ ioemu/audio/audio.c 2006-08-04 10:18:17.243240246 +0100 -@@ -597,11 +597,11 @@ +--- ioemu.orig/audio/audio.c 2006-08-06 02:03:50.013976165 +0100 ++++ ioemu/audio/audio.c 2006-08-06 02:42:28.991609008 +0100 +@@ -605,11 +605,11 @@ } if (info->sign) { diff --git a/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous b/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous index 65bd03490c..e077ab23cb 100644 --- a/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous +++ b/tools/ioemu/patches/qemu-fix-write-to-disk-synchronous @@ -1,7 +1,7 @@ Index: ioemu/block-vmdk.c =================================================================== ---- ioemu.orig/block-vmdk.c 2006-07-14 13:43:45.000000000 +0100 -+++ ioemu/block-vmdk.c 2006-08-04 10:27:15.368803650 +0100 +--- ioemu.orig/block-vmdk.c 2006-08-06 02:03:45.756450226 +0100 ++++ ioemu/block-vmdk.c 2006-08-06 02:42:31.884286728 +0100 @@ -96,7 +96,7 @@ uint32_t magic; int l1_size; @@ -13,8 +13,8 @@ Index: ioemu/block-vmdk.c if (fd < 0) Index: ioemu/block-qcow.c =================================================================== ---- ioemu.orig/block-qcow.c 2006-07-14 13:43:45.000000000 +0100 -+++ ioemu/block-qcow.c 2006-08-04 10:27:15.367803766 +0100 +--- ioemu.orig/block-qcow.c 2006-08-06 02:03:45.754450449 +0100 ++++ ioemu/block-qcow.c 2006-08-06 02:42:31.885286616 +0100 @@ -95,7 +95,7 @@ int fd, len, i, shift; QCowHeader header; @@ -26,8 +26,8 @@ Index: ioemu/block-qcow.c if (fd < 0) Index: ioemu/block-bochs.c =================================================================== ---- ioemu.orig/block-bochs.c 2006-07-14 13:43:45.000000000 +0100 -+++ ioemu/block-bochs.c 2006-08-04 10:27:15.345806311 +0100 +--- ioemu.orig/block-bochs.c 2006-08-06 01:55:02.225741179 +0100 ++++ ioemu/block-bochs.c 2006-08-06 02:42:31.885286616 +0100 @@ -91,7 +91,7 @@ int fd, i; struct bochs_header bochs; @@ -39,9 +39,9 @@ Index: ioemu/block-bochs.c if (fd < 0) Index: ioemu/block.c =================================================================== ---- ioemu.orig/block.c 2006-08-03 19:19:39.000000000 +0100 -+++ ioemu/block.c 2006-08-04 10:27:15.357804923 +0100 -@@ -677,7 +677,7 @@ +--- ioemu.orig/block.c 2006-08-06 02:42:18.880735483 +0100 ++++ ioemu/block.c 2006-08-06 02:42:31.886286505 +0100 +@@ -685,7 +685,7 @@ int rv; #endif @@ -52,8 +52,8 @@ Index: ioemu/block.c if (fd < 0) Index: ioemu/block-cow.c =================================================================== ---- ioemu.orig/block-cow.c 2006-07-14 13:43:45.000000000 +0100 -+++ ioemu/block-cow.c 2006-08-04 10:27:15.366803882 +0100 +--- ioemu.orig/block-cow.c 2006-08-06 02:03:45.751450783 +0100 ++++ ioemu/block-cow.c 2006-08-06 02:42:31.886286505 +0100 @@ -69,7 +69,7 @@ struct cow_header_v2 cow_header; int64_t size; @@ -65,8 +65,8 @@ Index: ioemu/block-cow.c if (fd < 0) Index: ioemu/block-cloop.c =================================================================== ---- ioemu.orig/block-cloop.c 2006-07-14 13:43:45.000000000 +0100 -+++ ioemu/block-cloop.c 2006-08-04 10:27:15.365803997 +0100 +--- ioemu.orig/block-cloop.c 2006-08-06 01:55:02.226741067 +0100 ++++ ioemu/block-cloop.c 2006-08-06 02:42:31.886286505 +0100 @@ -55,7 +55,7 @@ BDRVCloopState *s = bs->opaque; uint32_t offsets_size,max_compressed_block_size=1,i; diff --git a/tools/ioemu/patches/qemu-hvm-banner b/tools/ioemu/patches/qemu-hvm-banner index f199eae97a..697422a19a 100644 --- a/tools/ioemu/patches/qemu-hvm-banner +++ b/tools/ioemu/patches/qemu-hvm-banner @@ -1,8 +1,8 @@ Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-07-12 11:35:00.705828339 +0100 -+++ ioemu/monitor.c 2006-07-12 11:35:01.307752925 +0100 -@@ -2293,15 +2293,14 @@ +--- ioemu.orig/monitor.c 2006-08-06 02:15:01.772108510 +0100 ++++ ioemu/monitor.c 2006-08-06 02:17:10.847719223 +0100 +@@ -2425,15 +2425,14 @@ static void monitor_start_input(void) { diff --git a/tools/ioemu/patches/qemu-init-vgabios b/tools/ioemu/patches/qemu-init-vgabios index f1728979eb..15c5969b2c 100644 --- a/tools/ioemu/patches/qemu-init-vgabios +++ b/tools/ioemu/patches/qemu-init-vgabios @@ -1,8 +1,8 @@ Index: ioemu/hw/vga.c =================================================================== ---- ioemu.orig/hw/vga.c 2006-07-27 11:10:44.847738090 +0100 -+++ ioemu/hw/vga.c 2006-07-27 11:11:02.008839258 +0100 -@@ -1669,6 +1669,136 @@ +--- ioemu.orig/hw/vga.c 2006-08-06 02:22:01.441324863 +0100 ++++ ioemu/hw/vga.c 2006-08-06 02:22:46.606290142 +0100 +@@ -1728,6 +1728,136 @@ } } @@ -139,7 +139,7 @@ Index: ioemu/hw/vga.c void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { -@@ -1710,6 +1840,8 @@ +@@ -1769,6 +1899,8 @@ vga_screen_dump, s); /* XXX: currently needed for display */ vga_state = s; diff --git a/tools/ioemu/patches/qemu-logging b/tools/ioemu/patches/qemu-logging index 855a8c4b77..901f5db3fe 100644 --- a/tools/ioemu/patches/qemu-logging +++ b/tools/ioemu/patches/qemu-logging @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:57.756466882 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:57.828458912 +0100 -@@ -4698,7 +4698,7 @@ +--- ioemu.orig/vl.c 2006-08-06 02:15:48.550893605 +0100 ++++ ioemu/vl.c 2006-08-06 02:16:31.246133963 +0100 +@@ -5234,7 +5234,7 @@ "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" @@ -11,7 +11,7 @@ Index: ioemu/vl.c "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" -@@ -4776,7 +4776,7 @@ +@@ -5307,7 +5307,7 @@ QEMU_OPTION_S, QEMU_OPTION_s, QEMU_OPTION_p, @@ -20,7 +20,7 @@ Index: ioemu/vl.c QEMU_OPTION_hdachs, QEMU_OPTION_L, #ifdef USE_CODE_COPY -@@ -4845,7 +4845,7 @@ +@@ -5380,7 +5380,7 @@ { "S", 0, QEMU_OPTION_S }, { "s", 0, QEMU_OPTION_s }, { "p", HAS_ARG, QEMU_OPTION_p }, @@ -29,16 +29,16 @@ Index: ioemu/vl.c { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, #ifdef USE_CODE_COPY -@@ -5096,6 +5096,8 @@ - char usb_devices[MAX_VM_USB_PORTS][128]; +@@ -5640,6 +5640,8 @@ + char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; + char qemu_dm_logfilename[64]; + LIST_INIT (&vm_change_state_head); - #if !defined(CONFIG_SOFTMMU) - /* we never want that malloc() uses mmap() */ -@@ -5145,6 +5147,11 @@ + #ifndef _WIN32 + { +@@ -5715,6 +5717,11 @@ nb_nics = 0; /* default mac address of the first network interface */ @@ -50,7 +50,7 @@ Index: ioemu/vl.c optind = 1; for(;;) { if (optind >= argc) -@@ -5330,7 +5337,7 @@ +@@ -5905,7 +5912,7 @@ exit(1); } break; @@ -59,12 +59,3 @@ Index: ioemu/vl.c { int mask; CPULogItem *item; -@@ -5701,7 +5708,7 @@ - stk.ss_flags = 0; - - if (sigaltstack(&stk, NULL) < 0) { -- perror("sigaltstack"); -+ fprintf(logfile, "sigaltstack returned error %d\n", errno); - exit(1); - } - } diff --git a/tools/ioemu/patches/qemu-no-apic b/tools/ioemu/patches/qemu-no-apic index be3f7a588b..a2409da86f 100644 --- a/tools/ioemu/patches/qemu-no-apic +++ b/tools/ioemu/patches/qemu-no-apic @@ -1,20 +1,20 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-07-12 11:35:00.704828464 +0100 -+++ ioemu/Makefile.target 2006-07-12 11:35:01.899678766 +0100 -@@ -334,7 +334,7 @@ +--- ioemu.orig/Makefile.target 2006-08-06 02:21:42.270461924 +0100 ++++ ioemu/Makefile.target 2006-08-06 02:22:26.380544784 +0100 +@@ -355,7 +355,7 @@ # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8254.o pcspk.o pc.o --VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o -+VL_OBJS+= cirrus_vga.o mixeng.o parallel.o +-VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o ++VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o + VL_OBJS+= usb-uhci.o DEFINES += -DHAS_AUDIO endif - ifeq ($(TARGET_BASE_ARCH), ppc) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-12 11:35:01.685705573 +0100 -+++ ioemu/hw/pc.c 2006-07-12 11:35:01.900678640 +0100 +--- ioemu.orig/hw/pc.c 2006-08-06 02:22:01.524315611 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:22:11.875161758 +0100 @@ -39,7 +39,9 @@ static fdctrl_t *floppy_controller; static RTCState *rtc_state; @@ -22,10 +22,10 @@ Index: ioemu/hw/pc.c +#ifndef CONFIG_DM static IOAPICState *ioapic; +#endif /* !CONFIG_DM */ - static USBPort *usb_root_ports[2]; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) -@@ -633,9 +635,11 @@ + { +@@ -640,9 +642,11 @@ #endif /* !CONFIG_DM */ register_savevm("cpu", i, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); @@ -37,7 +37,7 @@ Index: ioemu/hw/pc.c } /* allocate RAM */ -@@ -782,9 +786,11 @@ +@@ -789,9 +793,11 @@ register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL); diff --git a/tools/ioemu/patches/qemu-nobios b/tools/ioemu/patches/qemu-nobios index 8d9464deb7..02229ab615 100644 --- a/tools/ioemu/patches/qemu-nobios +++ b/tools/ioemu/patches/qemu-nobios @@ -1,7 +1,8 @@ -diff -r 77a889b0aef8 hw/pc.c ---- a/hw/pc.c Wed Jun 14 19:29:20 2006 +0200 -+++ b/hw/pc.c Wed Jun 14 19:29:35 2006 +0200 -@@ -605,6 +605,8 @@ static void pc_init_ne2k_isa(NICInfo *nd +Index: ioemu/hw/pc.c +=================================================================== +--- ioemu.orig/hw/pc.c 2006-08-06 02:22:11.875161758 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:22:35.588518336 +0100 +@@ -611,6 +611,8 @@ nb_ne2k++; } @@ -10,7 +11,7 @@ diff -r 77a889b0aef8 hw/pc.c /* PC hardware initialisation */ static void pc_init1(uint64_t ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, -@@ -612,10 +614,15 @@ static void pc_init1(uint64_t ram_size, +@@ -618,10 +620,15 @@ const char *initrd_filename, int pci_enabled) { @@ -25,9 +26,9 @@ diff -r 77a889b0aef8 hw/pc.c int bios_size, isa_bios_size; +#endif /* !NOBIOS */ PCIBus *pci_bus; + int piix3_devfn = -1; CPUState *env; - NICInfo *nd; -@@ -647,6 +654,7 @@ static void pc_init1(uint64_t ram_size, +@@ -654,6 +661,7 @@ cpu_register_physical_memory(0, ram_size, 0); #endif @@ -35,7 +36,7 @@ diff -r 77a889b0aef8 hw/pc.c /* BIOS load */ bios_offset = ram_size + vga_ram_size; vga_bios_offset = bios_offset + 256 * 1024; -@@ -675,6 +683,7 @@ static void pc_init1(uint64_t ram_size, +@@ -682,6 +690,7 @@ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); } ret = load_image(buf, phys_ram_base + vga_bios_offset); @@ -43,7 +44,7 @@ diff -r 77a889b0aef8 hw/pc.c /* setup basic memory access */ #ifndef CONFIG_DM /* HVM domain owns memory */ -@@ -682,6 +691,7 @@ static void pc_init1(uint64_t ram_size, +@@ -689,6 +698,7 @@ vga_bios_offset | IO_MEM_ROM); #endif @@ -51,7 +52,7 @@ diff -r 77a889b0aef8 hw/pc.c /* map the last 128KB of the BIOS in ISA space */ isa_bios_size = bios_size; if (isa_bios_size > (128 * 1024)) -@@ -694,6 +704,7 @@ static void pc_init1(uint64_t ram_size, +@@ -701,6 +711,7 @@ /* map all the bios at the top of memory */ cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); diff --git a/tools/ioemu/patches/qemu-smp b/tools/ioemu/patches/qemu-smp index 327f990d90..f986915d6f 100644 --- a/tools/ioemu/patches/qemu-smp +++ b/tools/ioemu/patches/qemu-smp @@ -1,17 +1,17 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:58.619371357 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:58.823348777 +0100 -@@ -159,6 +159,8 @@ - #define MAX_CPUS 1 - #endif +--- ioemu.orig/vl.c 2006-08-06 02:18:54.847125593 +0100 ++++ ioemu/vl.c 2006-08-06 02:19:00.413505070 +0100 +@@ -158,6 +158,8 @@ + int acpi_enabled = 1; + int fd_bootchk = 1; +extern int vcpus; + int xc_handle; char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; -@@ -4636,6 +4638,7 @@ +@@ -5172,6 +5174,7 @@ "-m megs set virtual RAM size to megs MB [default=%d]\n" "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" @@ -19,23 +19,23 @@ Index: ioemu/vl.c #ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" #endif -@@ -4810,6 +4813,7 @@ - QEMU_OPTION_vnc, +@@ -5342,6 +5345,7 @@ + QEMU_OPTION_no_acpi, QEMU_OPTION_d, + QEMU_OPTION_vcpus, }; typedef struct QEMUOption { -@@ -4887,6 +4891,7 @@ - { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, +@@ -5423,6 +5427,7 @@ + { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "d", HAS_ARG, QEMU_OPTION_d }, + { "vcpus", 1, QEMU_OPTION_vcpus }, { NULL }, }; -@@ -5509,6 +5514,10 @@ +@@ -6087,6 +6092,10 @@ domid = atoi(optarg); fprintf(logfile, "domid: %d\n", domid); break; diff --git a/tools/ioemu/patches/qemu-target-i386-dm b/tools/ioemu/patches/qemu-target-i386-dm index 3d79ef0e4b..fd15e651b4 100644 --- a/tools/ioemu/patches/qemu-target-i386-dm +++ b/tools/ioemu/patches/qemu-target-i386-dm @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-07-28 09:56:49.468301708 +0100 -+++ ioemu/Makefile.target 2006-07-28 09:56:58.486281629 +0100 -@@ -57,6 +57,8 @@ +--- ioemu.orig/Makefile.target 2006-08-06 02:14:09.794902973 +0100 ++++ ioemu/Makefile.target 2006-08-06 02:21:42.270461924 +0100 +@@ -62,6 +62,8 @@ QEMU_SYSTEM=qemu-fast endif @@ -11,7 +11,7 @@ Index: ioemu/Makefile.target ifdef CONFIG_USER_ONLY PROGS=$(QEMU_USER) else -@@ -274,6 +276,9 @@ +@@ -291,6 +293,9 @@ OBJS+=gdbstub.o endif @@ -21,20 +21,20 @@ Index: ioemu/Makefile.target all: $(PROGS) $(QEMU_USER): $(OBJS) -@@ -328,7 +333,7 @@ +@@ -349,7 +354,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8254.o pcspk.o pc.o - VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o + VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o + VL_OBJS+= usb-uhci.o DEFINES += -DHAS_AUDIO - endif Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-07-28 09:56:49.469301595 +0100 -+++ ioemu/configure 2006-07-28 09:56:49.486299672 +0100 -@@ -359,6 +359,8 @@ +--- ioemu.orig/configure 2006-08-06 02:14:09.795902861 +0100 ++++ ioemu/configure 2006-08-06 02:15:01.771108621 +0100 +@@ -373,6 +373,8 @@ if [ "$user" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list" fi @@ -45,12 +45,12 @@ Index: ioemu/configure fi Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-07-28 09:56:49.472301255 +0100 -+++ ioemu/monitor.c 2006-07-28 09:56:58.720255164 +0100 -@@ -1142,6 +1142,10 @@ - "", "show host USB devices", }, - { "profile", "", do_info_profile, +--- ioemu.orig/monitor.c 2006-08-06 02:14:49.574468309 +0100 ++++ ioemu/monitor.c 2006-08-06 02:21:16.172371202 +0100 +@@ -1262,6 +1262,10 @@ "", "show profiling information", }, + { "capture", "", do_info_capture, + "show capture information" }, +#ifdef CONFIG_DM + { "hvmiopage", "", sp_info, + "", "show HVM device model shared page info", }, @@ -60,8 +60,8 @@ Index: ioemu/monitor.c Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-28 09:56:49.475300916 +0100 -+++ ioemu/vl.c 2006-07-28 09:56:58.917232883 +0100 +--- ioemu.orig/vl.c 2006-08-06 02:14:09.802902081 +0100 ++++ ioemu/vl.c 2006-08-06 02:21:16.369349244 +0100 @@ -87,7 +87,7 @@ #include "exec-all.h" @@ -71,7 +71,7 @@ Index: ioemu/vl.c //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT -@@ -4382,7 +4382,7 @@ +@@ -4918,7 +4918,7 @@ static QEMUResetEntry *first_reset_entry; static int reset_requested; @@ -80,7 +80,7 @@ Index: ioemu/vl.c static int powerdown_requested; void qemu_register_reset(QEMUResetHandler *func, void *opaque) -@@ -4534,6 +4534,7 @@ +@@ -5067,6 +5067,7 @@ qemu_get_clock(rt_clock)); } @@ -88,7 +88,7 @@ Index: ioemu/vl.c static CPUState *cur_cpu; int main_loop(void) -@@ -4608,6 +4609,7 @@ +@@ -5141,6 +5142,7 @@ cpu_disable_ticks(); return ret; } @@ -98,18 +98,18 @@ Index: ioemu/vl.c { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-28 09:56:49.281322859 +0100 -+++ ioemu/vl.h 2006-07-28 09:56:58.917232883 +0100 -@@ -38,6 +38,8 @@ +--- ioemu.orig/vl.h 2006-08-06 02:13:56.733359091 +0100 ++++ ioemu/vl.h 2006-08-06 02:21:16.369349244 +0100 +@@ -37,6 +37,8 @@ + #include #include #include - #include "audio/audio.h" +#include "xenctrl.h" +#include "xs.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 -@@ -131,6 +133,11 @@ +@@ -139,6 +141,11 @@ void main_loop_wait(int timeout); @@ -121,7 +121,7 @@ Index: ioemu/vl.h extern int ram_size; extern int bios_size; extern int rtc_utc; -@@ -814,6 +821,7 @@ +@@ -873,6 +880,7 @@ uint32_t pic_intack_read(PicState2 *s); void pic_info(void); void irq_info(void); @@ -132,7 +132,7 @@ Index: ioemu/vl.h Index: ioemu/target-i386-dm/cpu.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/cpu.h 2006-07-28 09:56:58.572271903 +0100 ++++ ioemu/target-i386-dm/cpu.h 2006-08-06 02:21:16.023387810 +0100 @@ -0,0 +1,86 @@ +/* + * i386 virtual CPU header @@ -223,7 +223,7 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/target-i386-dm/exec-dm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/exec-dm.c 2006-07-28 09:58:22.882736989 +0100 ++++ ioemu/target-i386-dm/exec-dm.c 2006-08-06 02:21:16.024387698 +0100 @@ -0,0 +1,516 @@ +/* + * virtual page mapping and translated block handling @@ -744,7 +744,7 @@ Index: ioemu/target-i386-dm/exec-dm.c Index: ioemu/target-i386-dm/helper2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/helper2.c 2006-07-28 09:56:58.312301309 +0100 ++++ ioemu/target-i386-dm/helper2.c 2006-08-06 02:21:15.779415007 +0100 @@ -0,0 +1,464 @@ +/* + * i386 helpers (without register variable usage) @@ -1213,7 +1213,7 @@ Index: ioemu/target-i386-dm/helper2.c Index: ioemu/target-i386-dm/i8259-dm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/i8259-dm.c 2006-07-28 09:56:49.492298993 +0100 ++++ ioemu/target-i386-dm/i8259-dm.c 2006-08-06 02:15:01.777107952 +0100 @@ -0,0 +1,107 @@ +/* Xen 8259 stub for interrupt controller emulation + * @@ -1325,7 +1325,7 @@ Index: ioemu/target-i386-dm/i8259-dm.c Index: ioemu/target-i386-dm/qemu-dm.debug =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/qemu-dm.debug 2006-07-28 09:56:49.493298880 +0100 ++++ ioemu/target-i386-dm/qemu-dm.debug 2006-08-06 02:15:01.778107841 +0100 @@ -0,0 +1,5 @@ +#!/bin/sh + @@ -1335,7 +1335,7 @@ Index: ioemu/target-i386-dm/qemu-dm.debug Index: ioemu/target-i386-dm/qemu-ifup =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/qemu-ifup 2006-07-28 09:56:49.493298880 +0100 ++++ ioemu/target-i386-dm/qemu-ifup 2006-08-06 02:15:01.778107841 +0100 @@ -0,0 +1,10 @@ +#!/bin/sh + diff --git a/tools/ioemu/patches/qemu-timer b/tools/ioemu/patches/qemu-timer index 94cdc9e784..fe4faa18c5 100644 --- a/tools/ioemu/patches/qemu-timer +++ b/tools/ioemu/patches/qemu-timer @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-12 11:35:02.126650330 +0100 -+++ ioemu/vl.c 2006-07-12 11:35:02.273631916 +0100 -@@ -861,6 +861,16 @@ +--- ioemu.orig/vl.c 2006-08-06 02:22:53.925474246 +0100 ++++ ioemu/vl.c 2006-08-06 02:22:56.618174081 +0100 +@@ -824,6 +824,16 @@ } } @@ -19,16 +19,16 @@ Index: ioemu/vl.c static void timer_save(QEMUFile *f, void *opaque) { if (cpu_ticks_enabled) { -@@ -977,6 +987,8 @@ +@@ -940,6 +950,8 @@ #endif /* !defined(_WIN32) */ +#endif /* !CONFIG_DM */ + - static void init_timers(void) + static void init_timer_alarm(void) { - rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); -@@ -1011,12 +1023,15 @@ + #ifdef _WIN32 +@@ -971,12 +983,15 @@ pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; #else { @@ -44,7 +44,7 @@ Index: ioemu/vl.c /* timer signal */ sigfillset(&act.sa_mask); act.sa_flags = 0; -@@ -1062,6 +1077,7 @@ +@@ -1022,6 +1037,7 @@ pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / 1000000; } diff --git a/tools/ioemu/patches/serial-non-block b/tools/ioemu/patches/serial-non-block index adbbe24319..242171e4e6 100644 --- a/tools/ioemu/patches/serial-non-block +++ b/tools/ioemu/patches/serial-non-block @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-12 11:35:02.880555879 +0100 -+++ ioemu/vl.c 2006-07-12 11:35:03.004540346 +0100 -@@ -1215,19 +1215,34 @@ +--- ioemu.orig/vl.c 2006-08-06 02:23:29.827472129 +0100 ++++ ioemu/vl.c 2006-08-06 02:23:36.856688561 +0100 +@@ -1175,19 +1175,34 @@ static int unix_write(int fd, const uint8_t *buf, int len1) { diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index eecf8819c3..7b886d60f7 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -26,7 +26,6 @@ shadow-vram serial-non-block ide-hd-multithread domain-timeoffset -sdl-mouse-invisible-wall acpi-support acpi-timer-support acpi-poweroff-support diff --git a/tools/ioemu/patches/shadow-vram b/tools/ioemu/patches/shadow-vram index 52557ca523..360ba75eef 100644 --- a/tools/ioemu/patches/shadow-vram +++ b/tools/ioemu/patches/shadow-vram @@ -1,8 +1,8 @@ Index: ioemu/hw/vga.c =================================================================== ---- ioemu.orig/hw/vga.c 2006-07-26 15:17:39.821306797 +0100 -+++ ioemu/hw/vga.c 2006-07-26 15:17:40.017285449 +0100 -@@ -1287,6 +1287,105 @@ +--- ioemu.orig/hw/vga.c 2006-08-06 02:23:29.824472464 +0100 ++++ ioemu/hw/vga.c 2006-08-06 02:23:33.873021159 +0100 +@@ -1359,6 +1359,105 @@ } } @@ -108,7 +108,7 @@ Index: ioemu/hw/vga.c /* * graphic modes */ -@@ -1382,6 +1481,11 @@ +@@ -1454,6 +1553,11 @@ printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); #endif @@ -120,7 +120,7 @@ Index: ioemu/hw/vga.c addr1 = (s->start_addr * 4); bwidth = width * 4; y_start = -1; -@@ -1830,6 +1934,14 @@ +@@ -1889,6 +1993,14 @@ vga_reset(s); @@ -137,9 +137,9 @@ Index: ioemu/hw/vga.c s->vram_size = vga_ram_size; Index: ioemu/hw/vga_int.h =================================================================== ---- ioemu.orig/hw/vga_int.h 2006-07-26 15:17:39.822306688 +0100 -+++ ioemu/hw/vga_int.h 2006-07-26 15:17:40.017285449 +0100 -@@ -76,6 +76,7 @@ +--- ioemu.orig/hw/vga_int.h 2006-08-06 02:23:29.824472464 +0100 ++++ ioemu/hw/vga_int.h 2006-08-06 02:23:33.874021048 +0100 +@@ -79,6 +79,7 @@ #define VGA_STATE_COMMON \ uint8_t *vram_ptr; \ diff --git a/tools/ioemu/patches/shared-vram b/tools/ioemu/patches/shared-vram index 023d2f546e..65230c8e0a 100644 --- a/tools/ioemu/patches/shared-vram +++ b/tools/ioemu/patches/shared-vram @@ -1,7 +1,7 @@ Index: ioemu/hw/cirrus_vga.c =================================================================== ---- ioemu.orig/hw/cirrus_vga.c 2006-07-27 11:16:53.059986783 +0100 -+++ ioemu/hw/cirrus_vga.c 2006-07-27 11:16:59.923227020 +0100 +--- ioemu.orig/hw/cirrus_vga.c 2006-08-06 01:55:02.822674718 +0100 ++++ ioemu/hw/cirrus_vga.c 2006-08-06 02:23:29.822472686 +0100 @@ -28,6 +28,9 @@ */ #include "vl.h" @@ -176,9 +176,9 @@ Index: ioemu/hw/cirrus_vga.c } Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-07-27 11:16:59.759245173 +0100 -+++ ioemu/hw/pc.c 2006-07-27 11:16:59.924226909 +0100 -@@ -783,14 +783,14 @@ +--- ioemu.orig/hw/pc.c 2006-08-06 02:23:07.875919141 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:23:29.823472575 +0100 +@@ -790,14 +790,14 @@ if (cirrus_vga_enabled) { if (pci_enabled) { pci_cirrus_vga_init(pci_bus, @@ -198,9 +198,9 @@ Index: ioemu/hw/pc.c Index: ioemu/hw/vga.c =================================================================== ---- ioemu.orig/hw/vga.c 2006-07-27 11:16:59.103317784 +0100 -+++ ioemu/hw/vga.c 2006-07-27 11:16:59.925226798 +0100 -@@ -1799,6 +1799,7 @@ +--- ioemu.orig/hw/vga.c 2006-08-06 02:22:46.606290142 +0100 ++++ ioemu/hw/vga.c 2006-08-06 02:23:29.824472464 +0100 +@@ -1858,6 +1858,7 @@ /* TODO: add vbe support if enabled */ } @@ -208,7 +208,7 @@ Index: ioemu/hw/vga.c void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { -@@ -1829,7 +1830,7 @@ +@@ -1888,7 +1889,7 @@ vga_reset(s); @@ -217,7 +217,7 @@ Index: ioemu/hw/vga.c s->vram_offset = vga_ram_offset; s->vram_size = vga_ram_size; s->ds = ds; -@@ -1943,6 +1944,31 @@ +@@ -2002,6 +2003,31 @@ return 0; } @@ -251,9 +251,9 @@ Index: ioemu/hw/vga.c Index: ioemu/hw/vga_int.h =================================================================== ---- ioemu.orig/hw/vga_int.h 2006-07-27 11:16:57.447501084 +0100 -+++ ioemu/hw/vga_int.h 2006-07-27 11:16:59.925226798 +0100 -@@ -166,5 +166,6 @@ +--- ioemu.orig/hw/vga_int.h 2006-08-06 02:14:09.797902638 +0100 ++++ ioemu/hw/vga_int.h 2006-08-06 02:23:29.824472464 +0100 +@@ -169,5 +169,6 @@ unsigned int color0, unsigned int color1, unsigned int color_xor); @@ -262,9 +262,9 @@ Index: ioemu/hw/vga_int.h extern const uint8_t gr_mask[16]; Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:59.762244841 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:59.928226466 +0100 -@@ -5149,6 +5149,78 @@ +--- ioemu.orig/vl.c 2006-08-06 02:23:07.878918807 +0100 ++++ ioemu/vl.c 2006-08-06 02:23:29.827472129 +0100 +@@ -5693,6 +5693,78 @@ #define MAX_NET_CLIENTS 32 @@ -345,9 +345,9 @@ Index: ioemu/vl.c #ifdef CONFIG_GDBSTUB Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-27 11:16:59.549268417 +0100 -+++ ioemu/vl.h 2006-07-27 11:16:59.929226356 +0100 -@@ -136,6 +136,13 @@ +--- ioemu.orig/vl.h 2006-08-06 02:23:02.271543880 +0100 ++++ ioemu/vl.h 2006-08-06 02:23:29.828472018 +0100 +@@ -144,6 +144,13 @@ void main_loop_wait(int timeout); diff --git a/tools/ioemu/patches/support-xm-console b/tools/ioemu/patches/support-xm-console index 3ce5198fcf..5803086194 100644 --- a/tools/ioemu/patches/support-xm-console +++ b/tools/ioemu/patches/support-xm-console @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:59.384286681 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:59.614261222 +0100 -@@ -1535,26 +1535,65 @@ +--- ioemu.orig/vl.c 2006-08-06 02:22:59.254880158 +0100 ++++ ioemu/vl.c 2006-08-06 02:23:05.216215627 +0100 +@@ -1536,26 +1536,65 @@ return chr; } @@ -77,7 +77,7 @@ Index: ioemu/vl.c return qemu_chr_open_fd(master_fd, master_fd); } -@@ -5298,7 +5337,9 @@ +@@ -5868,7 +5907,9 @@ break; case QEMU_OPTION_nographic: pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); diff --git a/tools/ioemu/patches/vnc-access-monitor-vt b/tools/ioemu/patches/vnc-access-monitor-vt index f796646cee..526945d300 100644 --- a/tools/ioemu/patches/vnc-access-monitor-vt +++ b/tools/ioemu/patches/vnc-access-monitor-vt @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-07-26 14:33:57.906165040 +0100 -+++ ioemu/vnc.c 2006-07-26 14:44:09.972552689 +0100 +--- ioemu.orig/vnc.c 2006-08-07 17:44:33.084748631 +0100 ++++ ioemu/vnc.c 2006-08-07 17:44:33.224733389 +0100 @@ -32,6 +32,10 @@ #include "vnc_keysym.h" #include "keymaps.c" @@ -13,15 +13,16 @@ Index: ioemu/vnc.c typedef struct Buffer { size_t capacity; -@@ -64,6 +68,7 @@ - Buffer output; - Buffer input; - kbd_layout_t *kbd_layout; -+ int ctl_keys; /* Ctrl+Alt starts calibration */ +@@ -95,6 +99,8 @@ + int visible_h; - VncReadEvent *read_handler; - size_t read_handler_expect; -@@ -679,16 +684,80 @@ + int slow_client; ++ ++ int ctl_keys; /* Ctrl+Alt starts calibration */ + }; + + #define DIRTY_PIXEL_BITS 64 +@@ -794,16 +800,80 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) { diff --git a/tools/ioemu/patches/vnc-cleanup b/tools/ioemu/patches/vnc-cleanup index 7041e1670c..934bcdb5dd 100644 --- a/tools/ioemu/patches/vnc-cleanup +++ b/tools/ioemu/patches/vnc-cleanup @@ -1,8 +1,8 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:42:19.575024607 +0100 -+++ ioemu/vnc.c 2006-08-04 10:42:26.918176009 +0100 -@@ -83,13 +83,16 @@ +--- ioemu.orig/vnc.c 2006-08-07 17:42:21.888055419 +0100 ++++ ioemu/vnc.c 2006-08-07 17:42:28.001363557 +0100 +@@ -143,13 +143,16 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) { VncState *vs = ds->opaque; @@ -17,12 +17,12 @@ Index: ioemu/vnc.c for (; y < h; y++) - for (i = 0; i < w; i += 16) -- vs->dirty_row[y] |= (1ULL << ((x + i) / 16)); +- vnc_set_bit(vs->dirty_row[y], (x + i) / 16); + vs->dirty_row[y] |= mask; } static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, -@@ -262,6 +265,7 @@ +@@ -373,6 +376,7 @@ static void vnc_update_client(void *opaque) { VncState *vs = opaque; @@ -30,16 +30,16 @@ Index: ioemu/vnc.c if (vs->need_update && vs->csock != -1) { int y; -@@ -282,7 +286,7 @@ +@@ -390,7 +394,7 @@ row = vs->ds->data; old_row = vs->old_data; - for (y = 0; y < vs->height; y++) { + for (y = 0; y < vs->ds->height; y++) { - if (vs->dirty_row[y] & width_mask) { + if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) { int x; char *ptr, *old_ptr; -@@ -307,10 +311,8 @@ +@@ -415,10 +419,8 @@ old_row += vs->ds->linesize; } @@ -52,7 +52,7 @@ Index: ioemu/vnc.c /* Count rectangles */ n_rectangles = 0; -@@ -348,7 +350,9 @@ +@@ -456,7 +458,9 @@ vnc_flush(vs); } @@ -65,9 +65,9 @@ Index: ioemu/vnc.c static void vnc_timer_init(VncState *vs) Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:42:26.723198541 +0100 -+++ ioemu/vl.c 2006-08-04 10:42:26.921175663 +0100 -@@ -4589,10 +4589,10 @@ +--- ioemu.orig/vl.c 2006-08-07 17:42:27.807385506 +0100 ++++ ioemu/vl.c 2006-08-07 17:42:28.004363230 +0100 +@@ -5120,10 +5120,10 @@ /* XXX: better handling of removal */ for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { ioh_next = ioh->next; diff --git a/tools/ioemu/patches/vnc-fixes b/tools/ioemu/patches/vnc-fixes index ba21cb25a4..0ddb26ec00 100644 --- a/tools/ioemu/patches/vnc-fixes +++ b/tools/ioemu/patches/vnc-fixes @@ -1,10 +1,10 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:57:29.116972627 +0100 -+++ ioemu/vl.c 2006-08-04 10:57:29.186964560 +0100 -@@ -6026,8 +6026,10 @@ - kernel_filename, kernel_cmdline, initrd_filename, - timeoffset); +--- ioemu.orig/vl.c 2006-08-07 17:42:28.004363230 +0100 ++++ ioemu/vl.c 2006-08-07 17:43:16.361100898 +0100 +@@ -6516,8 +6516,10 @@ + } + } - gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); - qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); @@ -17,8 +17,8 @@ Index: ioemu/vl.c if (use_gdbstub) { Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:57:29.114972858 +0100 -+++ ioemu/vnc.c 2006-08-04 10:57:29.187964445 +0100 +--- ioemu.orig/vnc.c 2006-08-07 17:42:28.001363557 +0100 ++++ ioemu/vnc.c 2006-08-07 17:43:33.593225293 +0100 @@ -3,6 +3,7 @@ * * Copyright (C) 2006 Anthony Liguori @@ -27,20 +27,32 @@ Index: ioemu/vnc.c * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal -@@ -51,7 +52,11 @@ +@@ -50,9 +51,11 @@ + uint32_t *last_fg, + int *has_bg, int *has_fg); + ++#if 0 + #define VNC_MAX_WIDTH 2048 + #define VNC_MAX_HEIGHT 2048 + #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) ++#endif + + struct VncState + { +@@ -63,7 +66,11 @@ int need_update; int width; int height; -- uint64_t dirty_row[768]; +- uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS]; + uint64_t *dirty_row; /* screen regions which are possibly dirty */ + int dirty_pixel_shift; + uint64_t *update_row; /* outstanding updates */ + int has_update; /* there's outstanding updates in the + * visible area */ char *old_data; - int depth; + int depth; /* internal VNC frame buffer byte per pixel */ int has_resize; -@@ -62,13 +67,25 @@ +@@ -81,13 +88,25 @@ VncReadEvent *read_handler; size_t read_handler_expect; @@ -67,7 +79,7 @@ Index: ioemu/vnc.c */ static void vnc_write(VncState *vs, const void *data, size_t len); -@@ -77,22 +94,38 @@ +@@ -96,9 +115,12 @@ static void vnc_write_u16(VncState *vs, uint16_t value); static void vnc_write_u8(VncState *vs, uint8_t value); static void vnc_flush(VncState *vs); @@ -76,6 +88,16 @@ Index: ioemu/vnc.c static void vnc_client_read(void *opaque); +static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h); ++#if 0 + static inline void vnc_set_bit(uint32_t *d, int k) + { + d[k >> 5] |= 1 << (k & 0x1f); +@@ -139,20 +161,35 @@ + } + return 0; + } ++#endif + -static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) +static void set_bits_in_row(VncState *vs, uint64_t *row, + int x, int y, int w, int h) @@ -112,7 +134,7 @@ Index: ioemu/vnc.c } static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, -@@ -109,16 +142,23 @@ +@@ -169,16 +206,23 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h) { VncState *vs = ds->opaque; @@ -138,7 +160,7 @@ Index: ioemu/vnc.c ds->width = w; ds->height = h; ds->linesize = w * vs->depth; -@@ -131,6 +171,10 @@ +@@ -191,6 +235,10 @@ vs->width = ds->width; vs->height = ds->height; } @@ -148,8 +170,8 @@ Index: ioemu/vnc.c + framebuffer_set_updated(vs, 0, 0, ds->width, ds->height); } - static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) -@@ -215,8 +259,20 @@ + /* fastest code */ +@@ -326,8 +374,20 @@ int y = 0; int pitch = ds->linesize; VncState *vs = ds->opaque; @@ -171,7 +193,7 @@ Index: ioemu/vnc.c if (dst_y > src_y) { y = h - 1; -@@ -238,31 +294,34 @@ +@@ -349,31 +409,34 @@ old_row += pitch; } @@ -202,11 +224,11 @@ Index: ioemu/vnc.c - for (h = 1; h < (vs->height - y); h++) { + for (h = 1; y + h < maxy; h++) { int tmp_x; -- if (!(vs->dirty_row[y + h] & (1ULL << last_x))) +- if (!vnc_get_bit(vs->dirty_row[y + h], last_x)) + if (!(vs->update_row[y + h] & (1ULL << last_x))) break; for (tmp_x = last_x; tmp_x < x; tmp_x++) -- vs->dirty_row[y + h] &= ~(1ULL << tmp_x); +- vnc_clear_bit(vs->dirty_row[y + h], tmp_x); + vs->update_row[y + h] &= ~(1ULL << tmp_x); } @@ -218,30 +240,41 @@ Index: ioemu/vnc.c { VncState *vs = opaque; int64_t now = qemu_get_clock(rt_clock); -@@ -274,11 +333,12 @@ - uint64_t width_mask; +@@ -382,12 +445,16 @@ + int y; + char *row; + char *old_row; +- uint32_t width_mask[VNC_DIRTY_WORDS]; ++ uint64_t width_mask; int n_rectangles; int saved_offset; - int has_dirty = 0; -- -- width_mask = (1ULL << (vs->width / 16)) - 1; + int maxx, maxy; + int tile_bytes = vs->depth * DP2X(vs, 1); -- if (vs->width == 1024) +- vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS); + if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS)) + width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1; + else - width_mask = ~(0ULL); ++ width_mask = ~(0ULL); /* Walk through the dirty map and eliminate tiles that -@@ -294,16 +354,18 @@ + really aren't dirty */ +@@ -395,23 +462,25 @@ + old_row = vs->old_data; + + for (y = 0; y < vs->ds->height; y++) { +- if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) { ++ if (vs->dirty_row[y] & width_mask) { + int x; + char *ptr, *old_ptr; + ptr = row; old_ptr = old_row; - for (x = 0; x < vs->ds->width; x += 16) { - if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) { -- vs->dirty_row[y] &= ~(1ULL << (x / 16)); +- vnc_clear_bit(vs->dirty_row[y], (x / 16)); - } else { - has_dirty = 1; - memcpy(old_ptr, ptr, 16 * vs->depth); @@ -262,7 +295,7 @@ Index: ioemu/vnc.c } } -@@ -311,7 +373,8 @@ +@@ -419,7 +488,8 @@ old_row += vs->ds->linesize; } @@ -272,7 +305,7 @@ Index: ioemu/vnc.c goto out; /* Count rectangles */ -@@ -321,40 +384,61 @@ +@@ -429,40 +499,61 @@ saved_offset = vs->output.offset; vnc_write_u16(vs, 0); @@ -288,7 +321,7 @@ Index: ioemu/vnc.c int x; int last_x = -1; - for (x = 0; x < vs->width / 16; x++) { -- if (vs->dirty_row[y] & (1ULL << x)) { +- if (vnc_get_bit(vs->dirty_row[y], x)) { - if (last_x == -1) { + for (x = X2DP_DOWN(vs, vs->visible_x); + x < X2DP_UP(vs, maxx); x++) { @@ -296,7 +329,7 @@ Index: ioemu/vnc.c + if (last_x == -1) last_x = x; - } -- vs->dirty_row[y] &= ~(1ULL << x); +- vnc_clear_bit(vs->dirty_row[y], x); + vs->update_row[y] &= ~(1ULL << x); } else { if (last_x != -1) { @@ -346,7 +379,7 @@ Index: ioemu/vnc.c static void vnc_timer_init(VncState *vs) { if (vs->timer == NULL) { -@@ -365,8 +449,6 @@ +@@ -473,8 +564,6 @@ static void vnc_dpy_refresh(DisplayState *ds) { @@ -355,7 +388,7 @@ Index: ioemu/vnc.c vga_hw_update(); } -@@ -402,7 +484,7 @@ +@@ -510,7 +599,7 @@ static void buffer_reset(Buffer *buffer) { @@ -364,7 +397,7 @@ Index: ioemu/vnc.c } static void buffer_append(Buffer *buffer, const void *data, size_t len) -@@ -443,12 +525,12 @@ +@@ -551,12 +640,12 @@ if (!ret) return; @@ -380,7 +413,7 @@ Index: ioemu/vnc.c } static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) -@@ -480,11 +562,11 @@ +@@ -588,11 +677,11 @@ return; if (!ret) { @@ -395,7 +428,7 @@ Index: ioemu/vnc.c } } -@@ -492,9 +574,9 @@ +@@ -600,9 +689,9 @@ { buffer_reserve(&vs->output, len); @@ -408,7 +441,7 @@ Index: ioemu/vnc.c buffer_append(&vs->output, data, len); } -@@ -616,24 +698,25 @@ +@@ -724,22 +813,25 @@ do_key_event(vs, down, sym); } @@ -430,10 +463,8 @@ Index: ioemu/vnc.c - char *old_row = vs->old_data + y_position * vs->ds->linesize; - - for (i = 0; i < h; i++) { -- vs->dirty_row[y_position + i] = (1ULL << (vs->ds->width / 16)) - 1; -- if (vs->ds->width == 1024) { -- vs->dirty_row[y_position + i] = ~(0ULL); -- } +- vnc_set_bits(vs->dirty_row[y_position + i], +- (vs->ds->width / 16), VNC_DIRTY_WORDS); - memset(old_row, 42, vs->ds->width * vs->depth); - old_row += vs->ds->linesize; - } @@ -447,8 +478,8 @@ Index: ioemu/vnc.c } static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) -@@ -690,8 +773,6 @@ - vnc_client_error(vs); +@@ -845,8 +937,6 @@ + } vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); - memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); @@ -456,7 +487,7 @@ Index: ioemu/vnc.c vga_hw_invalidate(); vga_hw_update(); -@@ -848,11 +929,11 @@ +@@ -1012,11 +1102,11 @@ vnc_write(vs, "RFB 003.003\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); @@ -470,7 +501,7 @@ Index: ioemu/vnc.c } } -@@ -909,17 +990,15 @@ +@@ -1073,17 +1163,15 @@ exit(1); } @@ -493,9 +524,9 @@ Index: ioemu/vnc.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:57:28.925994639 +0100 -+++ ioemu/vl.h 2006-08-04 10:57:29.187964445 +0100 -@@ -302,6 +302,7 @@ +--- ioemu.orig/vl.h 2006-08-07 17:42:27.807385506 +0100 ++++ ioemu/vl.h 2006-08-07 17:43:16.361100898 +0100 +@@ -318,6 +318,7 @@ int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds); void console_select(unsigned int index); diff --git a/tools/ioemu/patches/vnc-start-vncviewer b/tools/ioemu/patches/vnc-start-vncviewer index e0ecff1fe0..990bd6134c 100644 --- a/tools/ioemu/patches/vnc-start-vncviewer +++ b/tools/ioemu/patches/vnc-start-vncviewer @@ -1,8 +1,8 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-08-04 10:57:29.187964445 +0100 -+++ ioemu/vnc.c 2006-08-04 10:57:29.351945544 +0100 -@@ -1002,3 +1002,25 @@ +--- ioemu.orig/vnc.c 2006-08-07 17:44:32.852773890 +0100 ++++ ioemu/vnc.c 2006-08-07 17:44:32.915767031 +0100 +@@ -1175,3 +1175,25 @@ vnc_dpy_resize(vs->ds, 640, 400); } @@ -30,9 +30,9 @@ Index: ioemu/vnc.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:57:29.186964560 +0100 -+++ ioemu/vl.c 2006-08-04 10:57:29.354945198 +0100 -@@ -121,6 +121,7 @@ +--- ioemu.orig/vl.c 2006-08-07 17:44:32.851773999 +0100 ++++ ioemu/vl.c 2006-08-07 17:44:32.918766704 +0100 +@@ -120,6 +120,7 @@ int bios_size; static DisplayState display_state; int nographic; @@ -40,7 +40,7 @@ Index: ioemu/vl.c const char* keyboard_layout = NULL; int64_t ticks_per_sec; int boot_device = 'c'; -@@ -4804,6 +4805,7 @@ +@@ -5340,6 +5341,7 @@ #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" @@ -48,15 +48,15 @@ Index: ioemu/vl.c "-timeoffset time offset (in seconds) from local time\n" "-acpi disable or enable ACPI of HVM domain \n" "\n" -@@ -4893,6 +4895,7 @@ - QEMU_OPTION_usbdevice, - QEMU_OPTION_smp, - QEMU_OPTION_vnc, -+ QEMU_OPTION_vncviewer, - - QEMU_OPTION_d, +@@ -5428,6 +5430,7 @@ QEMU_OPTION_vcpus, -@@ -4969,6 +4972,7 @@ + QEMU_OPTION_timeoffset, + QEMU_OPTION_acpi, ++ QEMU_OPTION_vncviewer, + }; + + typedef struct QEMUOption { +@@ -5502,6 +5505,7 @@ { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, @@ -64,7 +64,7 @@ Index: ioemu/vl.c /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, -@@ -5300,6 +5304,7 @@ +@@ -5868,6 +5872,7 @@ #endif snapshot = 0; nographic = 0; @@ -72,17 +72,17 @@ Index: ioemu/vl.c kernel_filename = NULL; kernel_cmdline = ""; #ifdef TARGET_PPC -@@ -5669,6 +5674,9 @@ - exit(1); - } - break; +@@ -6262,6 +6267,9 @@ + case QEMU_OPTION_acpi: + acpi_enabled = 1; + break; + case QEMU_OPTION_vncviewer: + vncviewer++; + break; - case QEMU_OPTION_domainname: - strncat(domain_name, optarg, sizeof(domain_name) - 20); - break; -@@ -5933,6 +5941,8 @@ + } + } + } +@@ -6458,6 +6466,8 @@ dumb_display_init(ds); } else if (vnc_display != -1) { vnc_display_init(ds, vnc_display); @@ -93,9 +93,9 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:57:29.187964445 +0100 -+++ ioemu/vl.h 2006-08-04 10:57:29.355945083 +0100 -@@ -734,6 +734,7 @@ +--- ioemu.orig/vl.h 2006-08-07 17:44:32.853773781 +0100 ++++ ioemu/vl.h 2006-08-07 17:44:32.919766595 +0100 +@@ -785,6 +785,7 @@ /* vnc.c */ void vnc_display_init(DisplayState *ds, int display); diff --git a/tools/ioemu/patches/vnc-title-domain-name b/tools/ioemu/patches/vnc-title-domain-name index 3fb1491bab..a5d41fe4b1 100644 --- a/tools/ioemu/patches/vnc-title-domain-name +++ b/tools/ioemu/patches/vnc-title-domain-name @@ -1,8 +1,8 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-07-26 14:23:52.426074956 +0100 -+++ ioemu/vnc.c 2006-07-26 14:24:15.210558295 +0100 -@@ -850,6 +850,7 @@ +--- ioemu.orig/vnc.c 2006-08-07 17:44:32.915767031 +0100 ++++ ioemu/vnc.c 2006-08-07 17:44:33.084748631 +0100 +@@ -1014,6 +1014,7 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) { @@ -10,7 +10,7 @@ Index: ioemu/vnc.c char pad[3] = { 0, 0, 0 }; vs->width = vs->ds->width; -@@ -886,8 +887,10 @@ +@@ -1059,8 +1060,10 @@ vnc_write(vs, pad, 3); /* padding */ diff --git a/tools/ioemu/patches/xen-build b/tools/ioemu/patches/xen-build index 4635c51e26..ee2e2885e9 100644 --- a/tools/ioemu/patches/xen-build +++ b/tools/ioemu/patches/xen-build @@ -1,29 +1,38 @@ Index: ioemu/Makefile =================================================================== ---- ioemu.orig/Makefile 2006-07-25 14:18:33.163941149 +0100 -+++ ioemu/Makefile 2006-07-25 14:24:31.695096861 +0100 -@@ -1,6 +1,9 @@ +--- ioemu.orig/Makefile 2006-08-06 02:03:44.915543858 +0100 ++++ ioemu/Makefile 2006-08-06 02:11:33.461331417 +0100 +@@ -1,11 +1,14 @@ + # Makefile for QEMU. + -include config-host.mak +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Rules.mk ++ ++-include config-host.mak + + .PHONY: all clean distclean dvi info install install-doc tar tarbin \ + speed test test2 html dvi info -CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. -+-include config-host.mak -+ +CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif -@@ -17,7 +20,7 @@ +@@ -25,9 +28,11 @@ DOCS= endif --all: dyngen$(EXESUF) $(TOOLS) $(DOCS) -+all: $(DOCS) - for d in $(TARGET_DIRS); do \ - $(MAKE) -C $$d $@ || exit 1 ; \ - done -@@ -34,7 +37,7 @@ ++TOOLS= ++ + all: $(TOOLS) $(DOCS) recurse-all + +-subdir-%: dyngen$(EXESUF) ++subdir-%: + $(MAKE) -C $(subst subdir-,,$@) all + + recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) +@@ -44,7 +49,7 @@ rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~ $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ @@ -32,26 +41,26 @@ Index: ioemu/Makefile done distclean: clean -@@ -57,12 +60,12 @@ +@@ -68,12 +73,12 @@ install: all $(if $(BUILD_DOCS),install-doc) mkdir -p "$(DESTDIR)$(bindir)" - $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" - mkdir -p "$(DESTDIR)$(datadir)" - for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -- video.x proll.elf linux_boot.bin; do \ +- video.x openbios-sparc32 linux_boot.bin; do \ - $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ - done +# $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" +# mkdir -p "$(DESTDIR)$(datadir)" +# for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -+# video.x proll.elf linux_boot.bin; do \ ++# video.x openbios-sparc32 linux_boot.bin; do \ +# $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ +# done ifndef CONFIG_WIN32 mkdir -p "$(DESTDIR)$(datadir)/keymaps" for x in $(KEYMAPS); do \ -@@ -96,11 +99,11 @@ +@@ -107,11 +112,11 @@ texi2dvi $< qemu.1: qemu-doc.texi @@ -64,11 +73,11 @@ Index: ioemu/Makefile + perl -w $(SRC_PATH)/texi2pod.pl $< qemu-img.pod pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ - FILE=qemu-$(shell cat VERSION) + info: qemu-doc.info qemu-tech.info Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-07-25 14:18:33.163941149 +0100 -+++ ioemu/Makefile.target 2006-07-25 14:24:17.501562050 +0100 +--- ioemu.orig/Makefile.target 2006-08-06 02:03:44.922543079 +0100 ++++ ioemu/Makefile.target 2006-08-06 02:09:22.320951557 +0100 @@ -1,5 +1,8 @@ include config.mak @@ -102,7 +111,7 @@ Index: ioemu/Makefile.target #CFLAGS+=-Werror LDFLAGS=-g LIBS= -@@ -155,6 +165,9 @@ +@@ -167,6 +177,9 @@ DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS+=-lm @@ -112,7 +121,7 @@ Index: ioemu/Makefile.target ifndef CONFIG_USER_ONLY LIBS+=-lz endif -@@ -264,7 +277,7 @@ +@@ -281,7 +294,7 @@ all: $(PROGS) $(QEMU_USER): $(OBJS) @@ -121,7 +130,7 @@ Index: ioemu/Makefile.target ifeq ($(ARCH),alpha) # Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of # the address space (31 bit so sign extending doesn't matter) -@@ -490,10 +503,16 @@ +@@ -528,10 +541,16 @@ clean: rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o @@ -140,8 +149,8 @@ Index: ioemu/Makefile.target include .depend Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-07-25 14:18:33.163941149 +0100 -+++ ioemu/configure 2006-07-25 14:24:17.501562050 +0100 +--- ioemu.orig/configure 2006-08-06 02:03:45.783447220 +0100 ++++ ioemu/configure 2006-08-06 02:09:41.076860544 +0100 @@ -18,8 +18,8 @@ # default parameters @@ -169,7 +178,7 @@ Index: ioemu/configure softmmu="yes" user="no" build_docs="no" -@@ -366,6 +367,8 @@ +@@ -380,6 +381,8 @@ exit 1 fi @@ -178,7 +187,7 @@ Index: ioemu/configure if test -z "$cross_prefix" ; then # --- -@@ -491,14 +494,16 @@ +@@ -505,14 +508,16 @@ datadir="$prefix" docdir="$prefix" bindir="$prefix" @@ -197,7 +206,7 @@ Index: ioemu/configure fi echo "Install prefix $prefix" -@@ -567,6 +572,8 @@ +@@ -583,6 +588,8 @@ echo "mandir=$mandir" >> $config_mak echo "datadir=$datadir" >> $config_mak echo "docdir=$docdir" >> $config_mak @@ -206,7 +215,7 @@ Index: ioemu/configure echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "INSTALL=$install" >> $config_mak -@@ -748,7 +755,7 @@ +@@ -770,7 +777,7 @@ # don't use ln -sf as not all "ln -sf" over write the file/link # rm -f $target_dir/Makefile @@ -215,7 +224,7 @@ Index: ioemu/configure echo "# Automatically generated by configure - do not modify" > $config_mak -@@ -761,6 +768,12 @@ +@@ -784,6 +791,12 @@ interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h @@ -228,7 +237,7 @@ Index: ioemu/configure if test "$target_cpu" = "i386" ; then echo "TARGET_ARCH=i386" >> $config_mak echo "#define TARGET_ARCH \"i386\"" >> $config_h -@@ -823,6 +836,10 @@ +@@ -850,6 +863,10 @@ echo "#define CONFIG_USER_ONLY 1" >> $config_h fi @@ -236,6 +245,6 @@ Index: ioemu/configure + echo "#define CONFIG_DM 1" >> $config_h +fi + - if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then + if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h diff --git a/tools/ioemu/patches/xen-domain-name b/tools/ioemu/patches/xen-domain-name index 2c3efdd2e1..1b4afe2fdd 100644 --- a/tools/ioemu/patches/xen-domain-name +++ b/tools/ioemu/patches/xen-domain-name @@ -1,8 +1,8 @@ Index: ioemu/sdl.c =================================================================== ---- ioemu.orig/sdl.c 2006-07-27 11:16:53.590928008 +0100 -+++ ioemu/sdl.c 2006-07-27 11:16:58.124426148 +0100 -@@ -268,14 +268,14 @@ +--- ioemu.orig/sdl.c 2006-08-06 02:03:48.563137711 +0100 ++++ ioemu/sdl.c 2006-08-06 02:17:16.063137816 +0100 +@@ -273,14 +273,14 @@ static void sdl_update_caption(void) { char buf[1024]; @@ -21,18 +21,18 @@ Index: ioemu/sdl.c static void sdl_hide_cursor(void) Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:57.828458912 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:58.126425927 +0100 -@@ -159,6 +159,8 @@ - #define MAX_CPUS 1 - #endif +--- ioemu.orig/vl.c 2006-08-06 02:16:31.246133963 +0100 ++++ ioemu/vl.c 2006-08-06 02:17:31.428424918 +0100 +@@ -158,6 +158,8 @@ + int acpi_enabled = 1; + int fd_bootchk = 1; +char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; + /***********************************************************/ /* x86 ISA bus support */ -@@ -4699,6 +4701,7 @@ +@@ -5235,6 +5237,7 @@ "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" "-l item1,... output log to %s (use -d ? for a list of log items)\n" @@ -40,7 +40,7 @@ Index: ioemu/vl.c "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" -@@ -4788,6 +4791,7 @@ +@@ -5319,6 +5322,7 @@ QEMU_OPTION_g, QEMU_OPTION_std_vga, QEMU_OPTION_monitor, @@ -48,7 +48,7 @@ Index: ioemu/vl.c QEMU_OPTION_serial, QEMU_OPTION_parallel, QEMU_OPTION_loadvm, -@@ -4861,6 +4865,7 @@ +@@ -5396,6 +5400,7 @@ { "localtime", 0, QEMU_OPTION_localtime }, { "std-vga", 0, QEMU_OPTION_std_vga }, { "monitor", 1, QEMU_OPTION_monitor }, @@ -56,10 +56,10 @@ Index: ioemu/vl.c { "serial", 1, QEMU_OPTION_serial }, { "parallel", 1, QEMU_OPTION_parallel }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, -@@ -5484,6 +5489,9 @@ - exit(1); - } - break; +@@ -6062,6 +6067,9 @@ + case QEMU_OPTION_no_acpi: + acpi_enabled = 0; + break; + case QEMU_OPTION_domainname: + strncat(domain_name, optarg, sizeof(domain_name) - 20); + break; @@ -68,9 +68,9 @@ Index: ioemu/vl.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-07-27 11:16:57.682475072 +0100 -+++ ioemu/vl.h 2006-07-27 11:16:58.127425816 +0100 -@@ -1094,4 +1094,5 @@ +--- ioemu.orig/vl.h 2006-08-06 02:15:39.711878977 +0100 ++++ ioemu/vl.h 2006-08-06 02:17:16.068137258 +0100 +@@ -1185,4 +1185,5 @@ void kqemu_record_dump(void); diff --git a/tools/ioemu/patches/xen-domid b/tools/ioemu/patches/xen-domid index 25fef06d3d..fbf820c69b 100644 --- a/tools/ioemu/patches/xen-domid +++ b/tools/ioemu/patches/xen-domid @@ -1,16 +1,16 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:58.126425927 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:58.296407110 +0100 -@@ -160,6 +160,7 @@ - #endif +--- ioemu.orig/vl.c 2006-08-06 02:17:31.428424918 +0100 ++++ ioemu/vl.c 2006-08-06 02:18:12.550840673 +0100 +@@ -159,6 +159,7 @@ + int fd_bootchk = 1; char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; +extern int domid; /***********************************************************/ /* x86 ISA bus support */ -@@ -4701,6 +4702,7 @@ +@@ -5237,6 +5238,7 @@ "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" "-l item1,... output log to %s (use -d ? for a list of log items)\n" @@ -18,25 +18,25 @@ Index: ioemu/vl.c "-domain-name domain name that we're serving\n" "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" -@@ -4804,6 +4806,8 @@ - QEMU_OPTION_usbdevice, +@@ -5336,6 +5338,8 @@ QEMU_OPTION_smp, QEMU_OPTION_vnc, + QEMU_OPTION_no_acpi, + + QEMU_OPTION_d, }; typedef struct QEMUOption { -@@ -4879,6 +4883,8 @@ - /* temporary options */ +@@ -5415,6 +5419,8 @@ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { "no-acpi", 0, QEMU_OPTION_no_acpi }, + + { "d", HAS_ARG, QEMU_OPTION_d }, { NULL }, }; -@@ -5492,6 +5498,10 @@ +@@ -6070,6 +6076,10 @@ case QEMU_OPTION_domainname: strncat(domain_name, optarg, sizeof(domain_name) - 20); break; diff --git a/tools/ioemu/patches/xen-mm b/tools/ioemu/patches/xen-mm index ac54eefc98..fff0dc22f2 100644 --- a/tools/ioemu/patches/xen-mm +++ b/tools/ioemu/patches/xen-mm @@ -1,8 +1,8 @@ Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-04 10:53:02.019794255 +0100 -+++ ioemu/hw/pc.c 2006-08-04 10:54:56.876531492 +0100 -@@ -639,7 +639,9 @@ +--- ioemu.orig/hw/pc.c 2006-08-06 02:15:39.708879311 +0100 ++++ ioemu/hw/pc.c 2006-08-06 02:18:18.875135656 +0100 +@@ -646,7 +646,9 @@ } /* allocate RAM */ @@ -12,7 +12,7 @@ Index: ioemu/hw/pc.c /* BIOS load */ bios_offset = ram_size + vga_ram_size; -@@ -671,8 +673,10 @@ +@@ -678,8 +680,10 @@ ret = load_image(buf, phys_ram_base + vga_bios_offset); /* setup basic memory access */ @@ -25,20 +25,20 @@ Index: ioemu/hw/pc.c isa_bios_size = bios_size; Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:53:02.472741926 +0100 -+++ ioemu/vl.c 2006-08-04 10:55:48.361590787 +0100 -@@ -159,6 +159,8 @@ - #define MAX_CPUS 1 - #endif +--- ioemu.orig/vl.c 2006-08-06 02:18:12.550840673 +0100 ++++ ioemu/vl.c 2006-08-06 02:18:45.608155528 +0100 +@@ -158,6 +158,8 @@ + int acpi_enabled = 1; + int fd_bootchk = 1; +int xc_handle; + char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; extern int domid; -@@ -5106,6 +5108,9 @@ +@@ -5650,6 +5652,9 @@ QEMUMachine *machine; - char usb_devices[MAX_VM_USB_PORTS][128]; + char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; + unsigned long nr_pages; + xen_pfn_t *page_array; @@ -46,7 +46,7 @@ Index: ioemu/vl.c char qemu_dm_logfilename[64]; -@@ -5342,11 +5347,13 @@ +@@ -5917,11 +5922,13 @@ ram_size = atol(optarg) * 1024 * 1024; if (ram_size <= 0) help(); @@ -60,7 +60,7 @@ Index: ioemu/vl.c break; case QEMU_OPTION_l: { -@@ -5560,6 +5567,41 @@ +@@ -6133,12 +6140,49 @@ /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; @@ -99,12 +99,11 @@ Index: ioemu/vl.c + +#else /* !CONFIG_DM */ + - #ifdef CONFIG_SOFTMMU phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { -@@ -5600,6 +5642,8 @@ + fprintf(stderr, "Could not allocate physical memory\n"); + exit(1); } - #endif +#endif /* !CONFIG_DM */ + diff --git a/tools/ioemu/patches/xen-network b/tools/ioemu/patches/xen-network index f05935a6f1..b110375f90 100644 --- a/tools/ioemu/patches/xen-network +++ b/tools/ioemu/patches/xen-network @@ -1,7 +1,7 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-07-27 11:16:58.823348777 +0100 -+++ ioemu/vl.c 2006-07-27 11:16:59.169310479 +0100 +--- ioemu.orig/vl.c 2006-08-06 02:22:01.556312045 +0100 ++++ ioemu/vl.c 2006-08-06 02:22:53.925474246 +0100 @@ -89,6 +89,7 @@ #include "exec-all.h" @@ -10,7 +10,7 @@ Index: ioemu/vl.c //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT -@@ -2621,11 +2622,11 @@ +@@ -3090,11 +3091,11 @@ #endif static int net_tap_init(VLANState *vlan, const char *ifname1, @@ -24,7 +24,7 @@ Index: ioemu/vl.c char **parg; char ifname[128]; -@@ -2647,6 +2648,7 @@ +@@ -3116,6 +3117,7 @@ parg = args; *parg++ = (char *)setup_script; *parg++ = ifname; @@ -32,7 +32,7 @@ Index: ioemu/vl.c *parg++ = NULL; execv(setup_script, args); _exit(1); -@@ -3201,6 +3203,7 @@ +@@ -3671,6 +3673,7 @@ if (!strcmp(device, "tap")) { char ifname[64]; char setup_script[1024]; @@ -40,7 +40,7 @@ Index: ioemu/vl.c int fd; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { fd = strtol(buf, NULL, 0); -@@ -3213,7 +3216,10 @@ +@@ -3683,7 +3686,10 @@ if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); } @@ -52,7 +52,7 @@ Index: ioemu/vl.c } } else #endif -@@ -4672,7 +4678,7 @@ +@@ -5208,7 +5214,7 @@ "-net tap[,vlan=n],ifname=name\n" " connect the host TAP network interface to VLAN 'n'\n" #else diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config index 93cc5651a0..0cfa684b34 100644 --- a/tools/ioemu/patches/xenstore-block-device-config +++ b/tools/ioemu/patches/xenstore-block-device-config @@ -1,10 +1,10 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-04 10:57:28.920995216 +0100 -+++ ioemu/Makefile.target 2006-08-04 10:57:29.641912123 +0100 -@@ -336,6 +336,7 @@ - VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o - VL_OBJS+= cirrus_vga.o mixeng.o parallel.o +--- ioemu.orig/Makefile.target 2006-08-07 17:42:27.802386071 +0100 ++++ ioemu/Makefile.target 2006-08-07 17:42:28.683289358 +0100 +@@ -358,6 +358,7 @@ + VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o + VL_OBJS+= usb-uhci.o VL_OBJS+= piix4acpi.o +VL_OBJS+= xenstore.o DEFINES += -DHAS_AUDIO @@ -13,7 +13,7 @@ Index: ioemu/Makefile.target Index: ioemu/xenstore.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/xenstore.c 2006-08-04 10:57:29.641912123 +0100 ++++ ioemu/xenstore.c 2006-08-07 17:42:28.684289249 +0100 @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms and conditions of the GNU General @@ -204,9 +204,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:57:29.354945198 +0100 -+++ ioemu/vl.c 2006-08-04 10:57:29.644911777 +0100 -@@ -4711,9 +4711,11 @@ +--- ioemu.orig/vl.c 2006-08-07 17:42:28.393320909 +0100 ++++ ioemu/vl.c 2006-08-07 17:42:28.687288922 +0100 +@@ -5242,9 +5242,11 @@ "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" @@ -217,8 +217,8 @@ Index: ioemu/vl.c +#endif /* !CONFIG_DM */ "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" - "-m megs set virtual RAM size to megs MB [default=%d]\n" -@@ -4844,11 +4846,13 @@ + #ifdef TARGET_I386 +@@ -5370,11 +5372,13 @@ QEMU_OPTION_M, QEMU_OPTION_fda, QEMU_OPTION_fdb, @@ -231,8 +231,8 @@ Index: ioemu/vl.c +#endif /* !CONFIG_DM */ QEMU_OPTION_boot, QEMU_OPTION_snapshot, - QEMU_OPTION_m, -@@ -4915,11 +4919,13 @@ + #ifdef TARGET_I386 +@@ -5445,11 +5449,13 @@ { "M", HAS_ARG, QEMU_OPTION_M }, { "fda", HAS_ARG, QEMU_OPTION_fda }, { "fdb", HAS_ARG, QEMU_OPTION_fdb }, @@ -245,8 +245,8 @@ Index: ioemu/vl.c +#endif /* !CONFIG_DM */ { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, - { "m", HAS_ARG, QEMU_OPTION_m }, -@@ -5255,10 +5261,16 @@ + #ifdef TARGET_I386 +@@ -5797,10 +5803,16 @@ #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif @@ -265,7 +265,7 @@ Index: ioemu/vl.c const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; -@@ -5293,8 +5305,10 @@ +@@ -5861,8 +5873,10 @@ initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; @@ -276,7 +276,7 @@ Index: ioemu/vl.c ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; -@@ -5307,11 +5321,13 @@ +@@ -5875,11 +5889,13 @@ vncviewer = 0; kernel_filename = NULL; kernel_cmdline = ""; @@ -290,7 +290,7 @@ Index: ioemu/vl.c cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); -@@ -5344,7 +5360,11 @@ +@@ -5912,7 +5928,11 @@ break; r = argv[optind]; if (r[0] != '-') { @@ -302,7 +302,7 @@ Index: ioemu/vl.c } else { const QEMUOption *popt; -@@ -5388,6 +5408,7 @@ +@@ -5956,6 +5976,7 @@ case QEMU_OPTION_initrd: initrd_filename = optarg; break; @@ -310,7 +310,7 @@ Index: ioemu/vl.c case QEMU_OPTION_hda: case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: -@@ -5400,6 +5421,7 @@ +@@ -5968,6 +5989,7 @@ cdrom_index = -1; } break; @@ -318,7 +318,7 @@ Index: ioemu/vl.c case QEMU_OPTION_snapshot: snapshot = 1; break; -@@ -5452,11 +5474,13 @@ +@@ -6020,11 +6042,13 @@ case QEMU_OPTION_append: kernel_cmdline = optarg; break; @@ -332,7 +332,7 @@ Index: ioemu/vl.c case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && -@@ -5698,12 +5722,18 @@ +@@ -6274,12 +6298,18 @@ } } @@ -351,15 +351,15 @@ Index: ioemu/vl.c if (!linux_boot && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && -@@ -5717,6 +5747,7 @@ +@@ -6293,6 +6323,7 @@ else boot_device = 'd'; } +#endif /* !CONFIG_DM */ - #if !defined(CONFIG_SOFTMMU) - /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ -@@ -5870,6 +5901,7 @@ + setvbuf(stdout, NULL, _IOLBF, 0); + +@@ -6407,6 +6438,7 @@ #endif /* !CONFIG_DM */ @@ -367,7 +367,7 @@ Index: ioemu/vl.c /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { -@@ -5896,6 +5928,7 @@ +@@ -6433,6 +6465,7 @@ } } } @@ -375,9 +375,9 @@ Index: ioemu/vl.c /* we always create at least one floppy disk */ fd_table[0] = bdrv_new("fda"); -@@ -6031,6 +6064,8 @@ - #endif - init_timers(); +@@ -6511,6 +6544,8 @@ + } + } + qemu_set_fd_handler(xenstore_fd(), xenstore_process_event, NULL, NULL); + @@ -386,8 +386,8 @@ Index: ioemu/vl.c kernel_filename, kernel_cmdline, initrd_filename, Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-08-04 10:57:28.195078886 +0100 -+++ ioemu/monitor.c 2006-08-04 10:57:29.645911662 +0100 +--- ioemu.orig/monitor.c 2006-08-07 17:42:27.132461888 +0100 ++++ ioemu/monitor.c 2006-08-07 17:42:28.688288814 +0100 @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" @@ -396,7 +396,7 @@ Index: ioemu/monitor.c //#define DEBUG //#define DEBUG_COMPLETION -@@ -328,7 +329,7 @@ +@@ -330,7 +331,7 @@ return 0; } @@ -405,7 +405,7 @@ Index: ioemu/monitor.c { BlockDriverState *bs; -@@ -340,7 +341,7 @@ +@@ -342,7 +343,7 @@ eject_device(bs, force); } @@ -416,9 +416,9 @@ Index: ioemu/monitor.c int i; Index: ioemu/block.c =================================================================== ---- ioemu.orig/block.c 2006-08-04 10:57:21.718825369 +0100 -+++ ioemu/block.c 2006-08-04 10:57:29.646911546 +0100 -@@ -750,6 +750,7 @@ +--- ioemu.orig/block.c 2006-08-07 17:42:21.704076241 +0100 ++++ ioemu/block.c 2006-08-07 17:42:28.689288705 +0100 +@@ -758,6 +758,7 @@ static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -428,9 +428,9 @@ Index: ioemu/block.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:57:29.355945083 +0100 -+++ ioemu/vl.h 2006-08-04 10:57:29.647911431 +0100 -@@ -1093,6 +1093,8 @@ +--- ioemu.orig/vl.h 2006-08-07 17:42:28.394320800 +0100 ++++ ioemu/vl.h 2006-08-07 17:42:28.689288705 +0100 +@@ -1184,6 +1184,8 @@ void term_print_help(void); void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size); @@ -439,7 +439,7 @@ Index: ioemu/vl.h /* readline.c */ typedef void ReadLineFunc(void *opaque, const char *str); -@@ -1105,6 +1107,13 @@ +@@ -1196,6 +1198,13 @@ void readline_start(const char *prompt, int is_password, ReadLineFunc *readline_func, void *opaque); @@ -455,9 +455,9 @@ Index: ioemu/vl.h extern char domain_name[]; Index: ioemu/hw/ide.c =================================================================== ---- ioemu.orig/hw/ide.c 2006-08-04 10:57:28.612030827 +0100 -+++ ioemu/hw/ide.c 2006-08-04 10:57:29.648911316 +0100 -@@ -1279,6 +1279,7 @@ +--- ioemu.orig/hw/ide.c 2006-08-07 17:42:27.552414361 +0100 ++++ ioemu/hw/ide.c 2006-08-07 17:42:28.691288487 +0100 +@@ -1158,6 +1158,7 @@ } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port index fe326cffb1..2a0f62dd23 100644 --- a/tools/ioemu/patches/xenstore-write-vnc-port +++ b/tools/ioemu/patches/xenstore-write-vnc-port @@ -1,7 +1,7 @@ Index: ioemu/xenstore.c =================================================================== ---- ioemu.orig/xenstore.c 2006-08-04 10:57:29.641912123 +0100 -+++ ioemu/xenstore.c 2006-08-04 10:57:30.244842629 +0100 +--- ioemu.orig/xenstore.c 2006-08-07 17:42:28.684289249 +0100 ++++ ioemu/xenstore.c 2006-08-07 17:42:28.891266728 +0100 @@ -185,3 +185,31 @@ free(image); free(vec); @@ -36,9 +36,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-04 10:57:29.644911777 +0100 -+++ ioemu/vl.c 2006-08-04 10:57:30.246842399 +0100 -@@ -5976,6 +5976,7 @@ +--- ioemu.orig/vl.c 2006-08-07 17:42:28.687288922 +0100 ++++ ioemu/vl.c 2006-08-07 17:42:28.894266401 +0100 +@@ -6501,6 +6501,7 @@ vnc_display_init(ds, vnc_display); if (vncviewer) vnc_start_viewer(vnc_display); @@ -48,9 +48,9 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-04 10:57:29.647911431 +0100 -+++ ioemu/vl.h 2006-08-04 10:57:30.247842283 +0100 -@@ -1112,6 +1112,7 @@ +--- ioemu.orig/vl.h 2006-08-07 17:42:28.689288705 +0100 ++++ ioemu/vl.h 2006-08-07 17:42:28.895266293 +0100 +@@ -1203,6 +1203,7 @@ int xenstore_fd(void); void xenstore_process_event(void *opaque); void xenstore_check_new_media_present(int timeout);