Re: [PATCH 17/17] arm: vectors support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Feb 01, 2014 at 06:29:27PM -0800, Christoffer Dall wrote:
> On Tue, Jan 21, 2014 at 05:22:03PM +0100, Andrew Jones wrote:
> > Add support for tests to use exception handlers.
> > 
> > v2 -> v3:
> > - squashed in 'arm: Simplify exceptions_init in cstart.S' from
> >   Christoffer Dall
> > - suggested function name changes and comment additions [Christoffer Dall]
> > - fix a bug with stack restore from usr mode exceptions that Christoffer
> >   pointed out. Add a get_sp() accessor too.
> 
> hmmm, how did you address this, the only change I can see is using r6
> instead of r2, which I'm not sure how changes anything.

It also adds

	/* make sure we restore sp_svc and lr_svc on mode change */
	str	r6, [sp, #S_SP]
	str	lr, [sp, #S_LR]

lower down. Needed to switch to r6 from r2 for that

> 
> The problem is that your ldmia is replacing the usr sp, not the svc sp,
> so maybe you need to do ldmia sp!, [ r0 - pc ]^ (don't remember if that
> particular combination works) or you need to do something more fancy...

I'm not sure about the magic ! + ^ stuff, but what I've done does fix
the problem. I tested before/after the fix (actually that's why I also
added the get_sp).

> 
> Otherwise this is looking good.

Thanks!! v4 coming soon.

> 
> Thanks,
> Christoffer
> 
> > 
> > Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx>
> > ---
> >  arm/cstart.S          | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  arm/flat.lds          |   7 ++-
> >  arm/selftest.c        | 119 +++++++++++++++++++++++++++++++++++
> >  arm/unittests.cfg     |  20 +++++-
> >  config/config-arm.mak |   1 +
> >  lib/arm/processor.c   | 103 +++++++++++++++++++++++++++++++
> >  lib/arm/processor.h   |  35 +++++++++++
> >  lib/libcflat.h        |   2 +
> >  8 files changed, 453 insertions(+), 2 deletions(-)
> >  create mode 100644 lib/arm/processor.c
> >  create mode 100644 lib/arm/processor.h
> > 
> > diff --git a/arm/cstart.S b/arm/cstart.S
> > index 4de04b62c28c2..74674fd41c1b3 100644
> > --- a/arm/cstart.S
> > +++ b/arm/cstart.S
> > @@ -1,3 +1,7 @@
> > +#define __ASSEMBLY__
> > +#include "arm/asm-offsets.h"
> > +#include "arm/ptrace.h"
> > +#include "arm/cp15.h"
> >  
> >  .arm
> >  
> > @@ -10,6 +14,13 @@ start:
> >  	 * See the kernel doc Documentation/arm/Booting
> >  	 */
> >  	ldr	sp, =stacktop
> > +	push	{r0-r3}
> > +
> > +	/* set up vector table and mode stacks */
> > +	bl	exceptions_init
> > +
> > +	/* complete setup */
> > +	pop	{r0-r3}
> >  	bl	setup
> >  
> >  	/* start the test */
> > @@ -20,9 +31,166 @@ start:
> >  	bl	exit
> >  	b	halt
> >  
> > +.macro set_mode_stack mode, stack
> > +	add	\stack, #S_FRAME_SIZE
> > +	msr	cpsr_c, #(\mode | PSR_I_BIT | PSR_F_BIT)
> > +	mov	sp, \stack
> > +.endm
> > +
> > +exceptions_init:
> > +	mrc	p15, 0, r2, c1, c0, 0	@ read SCTLR
> > +	bic	r2, #CR_V		@ SCTLR.V := 0
> > +	mcr	p15, 0, r2, c1, c0, 0	@ write SCTLR
> > +	ldr	r2, =vector_table
> > +	mcr	p15, 0, r2, c12, c0, 0	@ write VBAR
> > +
> > +	mrs	r2, cpsr
> > +	ldr	r1, =exception_stacks
> > +		/* first frame for svc mode */
> > +	set_mode_stack	UND_MODE, r1
> > +	set_mode_stack	ABT_MODE, r1
> > +	set_mode_stack	IRQ_MODE, r1
> > +	set_mode_stack	FIQ_MODE, r1
> > +	msr	cpsr_cxsf, r2	@ back to svc mode
> > +	mov	pc, lr
> > +
> >  .text
> >  
> >  .globl halt
> >  halt:
> >  1:	wfi
> >  	b	1b
> > +
> > +/*
> > + * Vector stubs.
> > + * Simplified version of the Linux kernel implementation
> > + *   arch/arm/kernel/entry-armv.S
> > + *
> > + * Each mode has an S_FRAME_SIZE sized stack initialized
> > + * in exceptions_init
> > + */
> > +.macro vector_stub, name, vec, mode, correction=0
> > +.align 5
> > +vector_\name:
> > +.if \correction
> > +	sub	lr, lr, #\correction
> > +.endif
> > +	/*
> > +	 * Save r0, r1, lr_<exception> (parent PC)
> > +	 * and spsr_<exception> (parent CPSR)
> > +	 */
> > +	str	r0, [sp, #S_R0]
> > +	str	r1, [sp, #S_R1]
> > +	str	lr, [sp, #S_PC]
> > +	mrs	r0, spsr
> > +	str	r0, [sp, #S_PSR]
> > +
> > +	/* Prepare for SVC32 mode. */
> > +	mrs	r0, cpsr
> > +	bic	r0, #MODE_MASK
> > +	orr	r0, #SVC_MODE
> > +	msr	spsr_cxsf, r0
> > +
> > +	/* Branch to handler in SVC mode */
> > +	mov	r0, #\vec
> > +	mov	r1, sp
> > +	ldr	lr, =vector_common
> > +	movs	pc, lr
> > +.endm
> > +
> > +vector_stub 	rst,	0, UND_MODE
> > +vector_stub	und,	1, UND_MODE
> > +vector_stub	pabt,	3, ABT_MODE, 4
> > +vector_stub	dabt,	4, ABT_MODE, 8
> > +vector_stub	irq,	6, IRQ_MODE, 4
> > +vector_stub	fiq,	7, FIQ_MODE, 4
> > +
> > +.align 5
> > +vector_svc:
> > +	/*
> > +	 * Save r0, r1, lr_<exception> (parent PC)
> > +	 * and spsr_<exception> (parent CPSR)
> > +	 */
> > +	push	{ r1 }
> > +	ldr	r1, =exception_stacks
> > +	str	r0, [r1, #S_R0]
> > +	pop	{ r0 }
> > +	str	r0, [r1, #S_R1]
> > +	str	lr, [r1, #S_PC]
> > +	mrs	r0, spsr
> > +	str	r0, [r1, #S_PSR]
> > +
> > +	/*
> > +	 * Branch to handler, still in SVC mode.
> > +	 * r0 := 2 is the svc vector number.
> > +	 */
> > +	mov	r0, #2
> > +	ldr	lr, =vector_common
> > +	mov	pc, lr
> > +
> > +vector_common:
> > +	/* make room for pt_regs */
> > +	sub	sp, #S_FRAME_SIZE
> > +	tst	sp, #4			@ check stack alignment
> > +	subne	sp, #4
> > +
> > +	/* store registers r0-r12 */
> > +	stmia	sp, { r0-r12 }		@ stored wrong r0 and r1, fix later
> > +
> > +	/* get registers saved in the stub */
> > +	ldr	r2, [r1, #S_R0]		@ r0
> > +	ldr	r3, [r1, #S_R1]		@ r1
> > +	ldr	r4, [r1, #S_PC] 	@ lr_<exception> (parent PC)
> > +	ldr	r5, [r1, #S_PSR]	@ spsr_<exception> (parent CPSR)
> > +
> > +	/* fix r0 and r1 */
> > +	str	r2, [sp, #S_R0]
> > +	str	r3, [sp, #S_R1]
> > +
> > +	/* store sp_svc, if we were in usr mode we'll fix this later */
> > +	add	r6, sp, #S_FRAME_SIZE
> > +	addne	r6, #4			@ stack wasn't aligned
> > +	str	r6, [sp, #S_SP]
> > +
> > +	str	lr, [sp, #S_LR]		@ store lr_svc, fix later for usr mode
> > +	str	r4, [sp, #S_PC]		@ store lr_<exception>
> > +	str	r5, [sp, #S_PSR]	@ store spsr_<exception>
> > +
> > +	/* set ORIG_r0 */
> > +	mov	r2, #-1
> > +	str	r2, [sp, #S_OLD_R0]
> > +
> > +	/* if we were in usr mode then we need sp_usr and lr_usr instead */
> > +	and	r1, r5, #MODE_MASK
> > +	cmp	r1, #USR_MODE
> > +	bne	1f
> > +	add	r1, sp, #S_SP
> > +	stmia	r1, { sp,lr }^
> > +
> > +	/* Call the handler. r0 is the vector number, r1 := pt_regs */
> > +1:	mov	r1, sp
> > +	bl	do_handle_exception
> > +
> > +	/* make sure we restore sp_svc and lr_svc on mode change */
> > +	str	r6, [sp, #S_SP]
> > +	str	lr, [sp, #S_LR]
> > +
> > +	/* return from exception */
> > +	msr	spsr_cxsf, r5
> > +	ldmia	sp, { r0-pc }^
> > +
> > +.align 5
> > +vector_addrexcptn:
> > +	b	vector_addrexcptn
> > +
> > +.section .text.ex
> > +.align 5
> > +vector_table:
> > +	b	vector_rst
> > +	b	vector_und
> > +	b	vector_svc
> > +	b	vector_pabt
> > +	b	vector_dabt
> > +	b	vector_addrexcptn	@ should never happen
> > +	b	vector_irq
> > +	b	vector_fiq
> > diff --git a/arm/flat.lds b/arm/flat.lds
> > index 3e5d72e24989b..ee9fc0ab79abc 100644
> > --- a/arm/flat.lds
> > +++ b/arm/flat.lds
> > @@ -3,7 +3,12 @@ SECTIONS
> >  {
> >      .text : { *(.init) *(.text) *(.text.*) }
> >      . = ALIGN(4K);
> > -    .data : { *(.data) }
> > +    .data : {
> > +        exception_stacks = .;
> > +        . += 4K;
> > +        exception_stacks_end = .;
> > +        *(.data)
> > +    }
> >      . = ALIGN(16);
> >      .rodata : { *(.rodata) }
> >      . = ALIGN(16);
> > diff --git a/arm/selftest.c b/arm/selftest.c
> > index 3d47a16cbcfad..96ebfe3454e63 100644
> > --- a/arm/selftest.c
> > +++ b/arm/selftest.c
> > @@ -1,9 +1,119 @@
> >  #include "libcflat.h"
> >  #include "arm/sysinfo.h"
> > +#include "arm/ptrace.h"
> > +#include "arm/processor.h"
> > +#include "arm/asm-offsets.h"
> >  
> >  #define PASS 0
> >  #define FAIL 1
> >  
> > +static struct pt_regs expected_regs;
> > +/*
> > + * Capture the current register state and execute an instruction
> > + * that causes an exception. The test handler will check that its
> > + * capture of the current register state matches the capture done
> > + * here.
> > + *
> > + * NOTE: update clobber list if passed insns needs more than r0,r1
> > + */
> > +#define test_exception(pre_insns, excptn_insn, post_insns)	\
> > +	asm volatile(						\
> > +		pre_insns "\n"					\
> > +		"mov	r0, %0\n"				\
> > +		"stmia	r0, { r0-lr }\n"			\
> > +		"mrs	r1, cpsr\n"				\
> > +		"str	r1, [r0, #" __stringify(S_PSR) "]\n"	\
> > +		"mov	r1, #-1\n"				\
> > +		"str	r1, [r0, #" __stringify(S_OLD_R0) "]\n"	\
> > +		"add	r1, pc, #8\n"				\
> > +		"str	r1, [r0, #" __stringify(S_R1) "]\n"	\
> > +		"str	r1, [r0, #" __stringify(S_PC) "]\n"	\
> > +		excptn_insn "\n"				\
> > +		post_insns "\n"					\
> > +	:: "r" (&expected_regs) : "r0", "r1")
> > +
> > +static bool check_regs(struct pt_regs *regs)
> > +{
> > +	unsigned i;
> > +
> > +	/* exception handlers should always run in svc mode */
> > +	if (current_mode() != SVC_MODE)
> > +		return false;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) {
> > +		if (regs->uregs[i] != expected_regs.uregs[i])
> > +			return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static bool und_works;
> > +static void und_handler(struct pt_regs *regs)
> > +{
> > +	und_works = check_regs(regs);
> > +}
> > +
> > +static bool check_und(void)
> > +{
> > +	install_exception_handler(EXCPTN_UND, und_handler);
> > +
> > +	/* issue an instruction to a coprocessor we don't have */
> > +	test_exception("", "mcr p2, 0, r0, c0, c0", "");
> > +
> > +	install_exception_handler(EXCPTN_UND, NULL);
> > +
> > +	return und_works;
> > +}
> > +
> > +static bool svc_works;
> > +static void svc_handler(struct pt_regs *regs)
> > +{
> > +	u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff;
> > +
> > +	if (processor_mode(regs) == SVC_MODE) {
> > +		/*
> > +		 * When issuing an svc from supervisor mode lr_svc will
> > +		 * get corrupted. So before issuing the svc, callers must
> > +		 * always push it on the stack. We pushed it to offset 4.
> > +		 */
> > +		regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4);
> > +	}
> > +
> > +	svc_works = check_regs(regs) && svc == 123;
> > +}
> > +
> > +static bool check_svc(void)
> > +{
> > +	install_exception_handler(EXCPTN_SVC, svc_handler);
> > +
> > +	if (current_mode() == SVC_MODE) {
> > +		/*
> > +		 * An svc from supervisor mode will corrupt lr_svc and
> > +		 * spsr_svc. We need to save/restore them separately.
> > +		 */
> > +		test_exception(
> > +			"mrs	r0, spsr\n"
> > +			"push	{ r0,lr }\n",
> > +			"svc	#123\n",
> > +			"pop	{ r0,lr }\n"
> > +			"msr	spsr_cxsf, r0\n"
> > +		);
> > +	} else {
> > +		test_exception("", "svc #123", "");
> > +	}
> > +
> > +	install_exception_handler(EXCPTN_SVC, NULL);
> > +
> > +	return svc_works;
> > +}
> > +
> > +static void check_vectors(void)
> > +{
> > +	int ret = check_und() && check_svc() ? PASS : FAIL;
> > +	exit(ret);
> > +}
> > +
> >  static void assert_enough_args(int nargs, int needed)
> >  {
> >  	if (nargs < needed) {
> > @@ -24,6 +134,15 @@ int main(int argc, char **argv)
> >  
> >  		if (mem_size/1024/1024 == (size_t)atol(argv[1]))
> >  			ret = PASS;
> > +
> > +	} else if (strcmp(argv[0], "vectors") == 0) {
> > +
> > +		check_vectors(); /* doesn't return */
> > +
> > +	} else if (strcmp(argv[0], "vectors_usr") == 0) {
> > +
> > +		start_usr(check_vectors); /* doesn't return */
> > +
> >  	}
> >  
> >  	return ret;
> > diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> > index aff684892e90b..75e2a2e3d25bc 100644
> > --- a/arm/unittests.cfg
> > +++ b/arm/unittests.cfg
> > @@ -6,6 +6,24 @@
> >  # arch = arm/arm64 # Only if the test case works only on one of them
> >  # groups = group1 group2 # Used to identify test cases with run_tests -g ...
> >  
> > -[selftest]
> > +#
> > +# The selftest group tests the initial booting of a guest, as well as
> > +# the test framework itself.
> > +#
> > +# Test bootinfo reading; configured mem-size should equal expected mem-size
> > +[selftest_mem]
> >  file = selftest.flat
> >  extra_params = -m 256 -append 'mem 256'
> > +groups = selftest
> > +
> > +# Test vector setup and exception handling (svc mode).
> > +[selftest_vectors]
> > +file = selftest.flat
> > +extra_params = -append 'vectors'
> > +groups = selftest
> > +
> > +# Test vector setup and exception handling (usr mode).
> > +[selftest_vectors_usr]
> > +file = selftest.flat
> > +extra_params = -append 'vectors_usr'
> > +groups = selftest
> > diff --git a/config/config-arm.mak b/config/config-arm.mak
> > index a863b3e3511c9..99349bf8b0c6b 100644
> > --- a/config/config-arm.mak
> > +++ b/config/config-arm.mak
> > @@ -16,6 +16,7 @@ cflatobjs += \
> >  	lib/virtio.o \
> >  	lib/virtio-testdev.o \
> >  	lib/arm/io.o \
> > +	lib/arm/processor.o \
> >  	lib/arm/setup.o
> >  
> >  libeabi := lib/arm/libeabi.a
> > diff --git a/lib/arm/processor.c b/lib/arm/processor.c
> > new file mode 100644
> > index 0000000000000..1fededee6977f
> > --- /dev/null
> > +++ b/lib/arm/processor.c
> > @@ -0,0 +1,103 @@
> > +#include "libcflat.h"
> > +#include "arm/processor.h"
> > +#include "arm/sysinfo.h"
> > +#include "arm/ptrace.h"
> > +#include "heap.h"
> > +
> > +static const char *processor_modes[] = {
> > +	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
> > +	"UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
> > +	"UK8_26" , "UK9_26" , "UK10_26", "UK11_26",
> > +	"UK12_26", "UK13_26", "UK14_26", "UK15_26",
> > +	"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" ,
> > +	"UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
> > +	"UK8_32" , "UK9_32" , "UK10_32", "UND_32" ,
> > +	"UK12_32", "UK13_32", "UK14_32", "SYS_32"
> > +};
> > +
> > +static char *vector_names[] = {
> > +	"rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq"
> > +};
> > +
> > +void show_regs(struct pt_regs *regs)
> > +{
> > +	unsigned long flags;
> > +	char buf[64];
> > +
> > +	printf("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
> > +	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
> > +		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
> > +		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
> > +	printf("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
> > +		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
> > +	printf("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
> > +		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
> > +	printf("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
> > +		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
> > +
> > +	flags = regs->ARM_cpsr;
> > +	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
> > +	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
> > +	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
> > +	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
> > +	buf[4] = '\0';
> > +
> > +	printf("Flags: %s  IRQs o%s  FIQs o%s  Mode %s\n",
> > +		buf, interrupts_enabled(regs) ? "n" : "ff",
> > +		fast_interrupts_enabled(regs) ? "n" : "ff",
> > +		processor_modes[processor_mode(regs)]);
> > +
> > +	if (!user_mode(regs)) {
> > +		unsigned int ctrl, transbase, dac;
> > +		asm volatile(
> > +			"mrc p15, 0, %0, c1, c0\n"
> > +			"mrc p15, 0, %1, c2, c0\n"
> > +			"mrc p15, 0, %2, c3, c0\n"
> > +		: "=r" (ctrl), "=r" (transbase), "=r" (dac));
> > +		printf("Control: %08x  Table: %08x  DAC: %08x\n",
> > +			ctrl, transbase, dac);
> > +	}
> > +}
> > +
> > +void *get_sp(void)
> > +{
> > +	register unsigned long sp asm("sp");
> > +	return (void *)sp;
> > +}
> > +
> > +static exception_fn exception_handlers[EXCPTN_MAX];
> > +
> > +void install_exception_handler(enum vector v, exception_fn fn)
> > +{
> > +	if (v < EXCPTN_MAX)
> > +		exception_handlers[v] = fn;
> > +}
> > +
> > +void do_handle_exception(enum vector v, struct pt_regs *regs)
> > +{
> > +	if (v < EXCPTN_MAX && exception_handlers[v]) {
> > +		exception_handlers[v](regs);
> > +		return;
> > +	}
> > +
> > +	if (v < EXCPTN_MAX)
> > +		printf("Unhandled exception %d (%s)\n", v, vector_names[v]);
> > +	else
> > +		printf("%s called with vector=%d\n", __func__, v);
> > +	printf("Exception frame registers:\n");
> > +	show_regs(regs);
> > +	exit(EINTR);
> > +}
> > +
> > +void start_usr(void (*func)(void))
> > +{
> > +	void *sp_usr = alloc_page() + PAGE_SIZE;
> > +	asm volatile(
> > +		"mrs	r0, cpsr\n"
> > +		"bic	r0, #" __stringify(MODE_MASK) "\n"
> > +		"orr	r0, #" __stringify(USR_MODE) "\n"
> > +		"msr	cpsr_c, r0\n"
> > +		"mov	sp, %0\n"
> > +		"mov	pc, %1\n"
> > +	:: "r" (sp_usr), "r" (func) : "r0");
> > +}
> > diff --git a/lib/arm/processor.h b/lib/arm/processor.h
> > new file mode 100644
> > index 0000000000000..12c1902de97fd
> > --- /dev/null
> > +++ b/lib/arm/processor.h
> > @@ -0,0 +1,35 @@
> > +#ifndef _ARM_PROCESSOR_H_
> > +#define _ARM_PROCESSOR_H_
> > +#include "libcflat.h"
> > +#include "ptrace.h"
> > +
> > +enum vector {
> > +	EXCPTN_RST,
> > +	EXCPTN_UND,
> > +	EXCPTN_SVC,
> > +	EXCPTN_PABT,
> > +	EXCPTN_DABT,
> > +	EXCPTN_ADDREXCPTN,
> > +	EXCPTN_IRQ,
> > +	EXCPTN_FIQ,
> > +	EXCPTN_MAX,
> > +};
> > +
> > +typedef void (*exception_fn)(struct pt_regs *);
> > +extern void install_exception_handler(enum vector v, exception_fn fn);
> > +
> > +extern void show_regs(struct pt_regs *regs);
> > +extern void *get_sp(void);
> > +
> > +extern void start_usr(void (*func)(void));
> > +
> > +static inline unsigned long current_cpsr(void)
> > +{
> > +	unsigned long cpsr;
> > +	asm volatile("mrs %0, cpsr" : "=r" (cpsr));
> > +	return cpsr;
> > +}
> > +
> > +#define current_mode() (current_cpsr() & MODE_MASK)
> > +
> > +#endif
> > diff --git a/lib/libcflat.h b/lib/libcflat.h
> > index 84b8783bacfdc..3d47a3331b7fc 100644
> > --- a/lib/libcflat.h
> > +++ b/lib/libcflat.h
> > @@ -65,6 +65,8 @@ extern long atol(const char *ptr);
> >  		(type *)( (char *)__mptr - offsetof(type,member) );})
> >  
> >  #define __unused __attribute__((__unused__))
> > +#define __stringify_1(x...)	#x
> > +#define __stringify(x...)	__stringify_1(x)
> >  #define NULL ((void *)0UL)
> >  #include "errno.h"
> >  #endif
> > -- 
> > 1.8.1.4
> > 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux