bitkeeper revision 1.906 (40a5e91cnvIS_3gLwfnD2G3HV3odHA)

manual merge
This commit is contained in:
iap10@labyrinth.cl.cam.ac.uk committed 2004-05-15 09:55:40 +00:00
commit 5080a3f4b2
14 files changed
+769 -333

No files matched your search

+1
View File
@@ -144,6 +144,7 @@
3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/i386/pci-i386.h
3ddb79bdHe6_Uij4-glW91vInNtBYQ xen/arch/i386/pci-irq.c
3ddb79bcZ_2FxINljqNSkqa17ISyJw xen/arch/i386/pci-pc.c
40a4dfced2dnSzbKgJFlD3chKHexjQ xen/arch/i386/pdb-linux.c
4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/i386/pdb-stub.c
3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/i386/process.c
3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/i386/rwlock.c
+1 -8
View File
@@ -537,14 +537,7 @@ error_code:
movl %edx,%es
movl %edx,%fs
movl %edx,%gs
# We force a STI here. In most cases it is illegal to fault with
# interrupts disabled, so no need to check EFLAGS. There is one
# case when it /is/ valid -- on final return to guest context, we
# CLI so we can atomically check for events to notify guest about and
# return, all in one go. If we fault it is necessary to STI and the
# worst that will happen is that our return code is no longer atomic.
# This will do -- noone will ever notice. :-)
sti
movl %esp,%edx
pushl %esi # push the error code
pushl %edx # push the pt_regs pointer
GET_CURRENT(%ebx)
+100
View File
@@ -0,0 +1,100 @@
/*
* pervasive debugger
* www.cl.cam.ac.uk/netos/pdb
*
* alex ho
* 2004
* university of cambridge computer laboratory
*
* linux & i386 dependent code. bleech.
*/
#include <asm/pdb.h>
/* offset to the first instruction in the linux system call code
where we can safely set a breakpoint */
unsigned int pdb_linux_syscall_enter_bkpt_offset = 20;
/* offset to eflags saved on the stack after an int 80 */
unsigned int pdb_linux_syscall_eflags_offset = 48;
/* offset to the instruction pointer saved on the stack after an int 80 */
unsigned int pdb_linux_syscall_eip_offset = 40;
unsigned char
pdb_linux_set_bkpt (unsigned long addr)
{
unsigned char old_instruction = *(unsigned char *)addr;
*(unsigned char *)addr = 0xcc;
return old_instruction;
}
void
pdb_linux_clr_bkpt (unsigned long addr, unsigned char value)
{
*(unsigned char *)addr = value;
}
void
pdb_linux_syscall_enter_bkpt (struct pt_regs *regs, long error_code,
trap_info_t *ti)
{
/* set at breakpoint at the beginning of the
system call in the target domain */
pdb_system_call_enter_instr = pdb_linux_set_bkpt(ti->address +
pdb_linux_syscall_enter_bkpt_offset);
pdb_system_call = 1;
}
void
pdb_linux_syscall_exit_bkpt (struct pt_regs *regs, struct pdb_context *pdb_ctx)
{
/*
we've hit an int 0x80 in a user's program, jumped into xen
(traps.c::do_general_protection()) which re-wrote the next
instruction in the os kernel to 0xcc, and then hit that
exception.
we need to re-write the return instruction in the user's
program so that we know when we have finished the system call
and are back in the user's program.
at this point our stack should look something like this:
esp = 0x80a59f0
esp + 4 = 0x0
esp + 8 = 0x80485a0
esp + 12 = 0x2d
esp + 16 = 0x80485f4
esp + 20 = 0xbffffa48
esp + 24 = 0xd
esp + 28 = 0xc00a0833
esp + 32 = 0x833
esp + 36 = 0xd
esp + 40 = 0x804dcdd saved eip
esp + 44 = 0x82b saved cs
esp + 48 = 0x213392 saved eflags
esp + 52 = 0xbffffa2c saved esp
esp + 56 = 0x833 saved ss
esp + 60 = 0x1000000
*/
/* restore the entry instruction for the system call */
pdb_linux_clr_bkpt(regs->eip - 1, pdb_system_call_enter_instr);
/* save the address of eflags that was saved on the stack */
pdb_system_call_eflags_addr = (regs->esp +
pdb_linux_syscall_eflags_offset);
/* muck with the return instruction so that we trap back into the
debugger when re-entering user space */
pdb_system_call_next_addr = *(unsigned long *)(regs->esp +
pdb_linux_syscall_eip_offset);
pdb_linux_get_values (&pdb_system_call_leave_instr, 1,
pdb_system_call_next_addr,
pdb_ctx->process, pdb_ctx->ptbr);
pdb_linux_set_values ("cc", 1, pdb_system_call_next_addr,
pdb_ctx->process, pdb_ctx->ptbr);
}
+111 -63
View File
@@ -47,26 +47,13 @@ static int pdb_in_buffer_ptr;
static unsigned char pdb_in_checksum;
static unsigned char pdb_xmit_checksum;
/* function pointers in the near future... */
unsigned long pdb_linux_pid_ptbr (unsigned long cr3, int pid);
void pdb_linux_get_values(char *buffer, int length, unsigned long address,
int pid, unsigned long cr3);
void pdb_linux_set_values(char *buffer, int length, unsigned long address,
int pid, unsigned long cr3);
struct pdb_context
{
int valid;
int domain;
int process;
unsigned long ptbr; /* cached page table base register */
};
struct pdb_context pdb_ctx;
int pdb_continue_thread = 0;
int pdb_general_thread = 0;
void pdb_put_packet (unsigned char *buffer, int ack);
void pdb_bkpt_check (u_char *buffer, int length,
unsigned long cr3, unsigned long addr);
int pdb_initialized = 0;
int pdb_page_fault_possible = 0;
@@ -75,6 +62,12 @@ int pdb_page_fault = 0;
static int pdb_serhnd = -1;
static int pdb_stepping = 0;
int pdb_system_call = 0;
unsigned char pdb_system_call_enter_instr = 0; /* original enter instr */
unsigned char pdb_system_call_leave_instr = 0; /* original next instr */
unsigned long pdb_system_call_next_addr = 0; /* instr after int 0x80 */
unsigned long pdb_system_call_eflags_addr = 0; /* saved eflags on stack */
static inline void pdb_put_char(unsigned char c)
{
serial_putc(pdb_serhnd, c);
@@ -406,15 +399,49 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
break;
case 'S': /* step with signal */
case 's': /* step */
{
if ( pdb_system_call_eflags_addr != 0 )
{
unsigned long eflags;
char eflags_buf[sizeof(eflags)*2]; /* STUPID STUPID STUPID */
pdb_linux_get_values((u_char*)&eflags, sizeof(eflags),
pdb_system_call_eflags_addr,
pdb_ctx.process, pdb_ctx.ptbr);
eflags |= X86_EFLAGS_TF;
mem2hex ((u_char *)&eflags, eflags_buf, sizeof(eflags));
pdb_linux_set_values(eflags_buf, sizeof(eflags),
pdb_system_call_eflags_addr,
pdb_ctx.process, pdb_ctx.ptbr);
}
regs->eflags |= X86_EFLAGS_TF;
pdb_stepping = 1;
return 1;
/* not reached */
}
case 'C': /* continue with signal */
case 'c': /* continue */
{
if ( pdb_system_call_eflags_addr != 0 )
{
unsigned long eflags;
char eflags_buf[sizeof(eflags)*2]; /* STUPID STUPID STUPID */
pdb_linux_get_values((u_char*)&eflags, sizeof(eflags),
pdb_system_call_eflags_addr,
pdb_ctx.process, pdb_ctx.ptbr);
eflags &= ~X86_EFLAGS_TF;
mem2hex ((u_char *)&eflags, eflags_buf, sizeof(eflags));
pdb_linux_set_values(eflags_buf, sizeof(eflags),
pdb_system_call_eflags_addr,
pdb_ctx.process, pdb_ctx.ptbr);
}
regs->eflags &= ~X86_EFLAGS_TF;
return 1; /* jump out before replying to gdb */
/* not reached */
}
case 'd':
remote_debug = !(remote_debug); /* toggle debug flag */
break;
@@ -424,54 +451,11 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
case 'g': /* return the value of the CPU registers */
{
pdb_x86_to_gdb_regs (pdb_out_buffer, regs);
/*
printk (" reg: %s", pdb_out_buffer);
printk ("\n");
printk (" eax: 0x%08lx\n", regs->eax);
printk (" ecx: 0x%08lx\n", regs->ecx);
printk (" edx: 0x%08lx\n", regs->edx);
printk (" ebx: 0x%08lx\n", regs->ebx);
printk (" esp: 0x%08lx\n", regs->esp);
printk (" ebp: 0x%08lx\n", regs->ebp);
printk (" esi: 0x%08lx\n", regs->esi);
printk (" edi: 0x%08lx\n", regs->edi);
printk (" eip: 0x%08lx\n", regs->eip);
printk (" efl: 0x%08lx\n", regs->eflags);
printk (" xcs: 0x%08x\n", regs->xcs);
printk (" xss: 0x%08x\n", regs->xss);
printk (" xds: 0x%08x\n", regs->xds);
printk (" xes: 0x%08x\n", regs->xes);
printk (" xfs: 0x%08x\n", regs->xfs);
printk (" xgs: 0x%08x\n", regs->xgs);
*/
break;
}
case 'G': /* set the value of the CPU registers - return OK */
{
pdb_gdb_to_x86_regs (regs, ptr);
/*
printk (" ptr: %s \n\n", ptr);
printk (" eax: 0x%08lx\n", regs->eax);
printk (" ecx: 0x%08lx\n", regs->ecx);
printk (" edx: 0x%08lx\n", regs->edx);
printk (" ebx: 0x%08lx\n", regs->ebx);
printk (" esp: 0x%08lx\n", regs->esp);
printk (" ebp: 0x%08lx\n", regs->ebp);
printk (" esi: 0x%08lx\n", regs->esi);
printk (" edi: 0x%08lx\n", regs->edi);
printk (" eip: 0x%08lx\n", regs->eip);
printk (" efl: 0x%08lx\n", regs->eflags);
printk (" xcs: 0x%08x\n", regs->xcs);
printk (" xss: 0x%08x\n", regs->xss);
printk (" xds: 0x%08x\n", regs->xds);
printk (" xes: 0x%08x\n", regs->xes);
printk (" xfs: 0x%08x\n", regs->xfs);
printk (" xgs: 0x%08x\n", regs->xgs);
*/
break;
}
case 'H':
@@ -572,17 +556,20 @@ pdb_process_command (char *ptr, struct pt_regs *regs, unsigned long cr3,
if (addr >= PAGE_OFFSET)
{
hex2mem (ptr, (char *)addr, length);
pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
}
else if (pdb_ctx.process != -1)
{
pdb_linux_set_values(ptr, length, addr,
pdb_ctx.process,
pdb_ctx.ptbr);
pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
}
else
{
pdb_set_values (ptr, length,
pdb_ctx.ptbr, addr);
pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
}
pdb_page_fault_possible = 0;
if (pdb_page_fault)
@@ -936,7 +923,6 @@ int pdb_set_values(u_char *buffer, int length,
unsigned long cr3, unsigned long addr)
{
int count = pdb_change_values(buffer, length, cr3, addr, __PDB_SET_VAL);
pdb_bkpt_check(buffer, length, cr3, addr);
return count;
}
@@ -1176,16 +1162,35 @@ int pdb_handle_exception(int exceptionVector,
__asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
/* If the exception is an int3 from user space then pdb is only
interested if it re-wrote an instruction set the breakpoint.
This occurs when leaving a system call from a domain.
*/
if ( exceptionVector == 3 &&
(xen_regs->xcs & 3) == 3 &&
xen_regs->eip != pdb_system_call_next_addr + 1)
{
TRC(printf("pdb: user bkpt (0x%x) at 0x%x:0x%lx:0x%lx\n",
exceptionVector, xen_regs->xcs & 3, cr3, xen_regs->eip));
return 1;
}
/*
* If PDB didn't set the breakpoint, is not single stepping, and the user
* didn't press the magic debug key, then we don't handle the exception.
* If PDB didn't set the breakpoint, is not single stepping,
* is not entering a system call in a domain,
* the user didn't press the magic debug key,
* then we don't handle the exception.
*/
bkpt = pdb_bkpt_search(cr3, xen_regs->eip - 1);
if ( (bkpt == NULL) &&
!pdb_stepping && (exceptionVector != KEYPRESS_EXCEPTION) &&
!pdb_stepping &&
!pdb_system_call &&
xen_regs->eip != pdb_system_call_next_addr + 1 &&
(exceptionVector != KEYPRESS_EXCEPTION) &&
xen_regs->eip < 0xc0000000) /* xenolinux for now! */
{
TRC(printf("pdb: user bkpt at 0x%lx:0x%lx\n", cr3, xen_regs->eip));
TRC(printf("pdb: user bkpt (0x%x) at 0x%lx:0x%lx\n",
exceptionVector, cr3, xen_regs->eip));
return 1;
}
@@ -1199,12 +1204,54 @@ int pdb_handle_exception(int exceptionVector,
pdb_stepping = 0;
}
if ( pdb_system_call )
{
pdb_system_call = 0;
pdb_linux_syscall_exit_bkpt (xen_regs, &pdb_ctx);
/* we don't have a saved breakpoint so we need to rewind eip */
xen_regs->eip--;
/* if ther user doesn't care about breaking when entering a
system call then we'll just ignore the exception */
if ( (pdb_ctx.system_call & 0x01) == 0 )
{
return 0;
}
}
if ( exceptionVector == BREAKPT_EXCEPTION && bkpt != NULL)
{
/* Executed Int3: replace breakpoint byte with real program byte. */
xen_regs->eip--;
}
/* returning to user space after a system call */
if ( xen_regs->eip == pdb_system_call_next_addr + 1)
{
u_char instr[2]; /* REALLY REALLY REALLY STUPID */
mem2hex (&pdb_system_call_leave_instr, instr, sizeof(instr));
pdb_linux_set_values (instr, 1, pdb_system_call_next_addr,
pdb_ctx.process, pdb_ctx.ptbr);
pdb_system_call_next_addr = 0;
pdb_system_call_leave_instr = 0;
/* manually rewind eip */
xen_regs->eip--;
/* if the user doesn't care about breaking when returning
to user space after a system call then we'll just ignore
the exception */
if ( (pdb_ctx.system_call & 0x02) == 0 )
{
return 0;
}
}
/* Generate a signal for GDB. */
switch ( exceptionVector )
{
@@ -1267,6 +1314,7 @@ void initialize_pdb()
pdb_ctx.valid = 1;
pdb_ctx.domain = -1;
pdb_ctx.process = -1;
pdb_ctx.system_call = 0;
pdb_ctx.ptbr = 0;
printk("pdb: pervasive debugger (%s) www.cl.cam.ac.uk/netos/pdb\n",
+41 -21
View File
@@ -20,15 +20,6 @@
#ifdef CONFIG_SMP
/*
* This lock must be acquired before sending a synchronous IPI to another
* CPU (i.e., IPI + spin waiting for acknowledgement). The only safe ways of
* acquiring the lock are spin_lock() and spin_trylock(). The former is only
* safe if local interrupts are enabled (otherwise we will never see an IPI
* destined for us which we must acknowledge for the lock to be released).
*/
static spinlock_t synchronous_ipi_lock = SPIN_LOCK_UNLOCKED;
/*
* Some notes on x86 processor bugs affecting SMP operation:
*
@@ -220,16 +211,18 @@ static inline void send_IPI_allbutself(int vector)
* 2) Leave the mm if we are in the lazy tlb mode.
*/
static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED;
static volatile unsigned long flush_cpumask;
#define FLUSH_ALL 0xffffffff
asmlinkage void smp_invalidate_interrupt(void)
{
ack_APIC_irq();
local_flush_tlb();
clear_bit(smp_processor_id(), &flush_cpumask);
perfc_incrc(ipis);
if ( likely(test_and_clear_bit(smp_processor_id(), &flush_cpumask)) )
local_flush_tlb();
}
#ifndef NO_DEVICES_IN_XEN
int try_flush_tlb_mask(unsigned long mask)
{
if ( mask & (1 << smp_processor_id()) )
@@ -240,7 +233,7 @@ int try_flush_tlb_mask(unsigned long mask)
if ( mask != 0 )
{
if ( unlikely(!spin_trylock(&synchronous_ipi_lock)) )
if ( unlikely(!spin_trylock(&flush_lock)) )
return 0;
flush_cpumask = mask;
send_IPI_mask(mask, INVALIDATE_TLB_VECTOR);
@@ -249,15 +242,16 @@ int try_flush_tlb_mask(unsigned long mask)
rep_nop();
barrier();
}
spin_unlock(&synchronous_ipi_lock);
spin_unlock(&flush_lock);
}
return 1;
}
#endif
void flush_tlb_mask(unsigned long mask)
{
ASSERT(local_irq_is_enabled());
ASSERT(!in_irq());
if ( mask & (1 << smp_processor_id()) )
{
@@ -267,7 +261,21 @@ void flush_tlb_mask(unsigned long mask)
if ( mask != 0 )
{
spin_lock(&synchronous_ipi_lock);
/*
* We are certainly not reentering a flush_lock region on this CPU
* because we are not in an IRQ context. We can therefore wait for the
* other guy to release the lock. This is harder than it sounds because
* local interrupts might be disabled, and he may be waiting for us to
* execute smp_invalidate_interrupt(). We deal with this possibility by
* inlining the meat of that function here.
*/
while ( unlikely(!spin_trylock(&flush_lock)) )
{
if ( test_and_clear_bit(smp_processor_id(), &flush_cpumask) )
local_flush_tlb();
rep_nop();
}
flush_cpumask = mask;
send_IPI_mask(mask, INVALIDATE_TLB_VECTOR);
while ( flush_cpumask != 0 )
@@ -275,13 +283,15 @@ void flush_tlb_mask(unsigned long mask)
rep_nop();
barrier();
}
spin_unlock(&synchronous_ipi_lock);
spin_unlock(&flush_lock);
}
}
void new_tlbflush_clock_period(void)
{
if ( unlikely(!spin_trylock(&synchronous_ipi_lock)) )
/* Avoid deadlock because we might be reentering a flush_lock region. */
if ( unlikely(!spin_trylock(&flush_lock)) )
return;
/* Someone may acquire the lock and execute the flush before us. */
@@ -304,7 +314,7 @@ void new_tlbflush_clock_period(void)
tlbflush_clock++;
out:
spin_unlock(&synchronous_ipi_lock);
spin_unlock(&flush_lock);
}
static void flush_tlb_all_pge_ipi(void* info)
@@ -323,6 +333,12 @@ void smp_send_event_check_mask(unsigned long cpu_mask)
send_IPI_mask(cpu_mask, EVENT_CHECK_VECTOR);
}
/*
* Structure and data for smp_call_function(). This is designed to minimise
* static memory requirements. It also looks cleaner.
*/
static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
struct call_data_struct {
void (*func) (void *info);
void *info;
@@ -368,7 +384,8 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
ASSERT(local_irq_is_enabled());
spin_lock(&synchronous_ipi_lock);
spin_lock(&call_lock);
call_data = &data;
wmb();
/* Send a message to all other CPUs and wait for them to respond */
@@ -382,7 +399,7 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
while (atomic_read(&data.finished) != cpus)
barrier();
spin_unlock(&synchronous_ipi_lock);
spin_unlock(&call_lock);
return 0;
}
@@ -419,6 +436,7 @@ void smp_send_stop(void)
asmlinkage void smp_event_check_interrupt(void)
{
ack_APIC_irq();
perfc_incrc(ipis);
}
asmlinkage void smp_call_function_interrupt(void)
@@ -428,6 +446,8 @@ asmlinkage void smp_call_function_interrupt(void)
int wait = call_data->wait;
ack_APIC_irq();
perfc_incrc(ipis);
/*
* Notify initiating CPU that I've grabbed the data and am
* about to execute the function
+26 -31
View File
@@ -107,36 +107,9 @@ static inline int kernel_text_address(unsigned long addr)
}
void show_trace(unsigned long * stack)
{
int i;
unsigned long addr;
printk("Call Trace: ");
i = 1;
while (((long) stack & (STACK_SIZE-1)) != 0) {
addr = *stack++;
if (kernel_text_address(addr)) {
if (i && ((i % 6) == 0))
printk("\n ");
printk("[<%08lx>] ", addr);
i++;
}
}
printk("\n");
}
void show_traceX(void)
{
unsigned long *addr;
__asm__ __volatile__ ("movl %%esp,%0" : "=r" (addr) : );
show_trace(addr);
}
void show_stack(unsigned long *esp)
{
unsigned long *stack;
unsigned long *stack, addr;
int i;
printk("Stack trace from ESP=%p:\n", esp);
@@ -154,6 +127,20 @@ void show_stack(unsigned long *esp)
printk("%08lx ", *stack++);
}
printk("\n");
printk("Call Trace from ESP=%p: ", esp);
stack = esp;
i = 0;
while (((long) stack & (STACK_SIZE-1)) != 0) {
addr = *stack++;
if (kernel_text_address(addr)) {
if (i && ((i % 6) == 0))
printk("\n ");
printk("[<%08lx>] ", addr);
i++;
}
}
printk("\n");
}
void show_registers(struct pt_regs *regs)
@@ -250,7 +237,6 @@ DO_ERROR_NOCODE( 0, "divide error", divide_error)
DO_ERROR_NOCODE( 4, "overflow", overflow)
DO_ERROR_NOCODE( 5, "bounds", bounds)
DO_ERROR_NOCODE( 6, "invalid operand", invalid_op)
DO_ERROR_NOCODE( 7, "device not available", device_not_available)
DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, "invalid TSS", invalid_TSS)
DO_ERROR(11, "segment not present", segment_not_present)
@@ -267,10 +253,10 @@ asmlinkage void do_int3(struct pt_regs *regs, long error_code)
struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
trap_info_t *ti;
if ( pdb_handle_exception(3, regs) == 0 )
return;
if ( (regs->xcs & 3) != 3 )
{
if ( pdb_handle_exception(3, regs) == 0 )
return;
if ( unlikely((regs->xcs & 3) == 0) )
{
show_registers(regs);
@@ -445,6 +431,15 @@ asmlinkage void do_general_protection(struct pt_regs *regs, long error_code)
ti = current->thread.traps + (error_code>>3);
if ( TI_GET_DPL(ti) >= (regs->xcs & 3) )
{
unsigned long cr3;
__asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
if (pdb_initialized && pdb_ctx.system_call != 0 &&
cr3 == pdb_ctx.ptbr)
{
pdb_linux_syscall_enter_bkpt(regs, error_code, ti);
}
gtb->flags = GTBF_TRAP_NOCODE;
regs->eip += 2;
goto finish_propagation;
+9 -20
View File
@@ -28,15 +28,6 @@
extern unsigned int alloc_new_dom_mem(struct task_struct *, unsigned int);
/* Basically used to protect the domain-id space. */
static spinlock_t create_dom_lock = SPIN_LOCK_UNLOCKED;
static domid_t get_domnr(void)
{
static domid_t domnr = 0;
return ++domnr;
}
static int msr_cpu_mask;
static unsigned long msr_addr;
static unsigned long msr_lo;
@@ -117,23 +108,24 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
case DOM0_CREATEDOMAIN:
{
struct task_struct *p;
static unsigned int pro = 0;
static domid_t domnr = 0;
static spinlock_t domnr_lock = SPIN_LOCK_UNLOCKED;
unsigned int pro;
domid_t dom;
ret = -ENOMEM;
spin_lock_irq(&create_dom_lock);
if ( (dom = get_domnr()) == 0 )
goto exit_create;
spin_lock(&domnr_lock);
dom = ++domnr;
spin_unlock(&domnr_lock);
if (op->u.createdomain.cpu == -1 )
pro = (pro+1) % smp_num_cpus;
pro = (unsigned int)dom % smp_num_cpus;
else
pro = op->u.createdomain.cpu % smp_num_cpus;
p = do_createdomain(dom, pro);
if ( p == NULL )
goto exit_create;
break;
if ( op->u.createdomain.name[0] )
{
@@ -145,16 +137,13 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( ret != 0 )
{
__kill_domain(p);
goto exit_create;
break;
}
ret = 0;
op->u.createdomain.domain = p->domain;
copy_to_user(u_dom0_op, op, sizeof(*op));
exit_create:
spin_unlock_irq(&create_dom_lock);
}
break;
+12 -4
View File
@@ -292,6 +292,12 @@ struct pfn_info *alloc_domain_page(struct task_struct *p)
unsigned long flags, mask, pfn_stamp, cpu_stamp;
int i;
#ifdef NO_DEVICES_IN_XEN
ASSERT(!in_irq());
#else
ASSERT((p != NULL) || !in_irq());
#endif
spin_lock_irqsave(&free_list_lock, flags);
if ( likely(!list_empty(&free_list)) )
{
@@ -307,7 +313,7 @@ struct pfn_info *alloc_domain_page(struct task_struct *p)
if ( (mask = page->u.cpu_mask) != 0 )
{
pfn_stamp = page->tlbflush_timestamp;
for ( i = 0; (mask != 0) && (i < NR_CPUS); i++ )
for ( i = 0; (mask != 0) && (i < smp_num_cpus); i++ )
{
if ( mask & (1<<i) )
{
@@ -319,11 +325,15 @@ struct pfn_info *alloc_domain_page(struct task_struct *p)
if ( unlikely(mask != 0) )
{
#ifdef NO_DEVICES_IN_XEN
flush_tlb_mask(mask);
#else
/* In IRQ ctxt, flushing is best-effort only, to avoid deadlock. */
if ( likely(!in_irq()) )
flush_tlb_mask(mask);
else if ( unlikely(!try_flush_tlb_mask(mask)) )
goto free_and_exit;
#endif
perfc_incrc(need_flush_tlb_flush);
}
}
@@ -332,7 +342,6 @@ struct pfn_info *alloc_domain_page(struct task_struct *p)
page->type_and_flags = 0;
if ( p != NULL )
{
ASSERT(!in_irq());
wmb(); /* Domain pointer must be visible before updating refcnt. */
spin_lock(&p->page_list_lock);
if ( unlikely(p->tot_pages >= p->max_pages) )
@@ -363,8 +372,7 @@ void free_domain_page(struct pfn_info *page)
unsigned long flags;
struct task_struct *p = page->u.domain;
if ( unlikely(in_irq()) )
BUG();
ASSERT(!in_irq());
if ( likely(!IS_XEN_HEAP_FRAME(page)) )
{
+27 -19
View File
@@ -804,6 +804,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
unsigned long pfn = ptr >> PAGE_SHIFT;
unsigned long old_base_pfn;
struct pfn_info *page = &frame_table[pfn];
struct task_struct *p = current, *q;
switch ( cmd )
{
@@ -852,18 +853,18 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
break;
case MMUEXT_NEW_BASEPTR:
okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, current);
okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, p);
if ( likely(okay) )
{
invalidate_shadow_ldt();
percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB;
old_base_pfn = pagetable_val(current->mm.pagetable) >> PAGE_SHIFT;
current->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
old_base_pfn = pagetable_val(p->mm.pagetable) >> PAGE_SHIFT;
p->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
shadow_mk_pagetable(&current->mm);
shadow_mk_pagetable(&p->mm);
write_ptbase(&current->mm);
write_ptbase(&p->mm);
put_page_and_type(&frame_table[old_base_pfn]);
@@ -899,13 +900,13 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
okay = 0;
MEM_LOG("Bad args to SET_LDT: ptr=%08lx, ents=%08lx", ptr, ents);
}
else if ( (current->mm.ldt_ents != ents) ||
(current->mm.ldt_base != ptr) )
else if ( (p->mm.ldt_ents != ents) ||
(p->mm.ldt_base != ptr) )
{
invalidate_shadow_ldt();
current->mm.ldt_base = ptr;
current->mm.ldt_ents = ents;
load_LDT(current);
p->mm.ldt_base = ptr;
p->mm.ldt_ents = ents;
load_LDT(p);
percpu_info[cpu].deferred_ops &= ~DOP_RELOAD_LDT;
if ( ents != 0 )
percpu_info[cpu].deferred_ops |= DOP_RELOAD_LDT;
@@ -921,10 +922,10 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
percpu_info[cpu].subject_id |=
((domid_t)((ptr&~0xFFFF)|(val>>16)))<<32;
if ( !IS_PRIV(current) )
if ( !IS_PRIV(p) )
{
MEM_LOG("Dom %llu has no privilege to set subject domain",
current->domain);
p->domain);
okay = 0;
}
else
@@ -943,19 +944,26 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
}
break;
/* XXX This function is racey! */
case MMUEXT_REASSIGN_PAGE:
if ( unlikely(!IS_PRIV(current)) )
if ( unlikely(!IS_PRIV(p)) )
{
MEM_LOG("Dom %llu has no privilege to reassign page ownership",
current->domain);
p->domain);
okay = 0;
}
else if ( likely(percpu_info[cpu].gps != NULL) )
else if ( likely((q = percpu_info[cpu].gps) != NULL) &&
likely(test_bit(_PGC_allocated, &page->count_and_flags)) &&
likely(page->u.domain == p) ) /* won't be smp-guest safe */
{
current->tot_pages--;
percpu_info[cpu].gps->tot_pages++;
page->u.domain = percpu_info[cpu].gps;
spin_lock(&p->page_list_lock);
p->tot_pages--;
list_del(&page->list);
spin_unlock(&p->page_list_lock);
page->u.domain = q;
spin_lock(&q->page_list_lock);
q->tot_pages++;
list_add_tail(&page->list, &q->page_list);
spin_unlock(&q->page_list_lock);
}
else
{
+29
View File
@@ -14,6 +14,7 @@
#include <asm/ptrace.h>
#include <xen/list.h>
#include <hypervisor-ifs/dom0_ops.h>
#include <hypervisor-ifs/hypervisor-if.h> /* for domain id */
extern int pdb_initialized;
@@ -37,6 +38,17 @@ extern int pdb_handle_exception(int exceptionVector,
extern int pdb_serial_input(u_char c, struct pt_regs *regs);
extern void pdb_do_debug(dom0_op_t *op);
/* PDB Context. */
struct pdb_context
{
int valid;
int domain;
int process;
int system_call; /* 0x01 break on enter, 0x02 break on exit */
unsigned long ptbr;
};
extern struct pdb_context pdb_ctx;
/* Breakpoints. */
struct pdb_breakpoint
{
@@ -56,4 +68,21 @@ extern char *mem2hex (char *, char *, int);
extern char *hex2mem (char *, char *, int);
extern int hexToInt (char **ptr, int *intValue);
/* Temporary Linux specific definitions */
extern int pdb_system_call;
extern unsigned char pdb_system_call_enter_instr; /* original enter instr */
extern unsigned char pdb_system_call_leave_instr; /* original next instr */
extern unsigned long pdb_system_call_next_addr; /* instr after int 0x80 */
extern unsigned long pdb_system_call_eflags_addr; /* saved eflags on stack */
unsigned long pdb_linux_pid_ptbr (unsigned long cr3, int pid);
void pdb_linux_get_values(char *buffer, int length, unsigned long address,
int pid, unsigned long cr3);
void pdb_linux_set_values(char *buffer, int length, unsigned long address,
int pid, unsigned long cr3);
void pdb_linux_syscall_enter_bkpt (struct pt_regs *regs, long error_code,
trap_info_t *ti);
void pdb_linux_syscall_exit_bkpt (struct pt_regs *regs,
struct pdb_context *pdb_ctx);
#endif /* __PDB_H__ */
+4 -2
View File
@@ -12,6 +12,7 @@
#include <asm/cpufeature.h>
#include <asm/desc.h>
#include <asm/flushtlb.h>
#include <asm/pdb.h>
#include <xen/config.h>
#include <xen/spinlock.h>
#include <hypervisor-ifs/hypervisor-if.h>
@@ -406,8 +407,9 @@ extern struct desc_struct *idt_tables[];
0, 8))
#define SET_FAST_TRAP(_p) \
(memcpy(idt_tables[smp_processor_id()] + (_p)->fast_trap_idx, \
&((_p)->fast_trap_desc), 8))
(pdb_initialized ? (void *) 0 : \
(memcpy(idt_tables[smp_processor_id()] + (_p)->fast_trap_idx, \
&((_p)->fast_trap_desc), 8)))
long set_fast_trap(struct task_struct *p, int idx);
+1
View File
@@ -1,5 +1,6 @@
PERFCOUNTER_CPU( irqs, "#interrupts" )
PERFCOUNTER_CPU( ipis, "#IPIs" )
PERFCOUNTER_CPU( irq_time, "cycles spent in irq handler" )
PERFCOUNTER_CPU( apic_timer, "apic timer interrupts" )
@@ -13,19 +13,33 @@
#include "common.h"
#include <asm/hypervisor-ifs/dom_mem_ops.h>
static void net_tx_action(unsigned long unused);
static void netif_page_release(struct page *page);
static void make_tx_response(netif_t *netif,
u16 id,
s8 st);
static void make_rx_response(netif_t *netif,
static int make_rx_response(netif_t *netif,
u16 id,
s8 st,
netif_addr_t addr,
u16 size);
static void net_tx_action(unsigned long unused);
static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
static void net_rx_action(unsigned long unused);
static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
typedef struct {
u16 id;
unsigned long old_mach_ptr;
unsigned long new_mach_pfn;
netif_t *netif;
} rx_info_t;
static struct sk_buff_head rx_queue;
static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE*2];
static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE*4];
static unsigned char rx_notify[NR_EVENT_CHANNELS];
/* Don't currently gate addition of an interface to the tx scheduling list. */
#define tx_work_exists(_if) (1)
@@ -38,12 +52,24 @@ static unsigned long mmap_vstart;
static u16 pending_id[MAX_PENDING_REQS];
static netif_t *pending_netif[MAX_PENDING_REQS];
static u16 pending_ring[MAX_PENDING_REQS];
static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED;
typedef unsigned int PEND_RING_IDX;
#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
static PEND_RING_IDX pending_prod, pending_cons;
#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
/* Freed TX SKBs get batched on this ring before return to pending_ring. */
static u16 dealloc_ring[MAX_PENDING_REQS];
static spinlock_t dealloc_lock = SPIN_LOCK_UNLOCKED;
static PEND_RING_IDX dealloc_prod, dealloc_cons;
typedef struct {
u16 idx;
netif_tx_request_t req;
netif_t *netif;
} tx_info_t;
static struct sk_buff_head tx_queue;
static multicall_entry_t tx_mcl[MAX_PENDING_REQS];
static struct list_head net_schedule_list;
static spinlock_t net_schedule_list_lock;
@@ -98,22 +124,12 @@ static inline void maybe_schedule_tx_action(void)
int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
netif_t *netif = (netif_t *)dev->priv;
s8 status = NETIF_RSP_OKAY;
u16 size=0, id;
mmu_update_t mmu[4];
multicall_entry_t mcl[2];
unsigned long vdata, mdata=0, new_mfn;
/* Drop the packet if the target domain has no receive buffers. */
if ( (netif->rx_req_cons == netif->rx->req_prod) ||
((netif->rx_req_cons-netif->rx_resp_prod) == NETIF_RX_RING_SIZE) )
{
dev_kfree_skb(skb);
return 0;
}
goto drop;
id = netif->rx->ring[MASK_NETIF_RX_IDX(netif->rx_req_cons++)].req.id;
/*
* We do not copy the packet unless:
* 1. The data is shared; or
@@ -130,11 +146,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff *nskb = alloc_skb(PAGE_SIZE-1024, GFP_ATOMIC);
int hlen = skb->data - skb->head;
if ( unlikely(nskb == NULL) )
{
DPRINTK("DOM%llu couldn't get memory for skb.\n", netif->domid);
status = NETIF_RSP_ERROR;
goto out;
}
goto drop;
skb_reserve(nskb, hlen);
__skb_put(nskb, skb->len);
(void)skb_copy_bits(skb, -hlen, nskb->head, hlen + skb->len);
@@ -142,65 +154,166 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = nskb;
}
vdata = (unsigned long)skb->data;
mdata = virt_to_machine(vdata);
size = skb->tail - skb->data;
((rx_info_t *)&skb->cb[0])->id =
netif->rx->ring[MASK_NETIF_RX_IDX(netif->rx_req_cons++)].req.id;
((rx_info_t *)&skb->cb[0])->netif = netif;
__skb_queue_tail(&rx_queue, skb);
tasklet_schedule(&net_rx_tasklet);
new_mfn = get_new_mfn();
return 0;
mmu[0].ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
mmu[0].val = __pa(vdata) >> PAGE_SHIFT;
mmu[1].val = (unsigned long)(netif->domid<<16) & ~0xFFFFUL;
mmu[1].ptr = (unsigned long)(netif->domid<< 0) & ~0xFFFFUL;
mmu[2].val = (unsigned long)(netif->domid>>16) & ~0xFFFFUL;
mmu[2].ptr = (unsigned long)(netif->domid>>32) & ~0xFFFFUL;
mmu[1].ptr |= MMU_EXTENDED_COMMAND;
mmu[1].val |= MMUEXT_SET_SUBJECTDOM_L;
mmu[2].ptr |= MMU_EXTENDED_COMMAND;
mmu[2].val |= MMUEXT_SET_SUBJECTDOM_H;
mmu[3].ptr = (mdata & PAGE_MASK) | MMU_EXTENDED_COMMAND;
mmu[3].val = MMUEXT_REASSIGN_PAGE;
mcl[0].op = __HYPERVISOR_mmu_update;
mcl[0].args[0] = (unsigned long)mmu;
mcl[0].args[1] = 4;
mcl[1].op = __HYPERVISOR_update_va_mapping;
mcl[1].args[0] = vdata >> PAGE_SHIFT;
mcl[1].args[1] = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL;
mcl[1].args[2] = UVMF_INVLPG;
(void)HYPERVISOR_multicall(mcl, 2);
if ( mcl[0].args[5] != 0 )
{
DPRINTK("Failed MMU update transferring to DOM%llu\n", netif->domid);
(void)HYPERVISOR_update_va_mapping(
vdata >> PAGE_SHIFT,
(pte_t) { (mdata & PAGE_MASK) | __PAGE_KERNEL },
UVMF_INVLPG);
dealloc_mfn(new_mfn);
status = NETIF_RSP_ERROR;
goto out;
}
phys_to_machine_mapping[__pa(vdata) >> PAGE_SHIFT] = new_mfn;
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
netif->stats.rx_bytes += size;
netif->stats.rx_packets++;
out:
spin_lock(&netif->rx_lock);
make_rx_response(netif, id, status, mdata, size);
spin_unlock(&netif->rx_lock);
drop:
netif->stats.rx_dropped++;
dev_kfree_skb(skb);
return 0;
}
#if 0
static void xen_network_done_notify(void)
{
static struct net_device *eth0_dev = NULL;
if ( unlikely(eth0_dev == NULL) )
eth0_dev = __dev_get_by_name("eth0");
netif_rx_schedule(eth0_dev);
}
/*
* Add following to poll() function in NAPI driver (Tigon3 is example):
* if ( xen_network_done() )
* tge_3nable_ints(tp);
*/
int xen_network_done(void)
{
return skb_queue_empty(&rx_queue);
}
#endif
static void net_rx_action(unsigned long unused)
{
netif_t *netif;
s8 status;
u16 size, id, evtchn;
mmu_update_t *mmu = rx_mmu;
multicall_entry_t *mcl;
unsigned long vdata, mdata, new_mfn;
struct sk_buff_head rxq;
struct sk_buff *skb;
u16 notify_list[NETIF_RX_RING_SIZE];
int notify_nr = 0;
skb_queue_head_init(&rxq);
mcl = rx_mcl;
while ( (skb = __skb_dequeue(&rx_queue)) != NULL )
{
netif = ((rx_info_t *)&skb->cb[0])->netif;
vdata = (unsigned long)skb->data;
mdata = virt_to_machine(vdata);
new_mfn = get_new_mfn();
mmu[0].ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
mmu[0].val = __pa(vdata) >> PAGE_SHIFT;
mmu[1].val = (unsigned long)(netif->domid<<16) & ~0xFFFFUL;
mmu[1].ptr = (unsigned long)(netif->domid<< 0) & ~0xFFFFUL;
mmu[2].val = (unsigned long)(netif->domid>>16) & ~0xFFFFUL;
mmu[2].ptr = (unsigned long)(netif->domid>>32) & ~0xFFFFUL;
mmu[1].ptr |= MMU_EXTENDED_COMMAND;
mmu[1].val |= MMUEXT_SET_SUBJECTDOM_L;
mmu[2].ptr |= MMU_EXTENDED_COMMAND;
mmu[2].val |= MMUEXT_SET_SUBJECTDOM_H;
mmu[3].ptr = (mdata & PAGE_MASK) | MMU_EXTENDED_COMMAND;
mmu[3].val = MMUEXT_REASSIGN_PAGE;
mcl[0].op = __HYPERVISOR_update_va_mapping;
mcl[0].args[0] = vdata >> PAGE_SHIFT;
mcl[0].args[1] = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL;
mcl[0].args[2] = 0;
mcl[1].op = __HYPERVISOR_mmu_update;
mcl[1].args[0] = (unsigned long)mmu;
mcl[1].args[1] = 4;
mmu += 4;
mcl += 2;
((rx_info_t *)&skb->cb[0])->old_mach_ptr = mdata;
((rx_info_t *)&skb->cb[0])->new_mach_pfn = new_mfn;
__skb_queue_tail(&rxq, skb);
/* Filled the batch queue? */
if ( (mcl - rx_mcl) == ARRAY_SIZE(rx_mcl) )
break;
}
if ( mcl == rx_mcl )
return;
mcl[-2].args[2] = UVMF_FLUSH_TLB;
(void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
mcl = rx_mcl;
while ( (skb = __skb_dequeue(&rxq)) != NULL )
{
netif = ((rx_info_t *)&skb->cb[0])->netif;
size = skb->tail - skb->data;
id = ((rx_info_t *)&skb->cb[0])->id;
new_mfn = ((rx_info_t *)&skb->cb[0])->new_mach_pfn;
mdata = ((rx_info_t *)&skb->cb[0])->old_mach_ptr;
/* Check the reassignment error code. */
if ( unlikely(mcl[1].args[5] != 0) )
{
DPRINTK("Failed MMU update transferring to DOM%llu\n",
netif->domid);
(void)HYPERVISOR_update_va_mapping(
(unsigned long)skb->head >> PAGE_SHIFT,
(pte_t) { (mdata & PAGE_MASK) | __PAGE_KERNEL },
UVMF_INVLPG);
dealloc_mfn(new_mfn);
status = NETIF_RSP_ERROR;
}
else
{
phys_to_machine_mapping[__pa(skb->data) >> PAGE_SHIFT] = new_mfn;
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
netif->stats.rx_bytes += size;
netif->stats.rx_packets++;
status = NETIF_RSP_OKAY;
}
evtchn = netif->evtchn;
if ( make_rx_response(netif, id, status, mdata, size) &&
(rx_notify[evtchn] == 0) )
{
rx_notify[evtchn] = 1;
notify_list[notify_nr++] = evtchn;
}
dev_kfree_skb(skb);
mcl += 2;
}
while ( notify_nr != 0 )
{
evtchn = notify_list[--notify_nr];
rx_notify[evtchn] = 0;
notify_via_evtchn(evtchn);
}
/* More work to do? */
if ( !skb_queue_empty(&rx_queue) )
tasklet_schedule(&net_rx_tasklet);
#if 0
else
xen_network_done_notify();
#endif
}
struct net_device_stats *netif_be_get_stats(struct net_device *dev)
{
netif_t *netif = dev->priv;
@@ -215,10 +328,12 @@ static int __on_net_schedule_list(netif_t *netif)
static void remove_from_net_schedule_list(netif_t *netif)
{
spin_lock(&net_schedule_list_lock);
ASSERT(__on_net_schedule_list(netif));
list_del(&netif->list);
netif->list.next = NULL;
netif_put(netif);
if ( likely(__on_net_schedule_list(netif)) )
{
list_del(&netif->list);
netif->list.next = NULL;
netif_put(netif);
}
spin_unlock(&net_schedule_list_lock);
}
@@ -269,7 +384,51 @@ static void net_tx_action(unsigned long unused)
u16 pending_idx;
NETIF_RING_IDX i;
struct page *page;
multicall_entry_t *mcl;
if ( (i = dealloc_cons) == dealloc_prod )
goto skip_dealloc;
mcl = tx_mcl;
while ( i != dealloc_prod )
{
pending_idx = dealloc_ring[MASK_PEND_IDX(i++)];
mcl[0].op = __HYPERVISOR_update_va_mapping;
mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT;
mcl[0].args[1] = 0;
mcl[0].args[2] = 0;
mcl++;
}
mcl[-1].args[2] = UVMF_FLUSH_TLB;
(void)HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl);
while ( dealloc_cons != dealloc_prod )
{
pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)];
netif = pending_netif[pending_idx];
spin_lock(&netif->tx_lock);
make_tx_response(netif, pending_id[pending_idx], NETIF_RSP_OKAY);
spin_unlock(&netif->tx_lock);
pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
/*
* Scheduling checks must happen after the above response is posted.
* This avoids a possible race with a guest OS on another CPU.
*/
mb();
if ( (netif->tx_req_cons != netif->tx->req_prod) &&
((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE) )
add_to_net_schedule_list_tail(netif);
netif_put(netif);
}
skip_dealloc:
mcl = tx_mcl;
while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
!list_empty(&net_schedule_list) )
{
@@ -340,29 +499,61 @@ static void net_tx_action(unsigned long unused)
pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
if ( HYPERVISOR_update_va_mapping_otherdomain(
MMAP_VADDR(pending_idx) >> PAGE_SHIFT,
(pte_t) { (txreq.addr & PAGE_MASK) | __PAGE_KERNEL },
0, netif->domid) != 0 )
{
DPRINTK("Bad page frame\n");
make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
netif_put(netif);
continue;
}
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] =
txreq.addr >> PAGE_SHIFT;
if ( unlikely((skb = alloc_skb(PKT_PROT_LEN, GFP_ATOMIC)) == NULL) )
{
DPRINTK("Can't allocate a skb in start_xmit.\n");
make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
netif_put(netif);
HYPERVISOR_update_va_mapping(MMAP_VADDR(pending_idx) >> PAGE_SHIFT,
(pte_t) { 0 }, UVMF_INVLPG);
break;
}
mcl[0].op = __HYPERVISOR_update_va_mapping_otherdomain;
mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT;
mcl[0].args[1] = (txreq.addr & PAGE_MASK) | __PAGE_KERNEL;
mcl[0].args[2] = 0;
mcl[0].args[3] = (unsigned long)netif->domid;
mcl[0].args[4] = (unsigned long)(netif->domid>>32);
mcl++;
((tx_info_t *)&skb->cb[0])->idx = pending_idx;
((tx_info_t *)&skb->cb[0])->netif = netif;
memcpy(&((tx_info_t *)&skb->cb[0])->req, &txreq, sizeof(txreq));
__skb_queue_tail(&tx_queue, skb);
pending_cons++;
/* Filled the batch queue? */
if ( (mcl - tx_mcl) == ARRAY_SIZE(tx_mcl) )
break;
}
if ( mcl == tx_mcl )
return;
(void)HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl);
mcl = tx_mcl;
while ( (skb = __skb_dequeue(&tx_queue)) != NULL )
{
pending_idx = ((tx_info_t *)&skb->cb[0])->idx;
netif = ((tx_info_t *)&skb->cb[0])->netif;
memcpy(&txreq, &((tx_info_t *)&skb->cb[0])->req, sizeof(txreq));
/* Check the remap error code. */
if ( unlikely(mcl[0].args[5] != 0) )
{
DPRINTK("Bad page frame\n");
make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
netif_put(netif);
kfree_skb(skb);
mcl++;
pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
continue;
}
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] =
txreq.addr >> PAGE_SHIFT;
__skb_put(skb, PKT_PROT_LEN);
memcpy(skb->data,
(void *)(MMAP_VADDR(pending_idx)|(txreq.addr&~PAGE_MASK)),
@@ -391,42 +582,23 @@ static void net_tx_action(unsigned long unused)
netif->stats.tx_bytes += txreq.size;
netif->stats.tx_packets++;
pending_cons++;
netif_rx(skb);
netif->dev->last_rx = jiffies;
mcl++;
}
}
static void netif_page_release(struct page *page)
{
unsigned long flags;
netif_t *netif;
u16 pending_idx;
u16 pending_idx = page - virt_to_page(mmap_vstart);
pending_idx = page - virt_to_page(mmap_vstart);
spin_lock_irqsave(&dealloc_lock, flags);
dealloc_ring[MASK_PEND_IDX(dealloc_prod++)] = pending_idx;
spin_unlock_irqrestore(&dealloc_lock, flags);
netif = pending_netif[pending_idx];
HYPERVISOR_update_va_mapping(MMAP_VADDR(pending_idx) >> PAGE_SHIFT,
(pte_t) { 0 }, UVMF_INVLPG);
spin_lock(&netif->tx_lock);
make_tx_response(netif, pending_id[pending_idx], NETIF_RSP_OKAY);
spin_unlock(&netif->tx_lock);
/*
* Scheduling checks must happen after the above response is posted.
* This avoids a possible race with a guest OS on another CPU.
*/
mb();
netif_schedule_work(netif);
netif_put(netif);
spin_lock_irqsave(&pend_prod_lock, flags);
pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
spin_unlock_irqrestore(&pend_prod_lock, flags);
tasklet_schedule(&net_tx_tasklet);
}
#if 0
@@ -497,11 +669,11 @@ static void make_tx_response(netif_t *netif,
notify_via_evtchn(netif->evtchn);
}
static void make_rx_response(netif_t *netif,
u16 id,
s8 st,
netif_addr_t addr,
u16 size)
static int make_rx_response(netif_t *netif,
u16 id,
s8 st,
netif_addr_t addr,
u16 size)
{
NET_RING_IDX i = netif->rx_resp_prod;
netif_rx_response_t *resp;
@@ -516,8 +688,7 @@ static void make_rx_response(netif_t *netif,
netif->rx->resp_prod = netif->rx_resp_prod = ++i;
mb(); /* Update producer before checking event threshold. */
if ( i == netif->rx->event )
notify_via_evtchn(netif->evtchn);
return (i == netif->rx->event);
}
static int __init init_module(void)
@@ -527,6 +698,9 @@ static int __init init_module(void)
if ( !(start_info.flags & SIF_INITDOMAIN) )
return 0;
skb_queue_head_init(&rx_queue);
skb_queue_head_init(&tx_queue);
netif_interface_init();
if ( (mmap_vstart = allocate_empty_lowmem_region(MAX_PENDING_REQS)) == 0 )
@@ -37,6 +37,10 @@ static void network_tx_buf_gc(struct net_device *dev);
static void network_alloc_rx_buffers(struct net_device *dev);
static void cleanup_module(void);
static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE];
static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1];
static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE];
static struct list_head dev_list;
struct net_private
@@ -178,8 +182,7 @@ static void network_alloc_rx_buffers(struct net_device *dev)
struct sk_buff *skb;
NETIF_RING_IDX i = np->rx->req_prod;
dom_mem_op_t op;
unsigned long pfn_array[NETIF_RX_RING_SIZE];
int ret, nr_pfns = 0;
int nr_pfns = 0;
/* Make sure the batch is large enough to be worthwhile (1/2 ring). */
if ( unlikely((i - np->rx_resp_cons) > (NETIF_RX_RING_SIZE/2)) ||
@@ -201,9 +204,14 @@ static void network_alloc_rx_buffers(struct net_device *dev)
np->rx->ring[MASK_NET_RX_IDX(i)].req.id = id;
pfn_array[nr_pfns++] = virt_to_machine(skb->head) >> PAGE_SHIFT;
HYPERVISOR_update_va_mapping((unsigned long)skb->head >> PAGE_SHIFT,
(pte_t) { 0 }, UVMF_INVLPG);
rx_pfn_array[nr_pfns] = virt_to_machine(skb->head) >> PAGE_SHIFT;
rx_mcl[nr_pfns].op = __HYPERVISOR_update_va_mapping;
rx_mcl[nr_pfns].args[0] = (unsigned long)skb->head >> PAGE_SHIFT;
rx_mcl[nr_pfns].args[1] = 0;
rx_mcl[nr_pfns].args[2] = 0;
nr_pfns++;
}
while ( (++i - np->rx_resp_cons) != NETIF_RX_RING_SIZE );
@@ -213,14 +221,22 @@ static void network_alloc_rx_buffers(struct net_device *dev)
*/
flush_page_update_queue();
/* After all PTEs have been zapped we blow away stale TLB entries. */
rx_mcl[nr_pfns-1].args[2] = UVMF_FLUSH_TLB;
/* Give away a batch of pages. */
op.op = MEMOP_RESERVATION_DECREASE;
op.u.decrease.size = nr_pfns;
op.u.decrease.pages = pfn_array;
if ( (ret = HYPERVISOR_dom_mem_op(&op)) != nr_pfns )
{
printk(KERN_WARNING "Unable to reduce memory reservation (%d)\n", ret);
BUG();
}
op.u.decrease.pages = rx_pfn_array;
rx_mcl[nr_pfns].op = __HYPERVISOR_dom_mem_op;
rx_mcl[nr_pfns].args[0] = (unsigned long)&op;
/* Zap PTEs and give away pages in one big multicall. */
(void)HYPERVISOR_multicall(rx_mcl, nr_pfns+1);
/* Check return status of HYPERVISOR_dom_mem_op(). */
if ( rx_mcl[nr_pfns].args[5] != nr_pfns )
panic("Unable to reduce memory reservation\n");
np->rx->req_prod = i;
}
@@ -295,17 +311,36 @@ static void netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
struct net_device *dev = dev_id;
struct net_private *np = dev->priv;
unsigned long flags;
struct sk_buff *skb;
netif_rx_response_t *rx;
NETIF_RING_IDX i;
mmu_update_t mmu;
spin_lock_irqsave(&np->tx_lock, flags);
network_tx_buf_gc(dev);
spin_unlock_irqrestore(&np->tx_lock, flags);
again:
for ( i = np->rx_resp_cons; i != np->rx->resp_prod; i++ )
if ( np->rx_resp_cons != np->rx->resp_prod )
netif_rx_schedule(dev);
}
static int netif_poll(struct net_device *dev, int *pbudget)
{
struct net_private *np = dev->priv;
struct sk_buff *skb;
netif_rx_response_t *rx;
NETIF_RING_IDX i;
mmu_update_t *mmu = rx_mmu;
multicall_entry_t *mcl = rx_mcl;
int work_done, budget, more_to_do = 1;
struct sk_buff_head rxq;
unsigned long flags;
skb_queue_head_init(&rxq);
if ( (budget = *pbudget) > dev->quota )
budget = dev->quota;
for ( i = np->rx_resp_cons, work_done = 0;
(i != np->rx->resp_prod) && (work_done < budget);
i++, work_done++ )
{
rx = &np->rx->ring[MASK_NET_RX_IDX(i)].resp;
@@ -317,38 +352,53 @@ static void netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
/* Gate this error. We get a (valid) slew of them on suspend. */
if ( np->state == NETIF_STATE_ACTIVE )
printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
dev_kfree_skb_any(skb);
dev_kfree_skb(skb);
continue;
}
skb->data = skb->tail = skb->head + (rx->addr & ~PAGE_MASK);
skb_put(skb, rx->status);
np->stats.rx_packets++;
np->stats.rx_bytes += rx->status;
/* Remap the page. */
mmu.ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE;
mmu.val = __pa(skb->head) >> PAGE_SHIFT;
if ( HYPERVISOR_mmu_update(&mmu, 1) != 0 )
BUG();
HYPERVISOR_update_va_mapping((unsigned long)skb->head >> PAGE_SHIFT,
(pte_t) { (rx->addr & PAGE_MASK) |
__PAGE_KERNEL },
0);
mmu->ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE;
mmu->val = __pa(skb->head) >> PAGE_SHIFT;
mmu++;
mcl->op = __HYPERVISOR_update_va_mapping;
mcl->args[0] = (unsigned long)skb->head >> PAGE_SHIFT;
mcl->args[1] = (rx->addr & PAGE_MASK) | __PAGE_KERNEL;
mcl->args[2] = 0;
mcl++;
phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] =
rx->addr >> PAGE_SHIFT;
/*
* Set up shinfo -- from alloc_skb This was particularily nasty: the
* shared info is hidden at the back of the data area (presumably so it
* can be shared), but on page flip it gets very spunked.
*/
__skb_queue_tail(&rxq, skb);
}
/* Do all the remapping work, and M->P updates, in one big hypercall. */
if ( likely((mcl - rx_mcl) != 0) )
{
mcl->op = __HYPERVISOR_mmu_update;
mcl->args[0] = (unsigned long)rx_mmu;
mcl->args[1] = mmu - rx_mmu;
mcl++;
(void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
}
while ( (skb = __skb_dequeue(&rxq)) != NULL )
{
/* Set the shared-info area, which is hidden behind the real data. */
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
skb->data = skb->tail = skb->head + (rx->addr & ~PAGE_MASK);
skb_put(skb, rx->status);
/* Ethernet-specific work. Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
np->stats.rx_packets++;
np->stats.rx_bytes += rx->status;
/* Pass it up. */
netif_rx(skb);
dev->last_rx = jiffies;
}
@@ -356,12 +406,28 @@ static void netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
np->rx_resp_cons = i;
network_alloc_rx_buffers(dev);
np->rx->event = np->rx_resp_cons + 1;
*pbudget -= work_done;
dev->quota -= work_done;
if ( work_done < budget )
{
local_irq_save(flags);
np->rx->event = i + 1;
/* Deal with hypervisor racing our resetting of rx_event. */
mb();
if ( np->rx->resp_prod != i )
goto again;
/* Deal with hypervisor racing our resetting of rx_event. */
mb();
if ( np->rx->resp_prod == i )
{
__netif_rx_complete(dev);
more_to_do = 0;
}
local_irq_restore(flags);
}
return more_to_do;
}
@@ -524,6 +590,8 @@ static int __init init_module(void)
dev->hard_start_xmit = network_start_xmit;
dev->stop = network_close;
dev->get_stats = network_get_stats;
dev->poll = netif_poll;
dev->weight = 64;
if ( (err = register_netdev(dev)) != 0 )
{
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.