diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-03-15 00:16:44 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-03-15 00:16:44 +0000 |
commit | 998e4cfacfe9217a1d96e9300fbce22cf7e8b6bb (patch) | |
tree | dae6b6e851344579442d3bb7b920cd7511854b0c | |
parent | b500121df2e813156a8fe6220c1e0917be35744e (diff) | |
download | xen-998e4cfacfe9217a1d96e9300fbce22cf7e8b6bb.tar.gz xen-998e4cfacfe9217a1d96e9300fbce22cf7e8b6bb.tar.bz2 xen-998e4cfacfe9217a1d96e9300fbce22cf7e8b6bb.zip |
bitkeeper revision 1.131 (3e7270ecL24hQl_PjDBYoS8hhB8GTA)
multicall.h:
new file
Many files:
Multicall now available, so that Xen syscalls can be batched to amortise cost of trap to ring 0. Used by xenolinux to reduce the cost of a context switch.
-rw-r--r-- | .rootkeys | 1 | ||||
-rw-r--r-- | xen/arch/i386/entry.S | 85 | ||||
-rw-r--r-- | xen/arch/i386/mm.c | 33 | ||||
-rw-r--r-- | xen/common/kernel.c | 2 | ||||
-rw-r--r-- | xen/common/schedule.c | 8 | ||||
-rw-r--r-- | xen/include/hypervisor-ifs/hypervisor-if.h | 259 | ||||
-rw-r--r-- | xen/include/xeno/config.h | 2 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c | 3 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c | 26 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c | 2 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c | 23 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h | 37 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h | 10 | ||||
-rw-r--r-- | xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h | 45 |
14 files changed, 385 insertions, 151 deletions
@@ -529,6 +529,7 @@ 3e5a4e673p7PEOyHFm3nHkYX6HQYBg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/irq.h 3e5a4e67zoNch27qYhEBpr2k6SABOg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu.h 3e5a4e678ddsQOpbSiRdy1GRcDc9WA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h +3e7270deQqtGPSnFxcW4AvJZuTUWfg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h 3e5a4e67mnQfh-R8KcQCaVo2Oho6yg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/page.h 3e5a4e67uTYU5oEnIDjxuaez8njjqg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h 3e5a4e67X7JyupgdYkgDX19Huj2sAw xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable-2level.h diff --git a/xen/arch/i386/entry.S b/xen/arch/i386/entry.S index cd49578168..436d12a8ff 100644 --- a/xen/arch/i386/entry.S +++ b/xen/arch/i386/entry.S @@ -79,6 +79,8 @@ */ #include <xeno/config.h> +#include <xeno/errno.h> +#include <hypervisor-ifs/hypervisor-if.h> #include <asm/smp.h> EBX = 0x00 @@ -184,6 +186,77 @@ ENTRY(ret_from_newdomain) jmp test_all_events ALIGN +/* + * HYPERVISOR_multicall(call_list, nr_calls) + * Execute a list of 'nr_calls' system calls, pointed at by 'call_list'. + * This is fairly easy except that: + * 1. We may fault reading the call list, and must patch that up; and + * 2. We cannot recursively call HYPERVISOR_multicall, or a malicious + * caller could cause our stack to blow up. + */ +stringstring: + .asciz "%08x %08x %08x %08x %08x %08x %d\n" +do_multicall: + popl %eax + cmpl $SYMBOL_NAME(ret_from_hypervisor_call),%eax + jne multicall_exit /* bail if called recursively */ + pushl %ebx + movl 4(%esp),%ebx /* EBX == call_list */ + movl 8(%esp),%ecx /* ECX == nr_calls */ +multicall_loop: + pushl %ecx +multicall_fault1: + pushl 20(%ebx) +multicall_fault2: + pushl 16(%ebx) +multicall_fault3: + pushl 12(%ebx) +multicall_fault4: + pushl 8(%ebx) +multicall_fault5: + pushl 4(%ebx) +multicall_fault6: + movl (%ebx),%eax + andl $255,%eax + call *SYMBOL_NAME(hypervisor_call_table)(,%eax,4) + addl $20,%esp + popl %ecx + addl $BYTES_PER_MULTICALL_ENTRY,%ebx + loop multicall_loop + popl %ebx +multicall_exit: + xorl %eax,%eax + jmp ret_from_hypervisor_call + +.section __ex_table,"a" + .align 4 + .long multicall_fault1, multicall_fixup1 + .long multicall_fault2, multicall_fixup2 + .long multicall_fault3, multicall_fixup3 + .long multicall_fault4, multicall_fixup4 + .long multicall_fault5, multicall_fixup5 + .long multicall_fault6, multicall_fixup6 +.previous + +.section .fixup,"ax" +multicall_fixup6: + addl $4,%esp +multicall_fixup5: + addl $4,%esp +multicall_fixup4: + addl $4,%esp +multicall_fixup3: + addl $4,%esp +multicall_fixup2: + addl $4,%esp +multicall_fixup1: + addl $4,%esp + popl %ebx + movl $-EFAULT,%eax + jmp ret_from_hypervisor_call +.previous + + ALIGN restore_all: RESTORE_ALL @@ -194,7 +267,9 @@ ENTRY(hypervisor_call) GET_CURRENT(%ebx) andl $255,%eax call *SYMBOL_NAME(hypervisor_call_table)(,%eax,4) - movl %eax,EAX(%esp) # save the return value + +ret_from_hypervisor_call: + movl %eax,EAX(%esp) # save the return value test_all_events: mov PROCESSOR(%ebx),%eax @@ -517,10 +592,11 @@ ENTRY(hypervisor_call_table) .long SYMBOL_NAME(do_process_page_updates) .long SYMBOL_NAME(do_console_write) .long SYMBOL_NAME(do_set_gdt) - .long SYMBOL_NAME(do_stack_and_ldt_switch) + .long SYMBOL_NAME(do_stack_switch) + .long SYMBOL_NAME(do_ldt_switch) .long SYMBOL_NAME(do_net_update) .long SYMBOL_NAME(do_fpu_taskswitch) - .long SYMBOL_NAME(do_sched_op) + .long SYMBOL_NAME(do_yield) .long SYMBOL_NAME(kill_domain) .long SYMBOL_NAME(do_dom0_op) .long SYMBOL_NAME(do_network_op) @@ -530,6 +606,7 @@ ENTRY(hypervisor_call_table) .long SYMBOL_NAME(do_update_descriptor) .long SYMBOL_NAME(do_set_fast_trap) .long SYMBOL_NAME(do_dom_mem_op) - .rept NR_syscalls-(.-hypervisor_call_table)/4 + .long SYMBOL_NAME(do_multicall) + .rept NR_syscalls-((.-hypervisor_call_table)/4) .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/xen/arch/i386/mm.c b/xen/arch/i386/mm.c index 2d4d8ddf52..e330c092c6 100644 --- a/xen/arch/i386/mm.c +++ b/xen/arch/i386/mm.c @@ -97,8 +97,7 @@ void __init zap_low_mappings (void) } -long do_stack_and_ldt_switch( - unsigned long ss, unsigned long esp, unsigned long ldts) +long do_stack_switch(unsigned long ss, unsigned long esp) { int nr = smp_processor_id(); struct tss_struct *t = &init_tss[nr]; @@ -106,19 +105,6 @@ long do_stack_and_ldt_switch( if ( (ss == __HYPERVISOR_CS) || (ss == __HYPERVISOR_DS) ) return -1; - if ( ldts != current->mm.ldt_sel ) - { - unsigned long *ptabent; - ptabent = (unsigned long *)GET_GDT_ADDRESS(current); - /* Out of range for GDT table? */ - if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1; - ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */ - /* Not an LDT entry? (S=0b, type =0010b) */ - if ( (*ptabent & 0x00001f00) != 0x00000200 ) return -1; - current->mm.ldt_sel = ldts; - __load_LDT(ldts); - } - current->thread.ss1 = ss; current->thread.esp1 = esp; t->ss1 = ss; @@ -128,6 +114,23 @@ long do_stack_and_ldt_switch( } +long do_ldt_switch(unsigned long ldts) +{ + unsigned long *ptabent; + + ptabent = (unsigned long *)GET_GDT_ADDRESS(current); + /* Out of range for GDT table? */ + if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1; + ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */ + /* Not an LDT entry? (S=0b, type =0010b) */ + if ( ldts && ((*ptabent & 0x00001f00) != 0x00000200) ) return -1; + current->mm.ldt_sel = ldts; + __load_LDT(ldts); + + return 0; +} + + long do_set_gdt(unsigned long *frame_list, int entries) { return -ENOSYS; diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 28eaae9b51..0e4552fe11 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -533,7 +533,7 @@ int console_export(char *str, int len) } -long do_console_write(char *str, int count) +long do_console_write(char *str, unsigned int count) { #define SIZEOF_BUF 256 unsigned char safe_str[SIZEOF_BUF]; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 92bade958f..3ef29e3c5c 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -148,12 +148,10 @@ int wake_up(struct task_struct *p) } /**************************************************************************** - * Domain requested scheduling operations - * KAF: turn it back into do_yield()! + * Voluntarily yield the processor to another domain, until an event occurs. ****************************************************************************/ -long do_sched_op(void) +long do_yield(void) { - /* XXX implement proper */ current->state = TASK_INTERRUPTIBLE; schedule(); return 0; @@ -519,7 +517,7 @@ void schedulers_start(void) * Schedule timeout is used at a number of places and is a bit meaningless * in the context of Xen, as Domains are not able to call these and all * there entry points into Xen should be asynchronous. If a domain wishes - * to block for a while it should use Xen's sched_op entry point. + * to block for a while it should use Xen's sched_op/yield entry point. ****************************************************************************/ static void process_timeout(unsigned long __data) diff --git a/xen/include/hypervisor-ifs/hypervisor-if.h b/xen/include/hypervisor-ifs/hypervisor-if.h index 31cc8b18d8..797605e9c1 100644 --- a/xen/include/hypervisor-ifs/hypervisor-if.h +++ b/xen/include/hypervisor-ifs/hypervisor-if.h @@ -4,101 +4,64 @@ * Interface to Xeno hypervisor. */ -#include "network.h" -#include "block.h" - #ifndef __HYPERVISOR_IF_H__ #define __HYPERVISOR_IF_H__ /* - * Virtual addresses beyond this are not modifiable by guest OSes. - * The machine->physical mapping table starts at this address, read-only - * to all domains except DOM0. + * SEGMENT DESCRIPTOR TABLES */ -#define HYPERVISOR_VIRT_START (0xFC000000UL) -#ifndef machine_to_phys_mapping -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) -#endif - -typedef struct trap_info_st -{ - unsigned char vector; /* exception/interrupt vector */ - unsigned char dpl; /* privilege level */ - unsigned short cs; /* code selector */ - unsigned long address; /* code address */ -} trap_info_t; - - -typedef struct -{ -/* - * PGREQ_XXX: specified in least-significant bits of 'ptr' field. - * All requests specify relevent PTE or PT address in 'ptr'. - * Normal requests specify update value in 'value'. - * Extended requests specify command in least 8 bits of 'value'. - */ -/* A normal page-table update request. */ -#define PGREQ_NORMAL 0 -/* Update an entry in the machine->physical mapping table. */ -#define PGREQ_MPT_UPDATE 1 -/* An extended command. */ -#define PGREQ_EXTENDED_COMMAND 2 -/* DOM0 can make entirely unchecked updates which do not affect refcnts. */ -#define PGREQ_UNCHECKED_UPDATE 3 - unsigned long ptr, val; /* *ptr = val */ -/* Announce a new top-level page table. */ -#define PGEXT_PIN_L1_TABLE 0 -#define PGEXT_PIN_L2_TABLE 1 -#define PGEXT_PIN_L3_TABLE 2 -#define PGEXT_PIN_L4_TABLE 3 -#define PGEXT_UNPIN_TABLE 4 -#define PGEXT_NEW_BASEPTR 5 -#define PGEXT_TLB_FLUSH 6 -#define PGEXT_INVLPG 7 -#define PGEXT_CMD_MASK 255 -#define PGEXT_CMD_SHIFT 8 -} page_update_request_t; +/* 8 entries, plus a TSS entry for each CPU (up to 32 CPUs). */ +#define FIRST_DOMAIN_GDT_ENTRY 40 +/* These are flat segments for domain bootstrap and fallback. */ +#define FLAT_RING1_CS 0x11 +#define FLAT_RING1_DS 0x19 +#define FLAT_RING3_CS 0x23 +#define FLAT_RING3_DS 0x2b /* - * Segment descriptor tables. + * HYPERVISOR "SYSTEM CALLS" */ -/* 8 entries, plus a TSS entry for each CPU (up to 32 CPUs). */ -#define FIRST_DOMAIN_GDT_ENTRY 40 -/* These are flat segments for domain bootstrap and fallback. */ -#define FLAT_RING1_CS 0x11 -#define FLAT_RING1_DS 0x19 -#define FLAT_RING3_CS 0x23 -#define FLAT_RING3_DS 0x2b - /* EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. */ +#define __HYPERVISOR_set_trap_table 0 +#define __HYPERVISOR_pt_update 1 +#define __HYPERVISOR_console_write 2 +#define __HYPERVISOR_set_gdt 3 +#define __HYPERVISOR_stack_switch 4 +#define __HYPERVISOR_ldt_switch 5 +#define __HYPERVISOR_net_update 6 +#define __HYPERVISOR_fpu_taskswitch 7 +#define __HYPERVISOR_yield 8 +#define __HYPERVISOR_exit 9 +#define __HYPERVISOR_dom0_op 10 +#define __HYPERVISOR_network_op 11 +#define __HYPERVISOR_block_io_op 12 +#define __HYPERVISOR_set_debugreg 13 +#define __HYPERVISOR_get_debugreg 14 +#define __HYPERVISOR_update_descriptor 15 +#define __HYPERVISOR_set_fast_trap 16 +#define __HYPERVISOR_dom_mem_op 17 +#define __HYPERVISOR_multicall 18 + +/* And the trap vector is... */ +#define TRAP_INSTR "int $0x82" -#define __HYPERVISOR_set_trap_table 0 -#define __HYPERVISOR_pt_update 1 -#define __HYPERVISOR_console_write 2 -#define __HYPERVISOR_set_gdt 3 -#define __HYPERVISOR_stack_and_ldt_switch 4 -#define __HYPERVISOR_net_update 5 -#define __HYPERVISOR_fpu_taskswitch 6 -#define __HYPERVISOR_sched_op 7 -#define __HYPERVISOR_exit 8 -#define __HYPERVISOR_dom0_op 9 -#define __HYPERVISOR_network_op 10 -#define __HYPERVISOR_block_io_op 11 -#define __HYPERVISOR_set_debugreg 12 -#define __HYPERVISOR_get_debugreg 13 -#define __HYPERVISOR_update_descriptor 14 -#define __HYPERVISOR_set_fast_trap 15 -#define __HYPERVISOR_dom_mem_op 16 -#define TRAP_INSTR "int $0x82" +/* + * MULTICALLS + * + * Multicalls are listed in an array, with each element being a fixed size + * (BYTES_PER_MULTICALL_ENTRY). Each is of the form (op, arg1, ..., argN) + * where each element of the tuple is a machine word. + */ +#define BYTES_PER_MULTICALL_ENTRY 32 -/* Event message note: +/* EVENT MESSAGES * * Here, as in the interrupts to the guestos, additional network interfaces - * are defined. These definitions server as placeholders for the event bits, + * are defined. These definitions server as placeholders for the event bits, * however, in the code these events will allways be referred to as shifted * offsets from the base NET events. */ @@ -113,14 +76,88 @@ typedef struct /* Bit offsets, as opposed to the above masks. */ #define _EVENT_BLK_RESP 0 -#define _EVENT_TIMER 1 -#define _EVENT_DIE 2 -#define _EVENT_NET_TX 3 -#define _EVENT_NET_RX 4 -#define _EVENT_DEBUG 5 +#define _EVENT_TIMER 1 +#define _EVENT_DIE 2 +#define _EVENT_NET_TX 3 +#define _EVENT_NET_RX 4 +#define _EVENT_DEBUG 5 + + +/* + * Virtual addresses beyond this are not modifiable by guest OSes. + * The machine->physical mapping table starts at this address, read-only + * to all domains except DOM0. + */ +#define HYPERVISOR_VIRT_START (0xFC000000UL) +#ifndef machine_to_phys_mapping +#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) +#endif + + +/* + * PAGE UPDATE COMMANDS AND FLAGS + * + * PGREQ_XXX: specified in least-significant bits of 'ptr' field. + * All requests specify relevent PTE or PT address in 'ptr'. + * Normal requests specify update value in 'value'. + * Extended requests specify command in least 8 bits of 'value'. + */ +/* A normal page-table update request. */ +#define PGREQ_NORMAL 0 +/* Update an entry in the machine->physical mapping table. */ +#define PGREQ_MPT_UPDATE 1 +/* An extended command. */ +#define PGREQ_EXTENDED_COMMAND 2 +/* DOM0 can make entirely unchecked updates which do not affect refcnts. */ +#define PGREQ_UNCHECKED_UPDATE 3 +/* Announce a new top-level page table. */ +#define PGEXT_PIN_L1_TABLE 0 +#define PGEXT_PIN_L2_TABLE 1 +#define PGEXT_PIN_L3_TABLE 2 +#define PGEXT_PIN_L4_TABLE 3 +#define PGEXT_UNPIN_TABLE 4 +#define PGEXT_NEW_BASEPTR 5 +#define PGEXT_TLB_FLUSH 6 +#define PGEXT_INVLPG 7 +#define PGEXT_CMD_MASK 255 +#define PGEXT_CMD_SHIFT 8 + +#ifndef __ASSEMBLY__ + +#include "network.h" +#include "block.h" /* + * Send an array of these to HYPERVISOR_set_trap_table() + */ +typedef struct trap_info_st +{ + unsigned char vector; /* exception/interrupt vector */ + unsigned char dpl; /* privilege level */ + unsigned short cs; /* code selector */ + unsigned long address; /* code address */ +} trap_info_t; + +/* + * Send an array of these to HYPERVISOR_pt_update() + */ +typedef struct +{ + unsigned long ptr, val; /* *ptr = val */ +} page_update_request_t; + +/* + * Send an array of these to HYPERVISOR_multicall() + */ +typedef struct +{ + unsigned long op; + unsigned long args[7]; +} multicall_entry_t; + +/* + * Xen/guestos shared data -- pointer provided in start_info. * NB. We expect that this struct is smaller than a page. */ typedef struct shared_info_st { @@ -150,36 +187,34 @@ typedef struct shared_info_st { * registers, and executing 'iret'. * This callback is provided with an extended stack frame, augmented * with saved values for segment registers %ds and %es: - * %ds, %es, %eip, %cs, %eflags [, %oldesp, %oldss] + * %ds, %es, %eip, %cs, %eflags [, %oldesp, %oldss] * Code segment is the default flat selector. * FAULTS WHEN CALLING THIS HANDLER WILL TERMINATE THE DOMAIN!!! */ unsigned long failsafe_address; - /* - * Time: - * The following abstractions are exposed: System Time, Wall Clock - * Time, Domain Virtual Time. Domains can access Cycle counter time - * directly. - * XXX RN: Need something to pass NTP scaling to GuestOS. + /* + * Time: The following abstractions are exposed: System Time, Clock Time, + * Domain Virtual Time. Domains can access Cycle counter time directly. + * XXX RN: Need something to pass NTP scaling to GuestOS. */ - u64 cpu_freq; /* to calculate ticks -> real time */ - - /* System Time */ - long long system_time; /* in ns */ - unsigned long st_timestamp; /* cyclecounter at last update */ + u64 cpu_freq; /* to calculate ticks -> real time */ - /* Wall Clock Time */ - u32 wc_version; /* a version number for info below */ - long tv_sec; /* essentially a struct timeval */ - long tv_usec; - long long wc_timestamp; /* system time at last update */ + /* System Time */ + long long system_time; /* in ns */ + unsigned long st_timestamp; /* cyclecounter at last update */ - /* Domain Virtual Time */ - unsigned long long domain_time; + /* Wall Clock Time */ + u32 wc_version; /* a version number for info below */ + long tv_sec; /* essentially a struct timeval */ + long tv_usec; + long long wc_timestamp; /* system time at last update */ + + /* Domain Virtual Time */ + unsigned long long domain_time; - /* + /* * Timeout values: * Allow a domain to specify a timeout value in system time and * domain virtual time. @@ -193,18 +228,20 @@ typedef struct shared_info_st { * NB. We expect that this struct is smaller than a page. */ typedef struct start_info_st { - unsigned long nr_pages; /* total pages allocated to this domain */ - shared_info_t *shared_info; /* VIRTUAL address of shared info struct */ - unsigned long pt_base; /* VIRTUAL address of page directory */ - unsigned long mod_start; /* VIRTUAL address of pre-loaded module */ - unsigned long mod_len; /* size (bytes) of pre-loaded module */ - net_ring_t *net_rings; /* network rings (VIRTUAL ADDRESS) */ + unsigned long nr_pages; /* total pages allocated to this domain */ + shared_info_t *shared_info; /* VIRTUAL address of shared info struct */ + unsigned long pt_base; /* VIRTUAL address of page directory */ + unsigned long mod_start; /* VIRTUAL address of pre-loaded module */ + unsigned long mod_len; /* size (bytes) of pre-loaded module */ + net_ring_t *net_rings; /* network rings (VIRTUAL ADDRESS) */ int num_net_rings; - unsigned long blk_ring; /* block io ring (MACHINE ADDRESS) */ - unsigned char cmd_line[1]; /* variable-length */ + unsigned long blk_ring; /* block io ring (MACHINE ADDRESS) */ + unsigned char cmd_line[1]; /* variable-length */ } start_info_t; /* For use in guest OSes. */ extern shared_info_t *HYPERVISOR_shared_info; +#endif /* !__ASSEMBLY__ */ + #endif /* __HYPERVISOR_IF_H__ */ diff --git a/xen/include/xeno/config.h b/xen/include/xeno/config.h index 08cc5cb0dd..3687748a0b 100644 --- a/xen/include/xeno/config.h +++ b/xen/include/xeno/config.h @@ -114,7 +114,7 @@ #define __GUEST_CS 0x11 #define __GUEST_DS 0x19 -#define NR_syscalls 255 +#define NR_syscalls 256 #define offsetof(_p,_f) ((unsigned long)&(((_p *)0)->_f)) #define struct_cpy(_x,_y) (memcpy((_x),(_y),sizeof(*(_x)))) diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c index c49087173f..68670daa8c 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c @@ -13,6 +13,9 @@ #include <asm/system.h> #include <asm/ptrace.h> +multicall_entry_t multicall_list[8]; +int nr_multicall_ents = 0; + static unsigned long event_mask = 0; void frobb(void) {} diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c index a4e4cd2497..32ce1a66ab 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c @@ -43,6 +43,7 @@ #include <asm/i387.h> #include <asm/desc.h> #include <asm/mmu_context.h> +#include <asm/multicall.h> #include <linux/irq.h> @@ -85,7 +86,7 @@ void cpu_idle (void) while (1) { while (!current->need_resched) - HYPERVISOR_do_sched_op(NULL); + HYPERVISOR_yield(); schedule(); check_pgt_cache(); } @@ -334,9 +335,28 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; - unlazy_fpu(prev_p); + /* + * This is basically 'unlazy_fpu', except that we queue a multicall to + * indicate FPU task switch, rather than synchronously trapping to Xen. + */ + if ( prev_p->flags & PF_USEDFPU ) + { + if ( cpu_has_fxsr ) + asm volatile( "fxsave %0 ; fnclex" + : "=m" (prev_p->thread.i387.fxsave) ); + else + asm volatile( "fnsave %0 ; fwait" + : "=m" (prev_p->thread.i387.fsave) ); + prev_p->flags &= ~PF_USEDFPU; + queue_multicall0(__HYPERVISOR_fpu_taskswitch); + } + + if ( next->esp0 != 0 ) + queue_multicall2(__HYPERVISOR_stack_switch, __KERNEL_DS, next->esp0); - HYPERVISOR_stack_and_ldt_switch(__KERNEL_DS, next->esp0, 0); + /* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */ + execute_multicall_list(); + sti(); /* matches 'cli' in switch_mm() */ /* * Save away %fs and %gs. No need to save %es and %ds, as diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c index 1650d7028f..00c68a836f 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c @@ -967,7 +967,7 @@ void __init cpu_init (void) BUG(); enter_lazy_tlb(&init_mm, current, nr); - HYPERVISOR_stack_and_ldt_switch(__KERNEL_DS, current->thread.esp0, 0); + HYPERVISOR_stack_switch(__KERNEL_DS, current->thread.esp0); /* Force FPU initialization. */ current->flags &= ~PF_USEDFPU; diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c index 135ed5c066..93554c3420 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c @@ -11,6 +11,7 @@ #include <asm/hypervisor.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <asm/multicall.h> /* * This suffices to protect us if we ever move to SMP domains. @@ -85,6 +86,28 @@ static void DEBUG_disallow_pt_read(unsigned long pa) */ unsigned long pt_baseptr; +/* + * MULTICALL_flush_page_update_queue: + * This is a version of the flush which queues as part of a multicall. + */ +void MULTICALL_flush_page_update_queue(void) +{ + unsigned long flags; + spin_lock_irqsave(&update_lock, flags); + if ( idx != 0 ) + { +#if PT_UPDATE_DEBUG > 1 + printk("Flushing %d entries from pt update queue\n", idx); +#endif +#if PT_UPDATE_DEBUG > 0 + DEBUG_allow_pt_reads(); +#endif + queue_multicall2(__HYPERVISOR_pt_update, update_queue, idx); + idx = 0; + } + spin_unlock_irqrestore(&update_lock, flags); +} + static inline void __flush_page_update_queue(void) { #if PT_UPDATE_DEBUG > 1 diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h index 16f37cfe65..4b9591102c 100644 --- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h +++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h @@ -129,6 +129,7 @@ static inline int flush_page_update_queue(void) return idx; } #define XENO_flush_page_update_queue() (_flush_page_update_queue()) +void MULTICALL_flush_page_update_queue(void); /* @@ -183,14 +184,24 @@ static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries) return ret; } -static inline int HYPERVISOR_stack_and_ldt_switch( - unsigned long ss, unsigned long esp, unsigned long ldts) +static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp) { int ret; __asm__ __volatile__ ( TRAP_INSTR - : "=a" (ret) : "0" (__HYPERVISOR_stack_and_ldt_switch), - "b" (ss), "c" (esp), "d" (ldts) ); + : "=a" (ret) : "0" (__HYPERVISOR_stack_switch), + "b" (ss), "c" (esp) : "memory" ); + + return ret; +} + +static inline int HYPERVISOR_ldt_switch(unsigned long ldts) +{ + int ret; + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret) : "0" (__HYPERVISOR_ldt_switch), + "b" (ldts) : "memory" ); return ret; } @@ -215,13 +226,12 @@ static inline int HYPERVISOR_fpu_taskswitch(void) return ret; } -static inline int HYPERVISOR_do_sched_op(void *sched_op) +static inline int HYPERVISOR_yield(void) { int ret; __asm__ __volatile__ ( TRAP_INSTR - : "=a" (ret) : "0" (__HYPERVISOR_sched_op), - "b" (sched_op) ); + : "=a" (ret) : "0" (__HYPERVISOR_yield) ); return ret; } @@ -296,7 +306,7 @@ static inline int HYPERVISOR_update_descriptor( int ret; __asm__ __volatile__ ( TRAP_INSTR - : "=a" (ret) : "0" (__HYPERVISOR_set_gdt), + : "=a" (ret) : "0" (__HYPERVISOR_update_descriptor), "b" (pa), "c" (word1), "d" (word2) ); return ret; @@ -324,4 +334,15 @@ static inline int HYPERVISOR_dom_mem_op(void *dom_mem_op) return ret; } +static inline int HYPERVISOR_multicall(void *call_list, int nr_calls) +{ + int ret; + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret) : "0" (__HYPERVISOR_multicall), + "b" (call_list), "c" (nr_calls) : "memory" ); + + return ret; +} + #endif /* __HYPERVISOR_H__ */ diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h index c5b3cdcd61..ad07796f95 100644 --- a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h +++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h @@ -5,6 +5,7 @@ #include <asm/desc.h> #include <asm/atomic.h> #include <asm/pgalloc.h> +#include <asm/multicall.h> /* * possibly do the LDT unload here? @@ -33,6 +34,7 @@ extern pgd_t *cur_pgd; static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) { + cli(); /* protect flush_update_queue multicall */ if (prev != next) { /* stop flush ipis for the previous mm */ clear_bit(cpu, &prev->cpu_vm_mask); @@ -50,7 +52,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str /* Re-load page tables */ cur_pgd = next->pgd; queue_pt_switch(__pa(cur_pgd)); - XENO_flush_page_update_queue(); + MULTICALL_flush_page_update_queue(); } #ifdef CONFIG_SMP else { @@ -70,6 +72,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str } #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL,smp_processor_id()) +do { \ + switch_mm((prev),(next),NULL,smp_processor_id()); \ + execute_multicall_list(); \ + sti(); /* matches 'cli' in switch_mm() */ \ +} while ( 0 ) #endif diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h new file mode 100644 index 0000000000..27126dcaac --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * multicall.h + */ + +#ifndef __MULTICALL_H__ +#define __MULTICALL_H__ + +#include <asm/hypervisor.h> + +extern multicall_entry_t multicall_list[]; +extern int nr_multicall_ents; + +static inline void queue_multicall0(unsigned long op) +{ + int i = nr_multicall_ents; + multicall_list[i].op = op; + nr_multicall_ents = i+1; +} + +static inline void queue_multicall1(unsigned long op, unsigned long arg1) +{ + int i = nr_multicall_ents; + multicall_list[i].op = op; + multicall_list[i].args[0] = arg1; + nr_multicall_ents = i+1; +} + +static inline void queue_multicall2( + unsigned long op, unsigned long arg1, unsigned long arg2) +{ + int i = nr_multicall_ents; + multicall_list[i].op = op; + multicall_list[i].args[0] = arg1; + multicall_list[i].args[1] = arg2; + nr_multicall_ents = i+1; +} + +static inline void execute_multicall_list(void) +{ + if ( unlikely(nr_multicall_ents == 0) ) return; + (void)HYPERVISOR_multicall(multicall_list, nr_multicall_ents); + nr_multicall_ents = 0; +} + +#endif /* __MULTICALL_H__ */ |