add slot deletion, rmap chain tests
cover add slot deletion, rmap chain tests
PATCH 1/8 test: allow functions to execute on non-irq context remotely
Which allows code to execute on remote cpus while receiving interrupts.
Also move late smp initialization to common code, and the smp loop to C code.
kvm/user/test/lib/x86/smp.c +54 -1
@@ -114,7 +114,7 @@ void on_cpu_async(int cpu, void (*functi } -void smp_init (void ) +void smp_init_ids (void ) {int i;void ipi_entry (void );
@@ -125,4 +125,57 @@ void smp_init(void)for (i =1 ; i <cpu_count (); ++i)on_cpu (i, setup_smp_id,0 ); +printf ("detected %d cpus\n" ,cpu_count ()); +} + +static void *smp_function (void ) +{ +void *fn; + + asm ("mov %%gs:8, %0" :"=r" (fn)); +return fn; +} + +static void setup_smp_function (void *data) +{ + asm ("mov %0, %%gs:8" : :"r" (data) :"memory" ); +} + +static void *smp_data (void ) +{ +void *fn; + + asm ("mov %%gs:16, %0" :"=r" (fn)); +return fn; +} + +static void setup_smp_data (void *data) +{ + asm ("mov %0, %%gs:16" : :"r" (data) :"memory" ); +} + +void on_cpu_noipi (int cpu,void (*function)(void *data),void *data) +{ +if (cpu ==smp_id ()) +function (data); +else { +on_cpu (cpu, setup_smp_data, data); +on_cpu (cpu, setup_smp_function, function); + } +} + +void smp_loop (void ) +{ +void (*fn)(void *data); +void *data; + + asmvolatile ("hlt" ); +if (smp_id () ==0 ) +return ; + + fn =smp_function (); +if (fn) { +fn (smp_data ()); +setup_smp_function (0 ); + } }
kvm/user/test/lib/x86/smp.h +1 -2
@@ -5,12 +5,11 @@ struct spinlock {int v; }; -void smp_init (void ); -int cpu_count (void );int smp_id (void );void on_cpu (int cpu,void (*function)(void *data),void *data);void on_cpu_async (int cpu,void (*function)(void *data),void *data); +void on_cpu_noipi (int cpu,void (*function)(void *data),void *data);void spin_lock (struct spinlock *lock);void spin_unlock (struct spinlock *lock);
kvm/user/test/x86/cstart64.S +2 -1
@@ -165,7 +165,7 @@ ap_start64: nop lock incw cpu_online_count -1: hlt +1: call smp_loop jmp 1b start64:
@@ -174,6 +174,7 @@ start64: call enable_apic call smp_init call enable_x2apic + call smp_init_ids call main mov %eax, %edi call exit
kvm/user/test/x86/smptest.c +0 -2
@@ -15,8 +15,6 @@ int main()int ncpus;int i; -smp_init (); - ncpus =cpu_count ();printf ("found %d cpus\n" , ncpus);for (i =0 ; i < ncpus; ++i)
kvm/user/test/x86/vmexit.c +0 -2
@@ -155,8 +155,6 @@ int main(void) {int i; -smp_init (); -for (i =0 ; i <ARRAY_SIZE (tests); ++i)do_test (&tests[i]);
Re: [patch 1/8] test: allow functions to execute on non-irq context remotely
Quoted 8 lines · Marcelo Tosatti
Which allows code to execute on remote cpus while receiving interrupts.
Also move late smp initialization to common code, and the smp loop to C code.
kvm/user/test/lib/x86/smp.c void smp_init(void) · line 172
Quoted 7 lines
kvm/user/test/lib/x86/smp.c +7
-0+ +void smp_loop (void ) +{ +void (*fn)(void *data); +void *data; + + asmvolatile ("hlt" );
Racy. The interrupt can happen before the hlt, which will kill the cpu. Needs to be
cli
while not smp_function():
sti; hlt
cli
sti
smp_function()(smp_data())
Also need to make sure two on_cpu_noipi()s don't stomp on each other.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [patch 1/8] test: allow functions to execute on non-irq context remotely
Quoted 7 lines · Avi Kivity
Quoted 4 lines · Marcelo Tosatti
Which allows code to execute on remote cpus while receiving interrupts.
Also move late smp initialization to common code, and the smp loop to C code.
Quoted 10 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ +void smp_loop(void) +{ + void (*fn)(void *data); + void *data; + + asm volatile ("hlt");Racy. The interrupt can happen before the hlt, which will kill the cpu.
Why would it kill the cpu? Only miss the event AFAICS. See patch below.
Quoted 10 lines
Needs to be
cli
while notsmp_function():
sti; hlt
cli
sti
smp_function()(smp_data())Also need to make sure two on_cpu_noipi()s don't stomp on each other.
Only cpu0 requests this ATM, and the IPIs to set function/data are protected by a spinlock which serializes between cpu0<->target.
Its responsability of the caller to synchronization with termination.
Are you OK with this:
test: allow functions to execute on non-irq context remotely
Which allows code to execute on remote cpus while receiving interrupts.
Also move late smp initialization to common code, and the smp loop to C code.
kvm/user/test/lib/x86/smp.c +67 -1
@@ -114,7 +114,7 @@ void on_cpu_async(int cpu, void (*functi } -void smp_init (void ) +void smp_init_ids (void ) {int i;void ipi_entry (void );
@@ -125,4 +125,70 @@ void smp_init(void)for (i =1 ; i <cpu_count (); ++i)on_cpu (i, setup_smp_id,0 ); +printf ("detected %d cpus\n" ,cpu_count ()); +} + +static void *smp_function (void ) +{ +void *fn; + + asm ("mov %%gs:8, %0" :"=r" (fn)); +return fn; +} + +static void setup_smp_function (void *data) +{ + asm ("mov %0, %%gs:8" : :"r" (data) :"memory" ); +} + +static void *smp_data (void ) +{ +void *fn; + + asm ("mov %%gs:16, %0" :"=r" (fn)); +return fn; +} + +static void setup_smp_data (void *data) +{ + asm ("mov %0, %%gs:16" : :"r" (data) :"memory" ); +} + +void on_cpu_noipi (int cpu,void (*function)(void *data),void *data) +{ +if (cpu ==smp_id ()) +function (data); +else { +on_cpu (cpu, setup_smp_data, data); +on_cpu (cpu, setup_smp_function, function); + } +} + +static void irq_disable (void ) +{ + asmvolatile ("cli" ); +} + +static void irq_enable (void ) +{ + asmvolatile ("sti" ); +} + +void smp_loop (void ) +{ +void (*fn)(void *data); + +irq_disable (); + fn =smp_function (); +if (fn) { +setup_smp_function (0 ); +irq_enable (); +fn (smp_data ()); +irq_disable (); + } + +irq_enable (); + asmvolatile ("hlt" ); +irq_disable (); + }
kvm/user/test/lib/x86/smp.h +1 -2
@@ -5,12 +5,11 @@ struct spinlock {int v; }; -void smp_init (void ); -int cpu_count (void );int smp_id (void );void on_cpu (int cpu,void (*function)(void *data),void *data);void on_cpu_async (int cpu,void (*function)(void *data),void *data); +void on_cpu_noipi (int cpu,void (*function)(void *data),void *data);void spin_lock (struct spinlock *lock);void spin_unlock (struct spinlock *lock);
kvm/user/test/x86/cstart64.S +2 -1
@@ -165,7 +165,7 @@ ap_start64: nop lock incw cpu_online_count -1: hlt +1: call smp_loop jmp 1b start64:
@@ -174,6 +174,7 @@ start64: call enable_apic call smp_init call enable_x2apic + call smp_init_ids call main mov %eax, %edi call exit
kvm/user/test/x86/smptest.c +0 -2
@@ -15,8 +15,6 @@ int main()int ncpus;int i; -smp_init (); - ncpus =cpu_count ();printf ("found %d cpus\n" , ncpus);for (i =0 ; i < ncpus; ++i)
kvm/user/test/x86/vmexit.c +0 -2
@@ -155,8 +155,6 @@ int main(void) {int i; -smp_init (); -for (i =0 ; i <ARRAY_SIZE (tests); ++i)do_test (&tests[i]);
Re: [patch 1/8] test: allow functions to execute on non-irq context remotely
Quoted 22 lines · Marcelo Tosatti
Quoted 9 lines · Avi Kivity
Quoted 5 lines · Marcelo Tosatti
Which allows code to execute on remote cpus while receiving interrupts.
Also move late smp initialization to common code, and the smp loop to C code.
Quoted 11 lines
kvm/user/test/lib/x86/smp.c void smp_init(void) · line 191
Quoted 8 lines
kvm/user/test/lib/x86/smp.c +7
-0+ +void smp_loop (void ) +{ +void (*fn)(void *data); +void *data; + + asmvolatile ("hlt" );Racy. The interrupt can happen before the hlt, which will kill the cpu.
Quoted 2 lines
Why would it kill the cpu? Only miss the event AFAICS. See patch below.
If the other cpu won't send it a new event until this one is completed.
Quoted 37 lines
Quoted 11 lines
Needs to be
cli
while notsmp_function():
sti; hlt
cli
sti
smp_function()(smp_data())Also need to make sure two on_cpu_noipi()s don't stomp on each other.
Only cpu0 requests this ATM, and the IPIs to set function/data are protected by a spinlock which serializes between cpu0<->target.
Its responsability of the caller to synchronization with termination.
Are you OK with this:
kvm/user/test/lib/x86/smp.c +17
-0+ +static void irq_disable (void ) +{ + asmvolatile ("cli" ); +} + +static void irq_enable (void ) +{ + asmvolatile ("sti" ); +} + +void smp_loop (void ) +{ +void (*fn)(void *data); + +irq_disable (); + fn =smp_function ();
kvm/user/test/lib/x86/smp.c void smp_init(void) · line 192
Quoted 10 lines
kvm/user/test/lib/x86/smp.c +10
-0+if (fn) { +setup_smp_function (0 ); +irq_enable (); +fn (smp_data ()); +irq_disable (); + } + +irq_enable (); + asmvolatile ("hlt" ); +irq_disable ();
sti; hlt need to be in one asm statement so the compiler does't insert anything (for example a call insn) or the race window opens again.
Even then, can't two cpus overwrite a third cpu's smp_function()?
The most worrying bit is that this follows no known model so the reader doesn't know what to expect. on_cpu() follows Linux, but on_cpu_noipi has no parallel.
What about switching to a thread model? Have a single global runqueue, round robin threads (no preemption, only on calls to schedule()), use cpus_allowed to pin a thread to a cpu.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
PATCH 2/8 test: add pagefault exception handler
In reply to Marcelo TosattiWhich print cr2 and exits.
kvm/user/test/lib/x86/smp.c +35 -8
@@ -5,6 +5,7 @@#include "fwcfg.h" #define IPI_VECTOR 0x20 +#define PF_VECTOR 0xestatic struct spinlock ipi_lock;static void (*ipi_function)(void *data);
@@ -18,6 +19,20 @@ static __attribute__((used)) void ipi() ipi_done =1 ; } +unsigned long read_cr2 () +{ +unsigned long cr2; + + asmvolatile ("mov %%cr2, %0" :"=r" (cr2)); +return cr2; +} + +static __attribute__((used))void pf () +{ +printf ("PF: %lx\n" ,read_cr2 ()); + asm ("call exit" ); +} + asm ("ipi_entry: \n" " call ipi \n"
@@ -28,21 +43,31 @@ asm (#endif ); +asm ( + "pf_entry: \n" + " call pf \n" +#ifndef __x86_64__ + " iret" +#else +" iretq" +#endif + ); + -static void set_ipi_descriptor (void (*ipi_entry)(void )) +static void set_exp_descriptor (void (*entry)(void ),unsigned vec) { -unsigned short *desc = (void *)(IPI_VECTOR *sizeof (long ) *2 ); +unsigned short *desc = (void *)(vec *sizeof (long ) *2 );unsigned short cs; -unsigned long ipi = (unsigned long )ipi_entry; +unsigned long fn = (unsigned long )entry; asm ("mov %%cs, %0" :"=r" (cs)); - desc[0 ] = ipi; + desc[0 ] = fn; desc[1 ] = cs; desc[2 ] =0x8e00 ; - desc[3 ] = ipi >>16 ; + desc[3 ] = fn >>16 ;#ifdef __x86_64__ - desc[4 ] = ipi >>32 ; - desc[5 ] = ipi >>48 ; + desc[4 ] = fn >>32 ; + desc[5 ] = fn >>48 ; desc[6 ] =0 ; desc[7 ] =0 ;#endif
@@ -118,8 +143,10 @@ void smp_init_ids(void) {int i;void ipi_entry (void ); +void pf_entry (void ); -set_ipi_descriptor (ipi_entry); +set_exp_descriptor (ipi_entry,IPI_VECTOR ); +set_exp_descriptor (pf_entry,PF_VECTOR );setup_smp_id (0 );for (i =1 ; i <cpu_count (); ++i)
PATCH 3/8 test: protect fwcfg accesses with lock
In reply to Marcelo TosattiSo multiple CPU's can access fwcfg safely.
kvm/user/test/lib/x86/fwcfg.c +5 -0
@@ -1,4 +1,7 @@#include "fwcfg.h" +#include "smp.h" + +static struct spinlock lock;uint64_t fwcfg_get_u (uint16_t index,int bytes) {
@@ -6,11 +9,13 @@ uint64_t fwcfg_get_u(uint16_t index, intuint8_t b;int i; +spin_lock (&lock); asmvolatile ("out %0, %1" : :"a" (index),"d" ((uint16_t )BIOS_CFG_IOPORT ));for (i =0 ; i < bytes; ++i) { asmvolatile ("in %1, %0" :"=a" (b) :"d" ((uint16_t )(BIOS_CFG_IOPORT +1 ))); r |= (uint64_t )b << (i *8 ); } +spin_unlock (&lock);return r; }
PATCH 4/8 test: export vm helpers
In reply to Marcelo TosattiTo be used by next patches. Also make install_pte take an argument indicating physical location of pagetable.
kvm/user/test/x86/vm.c +17 -68
@@ -3,22 +3,9 @@void const char *s); -#define PAGE_SIZE 4096ul -#define LARGE_PAGE_SIZE (512 * PAGE_SIZE) -static void *free =0 ;static void *vfree_top =0 ; -static unsigned long virt_to_phys (const void *virt) -{ -return (unsigned long )virt; -} - -static void *phys_to_virt (unsigned long phys) -{ -return (void *)phys; -} -void *memset (void *data,int c,unsigned long len) {char *s = data;
@@ -61,15 +48,11 @@ void free_page(void *page)extern char edata;static unsigned long end_of_memory; -#define PTE_PRESENT (1ull << 0) -#define PTE_PSE (1ull << 7) -#define PTE_WRITE (1ull << 1) -#define PTE_ADDR (0xffffffffff000ull) - -static void install_pte (unsigned long *cr3, -int pte_level, +void install_pte (unsigned long *cr3, +int pte_level,void *virt, -unsigned long pte) +unsigned long pte, +unsigned long *pt_page) {int level;unsigned long *pt = cr3;
@@ -78,7 +61,11 @@ static void install_pte(unsigned long *cfor (level =4 ; level > pte_level; --level) { offset = ((unsigned long )virt >> ((level-1 ) *9 +12 )) &511 ;if (!(pt[offset] &PTE_PRESENT )) { -unsigned long *new_pt =alloc_page (); +unsigned long *new_pt = pt_page; +if (!new_pt) + new_pt =alloc_page (); +else + pt_page =0 ;memset (new_pt,0 ,PAGE_SIZE ); pt[offset] =virt_to_phys (new_pt) |PTE_PRESENT |PTE_WRITE ; }
@@ -108,58 +95,20 @@ static unsigned long get_pte(unsigned loreturn pte; } -static void install_large_page (unsigned long *cr3, -unsigned long phys, -void *virt) +void install_large_page (unsigned long *cr3, +unsigned long phys, +void *virt) { -install_pte (cr3,2 , virt, phys |PTE_PRESENT |PTE_WRITE |PTE_PSE ); +install_pte (cr3,2 , virt, phys |PTE_PRESENT |PTE_WRITE |PTE_PSE ,0 ); } -static void install_page (unsigned long *cr3, -unsigned long phys, -void *virt) +void install_page (unsigned long *cr3, +unsigned long phys, +void *virt) { -install_pte (cr3,1 , virt, phys |PTE_PRESENT |PTE_WRITE ); -} - -static inline void load_cr3 (unsigned long cr3) -{ - asm ("mov %0, %%cr3" : :"r" (cr3) ); -} - -static inline unsigned long read_cr3 () -{ -unsigned long cr3; - - asmvolatile ("mov %%cr3, %0" :"=r" (cr3) ); -return cr3; +install_pte (cr3,1 , virt, phys |PTE_PRESENT |PTE_WRITE ,0 ); } -static inline void load_cr0 (unsigned long cr0) -{ - asmvolatile ("mov %0, %%cr0" : :"r" (cr0) ); -} - -static inline unsigned long read_cr0 () -{ -unsigned long cr0; - - asmvolatile ("mov %%cr0, %0" :"=r" (cr0) ); -return cr0; -} - -static inline void load_cr4 (unsigned long cr4) -{ - asmvolatile ("mov %0, %%cr4" : :"r" (cr4) ); -} - -static inline unsigned long read_cr4 () -{ -unsigned long cr4; - - asmvolatile ("mov %%cr4, %0" :"=r" (cr4) ); -return cr4; -}struct gdt_table_descr {
kvm/user/test/x86/vm.h +62 -0
72 lines not on this page · raw message
PATCH 5/8 testdev: add port to create/delete memslots
In reply to Marcelo Tosattihw/testdev.c +45 -0
@@ -5,6 +5,10 @@struct testdev {ISADevice dev;CharDriverState *chr; +struct memslot { +target_phys_addr_t start; +target_phys_addr_t end; + } memslot; };static void test_device_serial_write (void *opaque,uint32_t addr,uint32_t data)
@@ -90,6 +94,45 @@ static CPUWriteMemoryFunc * const test_i test_iomem_writel, }; +#define CMD_CREATE_SLOT 0x0 +#define CMD_DELETE_SLOT 0x1 + +static void test_device_memslot_write (void *opaque,uint32_t addr,uint32_t data) +{ +uint32_t port = addr -0x2018 ; +struct testdev *dev = opaque; + +switch (port) { +case 0 : + dev->memslot.start =0 ; +case 4 : + dev->memslot.start |= (unsigned long )data << (port *8 ); +break ; +case 8 : + dev->memslot.end =0 ; +case 12 : + dev->memslot.end |= (unsigned long )data << ((port-8 ) *8 ); +break ; +case 16 : +if (data ==CMD_CREATE_SLOT ) { +ram_addr_t ram_addr, size; + + size = dev->memslot.end - dev->memslot.start; + + ram_addr =qemu_ram_alloc (size); +cpu_register_physical_memory (dev->memslot.start, size, ram_addr); + } +else if (data ==CMD_DELETE_SLOT ) { +ram_addr_t size = dev->memslot.end - dev->memslot.start; + +cpu_register_physical_memory (dev->memslot.start, size, +IO_MEM_UNASSIGNED ); + } +default : +break ; + } +} +static int init_test_device (ISADevice *isa) { struct testdev *dev = DO_UPCAST(struct testdev, dev, isa);
@@ -105,6 +148,8 @@ static int init_test_device(ISADevice *iregister_ioport_read (0xe0 ,1 ,4 , test_device_ioport_read, dev);register_ioport_write (0xe0 ,1 ,4 , test_device_ioport_write, dev);register_ioport_write (0x2000 ,24 ,1 , test_device_irq_line,NULL ); +register_ioport_write (0x2018 ,20 ,4 , test_device_memslot_write, dev); + iomem_buf =qemu_mallocz (0x10000 ); iomem =cpu_register_io_memory (test_iomem_read, test_iomem_write,NULL );cpu_register_physical_memory (0xff000000 ,0x10000 , iomem);
Re: [patch 5/8] testdev: add port to create/delete memslots
Quoted 2 lines · Marcelo Tosatti
Signed-off-by Marcelo Tosatti<[email protected]>
Whoa, memory hotplug.
Signature · 1 line
error compiling committee.c: too many arguments to function
PATCH 6/8 test: parallel faults vs slot deletion
In reply to Marcelo Tosattikvm/user/config-x86-common.mak +3 -0
@@ -42,6 +42,9 @@ $(TEST_DIR)/sieve.flat: $(cstart.o) $(TE $(TEST_DIR)/print.o $(TEST_DIR)/vm.o $(TEST_DIR)/vmexit.flat: $(cstart.o) $(TEST_DIR)/vmexit.o + +$(TEST_DIR)/slot_deletion.flat: $(cstart.o) $(TEST_DIR)/slot_deletion.o \ + $(TEST_DIR)/print.o $(TEST_DIR)/vm.o $(TEST_DIR)/test32.flat: $(TEST_DIR)/test32.o
kvm/user/config-x86_64.mak +2 -1
@@ -7,6 +7,7 @@ CFLAGS += -D__x86_64__ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/sieve.flat \ $(TEST_DIR)/simple.flat $(TEST_DIR)/stringio.flat \ $(TEST_DIR)/memtest1.flat $(TEST_DIR)/emulator.flat \ - $(TEST_DIR)/hypercall.flat $(TEST_DIR)/apic.flat + $(TEST_DIR)/hypercall.flat $(TEST_DIR)/apic.flat \ + $(TEST_DIR)/slot_deletion.flat include config-x86-common.mak
kvm/user/test/x86/slot_deletion.c new file +130 -0
130 lines not on this page · raw message
PATCH 7/8 test: bump max vcpus to 64
In reply to Marcelo Tosattikvm/user/test/x86/cstart64.S +1 -1
@@ -6,7 +6,7 @@ boot_idt = 0 ipi_vector = 0x20 -max_cpus = 4 +max_cpus = 64 .bss
PATCH 8/8 test: long rmap chains
In reply to Marcelo Tosattikvm/user/config-x86-common.mak +3 -0
@@ -45,6 +45,9 @@ $(TEST_DIR)/vmexit.flat: $(cstart.o) $(T $(TEST_DIR)/slot_deletion.flat: $(cstart.o) $(TEST_DIR)/slot_deletion.o \ $(TEST_DIR)/print.o $(TEST_DIR)/vm.o + +$(TEST_DIR)/rmap_chain.flat: $(cstart.o) $(TEST_DIR)/rmap_chain.o \ + $(TEST_DIR)/print.o $(TEST_DIR)/vm.o $(TEST_DIR)/test32.flat: $(TEST_DIR)/test32.o
kvm/user/config-x86_64.mak +1 -1
@@ -8,6 +8,6 @@ tests = $(TEST_DIR)/access.flat $(TEST_D $(TEST_DIR)/simple.flat $(TEST_DIR)/stringio.flat \ $(TEST_DIR)/memtest1.flat $(TEST_DIR)/emulator.flat \ $(TEST_DIR)/hypercall.flat $(TEST_DIR)/apic.flat \ - $(TEST_DIR)/slot_deletion.flat + $(TEST_DIR)/slot_deletion.flat $(TEST_DIR)/rmap_chain.flat include config-x86-common.mak
kvm/user/test/x86/rmap_chain.c new file +53 -0
53 lines not on this page · raw message