diff -urN linux-2.4.18/arch/i386/config.in linux-2.4.18-rtai-rthal5g/arch/i386/config.in --- linux-2.4.18/arch/i386/config.in 2002-02-25 14:37:52.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/config.in 2003-11-26 16:00:30.000000000 -0500 @@ -201,6 +201,8 @@ if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then define_bool CONFIG_HAVE_DEC_LOCK y fi +comment 'CONFIG_RTHAL must be yes' +bool 'Real-Time Hardware Abstraction Layer' CONFIG_RTHAL endmenu mainmenu_option next_comment @@ -412,6 +414,14 @@ fi mainmenu_option next_comment +comment 'Kernel tracing' +tristate 'Kernel events tracing support' CONFIG_TRACE +if [ "$CONFIG_TRACE" = "m" ]; then + bool 'RTAI event tracing support' CONFIG_RTAI_TRACE +fi +endmenu + +mainmenu_option next_comment comment 'Kernel hacking' bool 'Kernel debugging' CONFIG_DEBUG_KERNEL diff -urN linux-2.4.18/arch/i386/defconfig linux-2.4.18-rtai-rthal5g/arch/i386/defconfig --- linux-2.4.18/arch/i386/defconfig 2002-02-25 14:37:52.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/defconfig 2003-11-26 16:01:08.000000000 -0500 @@ -62,6 +62,7 @@ CONFIG_SMP=y # CONFIG_MULTIQUAD is not set CONFIG_HAVE_DEC_LOCK=y +CONFIG_RTHAL=y # # General setup @@ -825,6 +826,9 @@ # # CONFIG_USB_RIO500 is not set +# Kernel tracing +CONFIG_TRACE=n + # # Kernel hacking # diff -urN linux-2.4.18/arch/i386/kernel/entry.S linux-2.4.18-rtai-rthal5g/arch/i386/kernel/entry.S --- linux-2.4.18/arch/i386/kernel/entry.S 2002-02-25 14:37:53.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/entry.S 2003-11-26 16:02:45.000000000 -0500 @@ -176,6 +176,7 @@ ENTRY(ret_from_fork) + sti pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp @@ -199,20 +200,37 @@ jne tracesys cmpl $(NR_syscalls),%eax jae badsys + +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + movl %esp, %eax # copy the stack pointer + pushl %eax # pass the stack pointer copy + call SYMBOL_NAME(trace_real_syscall_entry) + addl $4,%esp # return stack to state before pass + movl ORIG_EAX(%esp),%eax # restore eax to it's original content +#endif + call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value + +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + call SYMBOL_NAME(trace_real_syscall_exit) +#endif + ENTRY(ret_from_sys_call) - cli # need_resched and signals atomic test + call *(SYMBOL_NAME(rthal) + 12) # cli cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_return + sti + call *(SYMBOL_NAME(rthal) + 16) # sti restore_all: RESTORE_ALL ALIGN signal_return: - sti # we can get here from an interrupt handler + sti # we can get here from an interrupt handler + call *(SYMBOL_NAME(rthal) + 16) # sti testl $(VM_MASK),EFLAGS(%esp) movl %esp,%eax jne v86_signal_return diff -urN linux-2.4.18/arch/i386/kernel/i386_ksyms.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/i386_ksyms.c --- linux-2.4.18/arch/i386/kernel/i386_ksyms.c 2002-02-25 14:37:53.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/i386_ksyms.c 2003-11-26 15:08:58.000000000 -0500 @@ -32,6 +32,14 @@ extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; +EXPORT_SYMBOL_NOVERS(rthal); +#include +EXPORT_SYMBOL(kd_mksound); +#include +EXPORT_SYMBOL(console_drivers); +extern unsigned long cpu_khz; +EXPORT_SYMBOL(cpu_khz); + #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern void machine_real_restart(unsigned char *, int); EXPORT_SYMBOL(machine_real_restart); @@ -174,3 +182,10 @@ extern int is_sony_vaio_laptop; EXPORT_SYMBOL(is_sony_vaio_laptop); + +#ifdef CONFIG_X86_REMOTE_DEBUG +#include +EXPORT_SYMBOL(linux_debug_hook); +EXPORT_SYMBOL(gdb_irq); +EXPORT_SYMBOL(gdb_interrupt); +#endif diff -urN linux-2.4.18/arch/i386/kernel/i8259.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/i8259.c --- linux-2.4.18/arch/i386/kernel/i8259.c 2001-09-18 02:03:09.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/i8259.c 2003-11-26 15:08:58.000000000 -0500 @@ -290,12 +290,12 @@ handle_real_irq: if (irq & 8) { - inb(0xA1); /* DUMMY - (do we need this?) */ +// inb(0xA1); /* DUMMY - (do we need this?) */ outb(cached_A1,0xA1); outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ } else { - inb(0x21); /* DUMMY - (do we need this?) */ +// inb(0x21); /* DUMMY - (do we need this?) */ outb(cached_21,0x21); outb(0x60+irq,0x20); /* 'Specific EOI' to master */ } @@ -508,3 +508,17 @@ if (boot_cpu_data.hard_math && !cpu_has_fpu) setup_irq(13, &irq13); } + +void ack_8259_irq(unsigned int irq) +{ + spin_lock(&i8259A_lock); + if (irq & 8) { + outb(0x62,0x20); + outb(0x20,0xA0); + } else { + outb(0x20,0x20); + } + spin_unlock(&i8259A_lock); + return; +} + diff -urN linux-2.4.18/arch/i386/kernel/io_apic.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/io_apic.c --- linux-2.4.18/arch/i386/kernel/io_apic.c 2001-11-13 20:28:41.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/io_apic.c 2003-11-26 15:08:58.000000000 -0500 @@ -35,7 +35,7 @@ #undef APIC_LOCKUP_DEBUG -#define APIC_LOCKUP_DEBUG +//#define APIC_LOCKUP_DEBUG static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; @@ -1208,11 +1208,10 @@ #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq +static unsigned long strange_level; + static void end_level_ioapic_irq (unsigned int irq) { - unsigned long v; - int i; - /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1232,12 +1231,8 @@ * operation to prevent an edge-triggered interrupt escaping meanwhile. * The idea is from Manfred Spraul. --macro */ - i = IO_APIC_VECTOR(irq); - v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); - ack_APIC_irq(); - - if (!(v & (1 << (i & 0x1f)))) { + if (test_and_clear_bit(irq, &strange_level)) { #ifdef APIC_LOCKUP_DEBUG struct irq_pin_list *entry; #endif @@ -1246,7 +1241,6 @@ atomic_inc(&irq_mis_count); #endif spin_lock(&ioapic_lock); - __mask_and_edge_IO_APIC_irq(irq); #ifdef APIC_LOCKUP_DEBUG for (entry = irq_2_pin + irq;;) { unsigned int reg; @@ -1264,10 +1258,30 @@ #endif __unmask_and_level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); + } else { + spin_lock(&ioapic_lock); + __unmask_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); } } -static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } +static void mask_and_ack_level_ioapic_irq (unsigned int irq) +{ + unsigned long i; + + i = IO_APIC_VECTOR(irq); + if (!(apic_read(APIC_TMR + ((i & ~0x1f) >> 1)) & (1 << (i & 0x1f)))) { + test_and_set_bit(irq, &strange_level); + spin_lock(&ioapic_lock); + __mask_and_edge_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); + } else { + spin_lock(&ioapic_lock); + __mask_IO_APIC_irq(irq); + spin_unlock(&ioapic_lock); + } + ack_APIC_irq(); +} static void set_ioapic_affinity (unsigned int irq, unsigned long mask) { diff -urN linux-2.4.18/arch/i386/kernel/irq.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/irq.c --- linux-2.4.18/arch/i386/kernel/irq.c 2001-10-25 16:53:46.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/irq.c 2003-11-26 16:06:16.000000000 -0500 @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -441,6 +443,8 @@ irq_enter(cpu, irq); + TRACE_IRQ_ENTRY(irq, !(user_mode(regs))); + status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) @@ -457,6 +461,8 @@ irq_exit(cpu, irq); + TRACE_IRQ_EXIT(); + return status; } @@ -1198,3 +1204,71 @@ register_irq_proc(i); } +static void linux_cli(void) +{ + hard_cli(); +} + +static void linux_sti(void) +{ + hard_sti(); +} + +static unsigned int linux_save_flags(void) +{ + int flags; + hard_save_flags(flags); + return flags; +} + +static void linux_restore_flags(unsigned int flags) +{ + hard_restore_flags(flags); +} + +static unsigned int linux_save_flags_and_cli(void) +{ + int flags; + hard_save_flags_and_cli(flags); + return flags; +} + +#include + +#ifndef CONFIG_X86_IO_APIC +int irq_vector[]; +#endif +#ifndef CONFIG_SMP +void smp_invalidate_interrupt(void) { } +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +static volatile int physical_apicid_2_cpu[1]; +#endif + +extern void *ret_from_intr; +extern struct desc_struct idt_table[]; +extern void ack_8259_irq(unsigned int); +extern int idle_weight; +extern void smp_invalidate_interrupt(void); +extern void switch_mem(struct task_struct *, struct task_struct *, int); +extern volatile int physical_apicid_2_cpu[]; + +struct rt_hal rthal = { + ret_from_intr: &ret_from_intr, + __switch_to: __switch_to, + idt_table: idt_table, + disint: linux_cli, + enint: linux_sti, + getflags: linux_save_flags, + setflags: linux_restore_flags, + getflags_and_cli: linux_save_flags_and_cli, + irq_desc: irq_desc, + irq_vector: irq_vector, + irq_affinity: irq_affinity, + smp_invalidate_interrupt: smp_invalidate_interrupt, + ack_8259_irq: ack_8259_irq, + idle_weight: &idle_weight, + lxrt_global_cli: NULL, + switch_mem: switch_mem, + init_tasks: init_tasks, + apicmap: physical_apicid_2_cpu, +}; diff -urN linux-2.4.18/arch/i386/kernel/process.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/process.c --- linux-2.4.18/arch/i386/kernel/process.c 2002-02-25 14:37:53.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/process.c 2003-11-26 16:07:43.000000000 -0500 @@ -34,6 +34,8 @@ #include #include +#include + #include #include #include @@ -508,6 +510,10 @@ "r" (arg), "r" (fn), "b" (flags | CLONE_VM) : "memory"); +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + if (retval > 0) + TRACE_PROCESS(TRACE_EV_PROCESS_KTHREAD, retval, (int) fn); +#endif return retval; } diff -urN linux-2.4.18/arch/i386/kernel/smp.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/smp.c --- linux-2.4.18/arch/i386/kernel/smp.c 2001-12-21 12:41:53.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/smp.c 2003-11-26 15:08:58.000000000 -0500 @@ -160,8 +160,7 @@ unsigned long cfg; unsigned long flags; - __save_flags(flags); - __cli(); + hard_save_flags_and_cli(flags); /* @@ -185,7 +184,7 @@ */ apic_write_around(APIC_ICR, cfg); - __restore_flags(flags); + hard_restore_flags(flags); } static inline void send_IPI_mask_sequence(int mask, int vector) diff -urN linux-2.4.18/arch/i386/kernel/sys_i386.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/sys_i386.c --- linux-2.4.18/arch/i386/kernel/sys_i386.c 2001-03-19 15:35:09.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/sys_i386.c 2003-11-26 16:09:41.000000000 -0500 @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -137,6 +139,8 @@ version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + TRACE_IPC(TRACE_EV_IPC_CALL, call, first); + switch (call) { case SEMOP: return sys_semop (first, (struct sembuf *)ptr, second); diff -urN linux-2.4.18/arch/i386/kernel/time.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/time.c --- linux-2.4.18/arch/i386/kernel/time.c 2002-02-25 14:37:53.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/time.c 2003-11-26 16:15:21.000000000 -0500 @@ -42,6 +42,8 @@ #include #include +#include + #include #include #include @@ -67,7 +69,9 @@ unsigned long cpu_khz; /* Detected as we calibrate the TSC */ /* Number of usecs that the last interrupt was delayed */ +#if !CONFIG_RTAI_TRACE static int delay_at_last_interrupt; +#endif static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ @@ -78,7 +82,11 @@ */ unsigned long fast_gettimeoffset_quotient; +#if !CONFIG_RTAI_TRACE extern rwlock_t xtime_lock; +#else +extern spinlock_t xtime_lock; +#endif extern unsigned long wall_jiffies; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -109,7 +117,11 @@ "0" (eax)); /* our adjusted time offset in microseconds */ +#if !CONFIG_RTAI_TRACE return delay_at_last_interrupt + edx; +#else + return edx; +#endif } #define TICK_SIZE tick @@ -268,7 +280,11 @@ unsigned long flags; unsigned long usec, sec; +#if !CONFIG_RTAI_TRACE read_lock_irqsave(&xtime_lock, flags); +#else + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif usec = do_gettimeoffset(); { unsigned long lost = jiffies - wall_jiffies; @@ -277,7 +293,11 @@ } sec = xtime.tv_sec; usec += xtime.tv_usec; +#if !CONFIG_RTAI_TRACE read_unlock_irqrestore(&xtime_lock, flags); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif while (usec >= 1000000) { usec -= 1000000; @@ -290,7 +310,12 @@ void do_settimeofday(struct timeval *tv) { - write_lock_irq(&xtime_lock); +#if !CONFIG_RTAI_TRACE + write_lock_irq(&xtime_lock); +#else + unsigned long flags; + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif /* * This is revolting. We need to set "xtime" correctly. However, the * value in this location is the value at the most recent update of @@ -310,7 +335,11 @@ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - write_unlock_irq(&xtime_lock); +#if !CONFIG_RTAI_TRACE + write_unlock_irq(&xtime_lock); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif } /* @@ -467,7 +496,11 @@ */ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int count; +#if !CONFIG_RTAI_TRACE + int count; +#else + unsigned long tsc_value, tsc_delta, micros_elapsed; +#endif /* * Here we are in the timer irq handler. We just have irqs locally @@ -476,8 +509,54 @@ * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ - write_lock(&xtime_lock); +#if !CONFIG_RTAI_TRACE + write_lock(&xtime_lock); +#else + unsigned long flags; + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif + +#if CONFIG_RTAI_TRACE + /* This is for RTAI only */ + if (use_tsc) + { + /* Read the TSC's value */ + rdtscl(tsc_value); + + /* Compute difference between the current TSC value and the last low val */ + tsc_delta = tsc_value - last_tsc_low; + + /* Time elapsed since last interrupt */ + { + unsigned long eax=tsc_delta, edx=0; + __asm__("mull %2" + :"=a" (eax), "=d" (micros_elapsed) + :"g" (fast_gettimeoffset_quotient), + "0" (eax), "1" (edx)); + } + /* Did 10ms pass since the last time the TSC's low value was updated */ + if(micros_elapsed >= (1000000/HZ)) + { + /* Loop until we've taken in account all 10ms lost interrupts */ + do + { + /* We've lost one tick */ + jiffies++; + + /* We've taken in account 10ms */ + micros_elapsed -= (1000000/HZ); + } while (micros_elapsed >= (1000000/HZ)); + + /* We've incremented one lost-tick too many since do_timer will increment one more */ + jiffies--; + } + + /* Update the TSC low val (this should be good t'il we reach 4 GHz K.Y.) */ + /* 2 divisions are done to keep precision as best can be */ + last_tsc_low = tsc_value - (micros_elapsed * (cpu_khz / (1000/HZ))) / HZ; + } +#else /* NOT RTAI */ if (use_tsc) { /* @@ -496,6 +575,7 @@ rdtscl(last_tsc_low); +#if 0 spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -505,11 +585,17 @@ count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; +#endif } +#endif /* CONFIG_RTAI_TRACE */ do_timer_interrupt(irq, NULL, regs); - write_unlock(&xtime_lock); +#if !CONFIG_RTAI_TRACE + write_unlock(&xtime_lock); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif } diff -urN linux-2.4.18/arch/i386/kernel/traps.c linux-2.4.18-rtai-rthal5g/arch/i386/kernel/traps.c --- linux-2.4.18/arch/i386/kernel/traps.c 2001-09-30 15:26:08.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/arch/i386/kernel/traps.c 2003-11-26 16:24:47.000000000 -0500 @@ -25,6 +25,8 @@ #include #include +#include + #ifdef CONFIG_MCA #include #include @@ -237,6 +239,82 @@ printk("\n"); } +/* Trace related code */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +asmlinkage void trace_real_syscall_entry(struct pt_regs * regs) +{ + int use_depth; + int use_bounds; + int depth = 0; + int seek_depth; + unsigned long lower_bound; + unsigned long upper_bound; + unsigned long addr; + unsigned long* stack; + trace_syscall_entry trace_syscall_event; + + /* Set the syscall ID */ + trace_syscall_event.syscall_id = (uint8_t) regs->orig_eax; + + /* Set the address in any case */ + trace_syscall_event.address = regs->eip; + + /* Are we in the kernel (This is a kernel thread)? */ + if(!(regs->xcs & 3)) + /* Don't go digining anywhere */ + goto trace_syscall_end; + + /* Get the trace configuration */ + if(trace_get_config(&use_depth, + &use_bounds, + &seek_depth, + (void*)&lower_bound, + (void*)&upper_bound) < 0) + goto trace_syscall_end; + + /* Do we have to search for an eip address range */ + if((use_depth == 1) || (use_bounds == 1)) + { + /* Start at the top of the stack (bottom address since stacks grow downward) */ + stack = (unsigned long*) regs->esp; + + /* Keep on going until we reach the end of the process' stack limit (wherever it may be) */ + while(!get_user(addr, stack)) + { + /* Does this LOOK LIKE an address in the program */ + if((addr > current->mm->start_code) + &&(addr < current->mm->end_code)) + { + /* Does this address fit the description */ + if(((use_depth == 1) && (depth == seek_depth)) + ||((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound))) + { + /* Set the address */ + trace_syscall_event.address = addr; + + /* We're done */ + goto trace_syscall_end; + } + else + /* We're one depth more */ + depth++; + } + /* Go on to the next address */ + stack++; + } + } + +trace_syscall_end: + /* Trace the event */ + trace_event(TRACE_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + trace_event(TRACE_EV_SYSCALL_EXIT, NULL); +} +#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */ + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * regs, long err) @@ -269,6 +347,8 @@ static void inline do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { + TRACE_TRAP_ENTRY(trapnr, regs->eip); + if (vm86 && regs->eflags & VM_MASK) goto vm86_trap; if (!(regs->xcs & 3)) @@ -282,6 +362,7 @@ force_sig_info(signr, info, tsk); else force_sig(signr, tsk); + TRACE_TRAP_EXIT(); return; } @@ -291,14 +372,17 @@ regs->eip = fixup; else die(str, regs, error_code); + TRACE_TRAP_EXIT(); return; } vm86_trap: { int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); if (ret) goto trap_signal; + TRACE_TRAP_EXIT(); return; } + TRACE_TRAP_EXIT(); } #define DO_ERROR(trapnr, signr, str, name) \ @@ -358,11 +442,15 @@ current->thread.error_code = error_code; current->thread.trap_no = 13; + TRACE_TRAP_ENTRY(13, regs->eip); force_sig(SIGSEGV, current); + TRACE_TRAP_EXIT(); return; gp_in_vm86: + TRACE_TRAP_ENTRY(13, regs->eip); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + TRACE_TRAP_EXIT(); return; gp_in_kernel: @@ -422,6 +510,11 @@ { unsigned char reason = inb(0x61); +#ifndef CONFIG_SMP /* On an SMP machine NMIs are used to implement a watchdog and will hang + the machine if traced. */ + TRACE_TRAP_ENTRY(2, regs->eip); +#endif + ++nmi_count(smp_processor_id()); if (!(reason & 0xc0)) { @@ -436,6 +529,9 @@ } #endif unknown_nmi_error(reason, regs); +#ifndef CONFIG_SMP + TRACE_TRAP_EXIT(); +#endif return; } if (reason & 0x80) @@ -450,6 +546,9 @@ inb(0x71); /* dummy */ outb(0x0f, 0x70); inb(0x71); /* dummy */ +#ifndef CONFIG_SMP + TRACE_TRAP_EXIT(); +#endif } /* @@ -521,7 +620,9 @@ */ info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : (void *)regs->eip; + TRACE_TRAP_ENTRY(1, regs->eip); force_sig_info(SIGTRAP, &info, tsk); + TRACE_TRAP_EXIT(); /* Disable additional traps. They'll be re-enabled when * the signal is delivered. @@ -533,7 +634,9 @@ return; debug_vm86: + TRACE_TRAP_ENTRY(1, regs->eip); handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + TRACE_TRAP_EXIT(); return; clear_TF: @@ -682,10 +785,12 @@ asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, long error_code) { + TRACE_TRAP_ENTRY(16, regs->eip); #if 0 /* No need to warn about this any longer. */ printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); #endif + TRACE_TRAP_EXIT(); } /* @@ -713,8 +818,10 @@ { printk("math-emulation not enabled and no coprocessor found.\n"); printk("killing %s.\n",current->comm); + TRACE_TRAP_ENTRY(7, 0); force_sig(SIGFPE,current); schedule(); + TRACE_TRAP_EXIT(); } #endif /* CONFIG_MATH_EMULATION */ diff -urN linux-2.4.18/arch/i386/mm/fault.c linux-2.4.18-rtai-rthal5g/arch/i386/mm/fault.c --- linux-2.4.18/arch/i386/mm/fault.c 2002-02-25 14:37:53.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/mm/fault.c 2003-11-26 16:28:06.000000000 -0500 @@ -20,6 +20,8 @@ #include #include /* For unblank_screen() */ +#include + #include #include #include @@ -160,7 +162,7 @@ /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) - local_irq_enable(); + hard_sti(); tsk = current; @@ -183,6 +185,8 @@ mm = tsk->mm; info.si_code = SEGV_MAPERR; + TRACE_TRAP_ENTRY(14, regs->eip); + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -265,6 +269,7 @@ tsk->thread.screen_bitmap |= 1 << bit; } up_read(&mm->mmap_sem); + TRACE_TRAP_EXIT(); return; /* @@ -284,6 +289,7 @@ /* info.si_code has been set above */ info.si_addr = (void *)address; force_sig_info(SIGSEGV, &info, tsk); + TRACE_TRAP_EXIT(); return; } @@ -297,6 +303,7 @@ if (nr == 6) { do_invalid_op(regs, 0); + TRACE_TRAP_EXIT(); return; } } @@ -305,6 +312,7 @@ /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { regs->eip = fixup; + TRACE_TRAP_EXIT(); return; } @@ -371,6 +379,7 @@ /* Kernel mode? Handle exceptions or die */ if (!(error_code & 4)) goto no_context; + TRACE_TRAP_EXIT(); return; vmalloc_fault: @@ -404,6 +413,8 @@ pte_k = pte_offset(pmd_k, address); if (!pte_present(*pte_k)) goto no_context; + TRACE_TRAP_EXIT(); return; } + TRACE_TRAP_EXIT(); } diff -urN linux-2.4.18/arch/i386/mm/ioremap.c linux-2.4.18-rtai-rthal5g/arch/i386/mm/ioremap.c --- linux-2.4.18/arch/i386/mm/ioremap.c 2001-03-20 11:13:33.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/i386/mm/ioremap.c 2003-11-26 15:08:58.000000000 -0500 @@ -81,6 +81,7 @@ if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) break; + set_pgdir(address, *dir); error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; diff -urN linux-2.4.18/arch/ppc/config.in linux-2.4.18-rtai-rthal5g/arch/ppc/config.in --- linux-2.4.18/arch/ppc/config.in 2002-02-25 14:37:55.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/ppc/config.in 2003-11-26 15:08:58.000000000 -0500 @@ -109,6 +109,9 @@ bool ' Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS fi +#bool 'Real-Time Hardware Abstraction Layer' CONFIG_RTHAL +define_bool CONFIG_RTHAL y + if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then bool 'AltiVec Support' CONFIG_ALTIVEC bool 'Thermal Management Support' CONFIG_TAU diff -urN linux-2.4.18/arch/ppc/kernel/entry.S linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/entry.S --- linux-2.4.18/arch/ppc/kernel/entry.S 2002-02-25 14:37:55.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/entry.S 2003-11-26 15:08:58.000000000 -0500 @@ -294,6 +294,7 @@ bl do_signal .globl do_signal_ret do_signal_ret: + bl do_soft_sti .globl ret_to_user_hook ret_to_user_hook: nop diff -urN linux-2.4.18/arch/ppc/kernel/irq.c linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/irq.c --- linux-2.4.18/arch/ppc/kernel/irq.c 2002-02-25 14:37:55.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/irq.c 2003-11-26 15:08:58.000000000 -0500 @@ -534,6 +534,17 @@ spin_unlock(&desc->lock); } +void do_soft_cli(void) +{ +} + +void (*rtai_soft_sti)(void); + +void do_soft_sti(void) +{ + if(rtai_soft_sti)rtai_soft_sti(); +} + int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); diff -urN linux-2.4.18/arch/ppc/kernel/ppc_ksyms.c linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.18/arch/ppc/kernel/ppc_ksyms.c 2002-02-25 14:37:55.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/ppc_ksyms.c 2003-11-26 15:08:58.000000000 -0500 @@ -217,6 +217,12 @@ EXPORT_SYMBOL(synchronize_irq); #endif +extern int (*rtai_srq_bckdr)(struct pt_regs *); +EXPORT_SYMBOL(rtai_srq_bckdr); + +extern void (*rtai_soft_sti)(void); +EXPORT_SYMBOL(rtai_soft_sti); + EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB diff -urN linux-2.4.18/arch/ppc/kernel/traps.c linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/traps.c --- linux-2.4.18/arch/ppc/kernel/traps.c 2001-11-02 20:43:54.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/arch/ppc/kernel/traps.c 2003-11-26 15:08:58.000000000 -0500 @@ -269,9 +269,14 @@ return(retval); } +int (*rtai_srq_bckdr)(struct pt_regs *regs) = NULL; + void ProgramCheckException(struct pt_regs *regs) { + if (rtai_srq_bckdr && !rtai_srq_bckdr(regs)) { + return; + } #if defined(CONFIG_4xx) unsigned int esr = mfspr(SPRN_ESR); diff -urN linux-2.4.18/Documentation/Configure.help linux-2.4.18-rtai-rthal5g/Documentation/Configure.help --- linux-2.4.18/Documentation/Configure.help 2002-02-25 14:37:51.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/Documentation/Configure.help 2003-11-26 16:08:34.000000000 -0500 @@ -241,6 +241,13 @@ You will need a new lynxer.elf file to flash your firmware with - send email to Martin.Bligh@us.ibm.com +Real-Time Harware Abstraction +CONFIG_RTHAL + The Real-Time Hardware Abstraction Layer (RTHAL) is used by + the Real-Time Application Interface (RTAI) to provide a + hard real-time environment as part of Linux. This feature + cannot be turned off, so say Y. + IO-APIC support on uniprocessors CONFIG_X86_UP_IOAPIC An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an @@ -24382,6 +24389,43 @@ information: http://www.candelatech.com/~greear/vlan.html If unsure, you can safely say 'N'. +Kernel events tracing support +CONFIG_TRACE + It is possible for the kernel to log important events to a tracing + driver. Doing so, enables the use of the generated traces in order + to reconstruct the dynamic behavior of the kernel, and hence the + whole system. + + The tracing process contains 4 parts : + 1) The logging of events by key parts of the kernel. + 2) The trace driver that keeps the events in a data buffer. + 3) A trace daemon that opens the trace driver and is notified + every time there is a certain quantity of data to read + from the trace driver (using SIG_IO). + 4) A trace event data decoder that reads the accumulated data + and formats it in a human-readable format. + + If you say Y or M here, the first part of the tracing process will + always take place. That is, critical parts of the kernel will call + upon the kernel tracing function. The data generated doesn't go + any further until a trace driver registers himself as such with the + kernel. Therefore, if you answer Y, then the driver will be part of + the kernel and the events will always proceed onto the driver and + if you say M, then the events will only proceed onto the driver when + it's module is loaded. Note that event's aren't logged in the driver + until the profiling daemon opens the device, configures it and + issues the "start" command through ioctl(). + + The impact of a fully functionnal system (kernel event logging + + driver event copying + active trace daemon) is of 2.5% for core events. + This means that for a task that took 100 seconds on a normal system, it + will take 102.5 seconds on a traced system. This is very low compared + to other profiling or tracing methods. + + For more information on kernel tracing, the trace daemon or the event + decoder, please check the following address : + http://www.opersys.com/LTT + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -urN linux-2.4.18/drivers/Makefile linux-2.4.18-rtai-rthal5g/drivers/Makefile --- linux-2.4.18/drivers/Makefile 2002-02-25 14:37:56.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/drivers/Makefile 2003-11-26 16:30:23.000000000 -0500 @@ -39,6 +39,7 @@ subdir-$(CONFIG_ISDN) += isdn subdir-$(CONFIG_ATM) += atm subdir-$(CONFIG_FC4) += fc4 +subdir-$(CONFIG_TRACE) += trace # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch subdir-$(CONFIG_HAMRADIO) += net/hamradio diff -urN linux-2.4.18/drivers/trace/Makefile linux-2.4.18-rtai-rthal5g/drivers/trace/Makefile --- linux-2.4.18/drivers/trace/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/drivers/trace/Makefile 2002-03-17 01:33:56.000000000 -0500 @@ -0,0 +1,17 @@ +# +# Makefile for the kernel tracing drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +O_TARGET := trace_driver.o + +# Is it loaded as a module or as part of the kernel +obj-$(CONFIG_TRACE) = tracer.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.18/drivers/trace/tracer.c linux-2.4.18-rtai-rthal5g/drivers/trace/tracer.c --- linux-2.4.18/drivers/trace/tracer.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/drivers/trace/tracer.c 2002-03-17 01:33:56.000000000 -0500 @@ -0,0 +1,1456 @@ +/***************************************************************** + * File : tracer.c + * Description : + * Contains the code for the kernel tracing driver (tracer + * for short). + * Author : + * Karim Yaghmour + * Date : + * 03/12/01, Added user event support. + * 05/01/01, Modified PPC bit manipulation functions for + * x86 compatibility. (andy_lowe@mvista.com) + * 15/11/00, Finally fixed memory allocation and remapping + * method. Now using BTTV-driver-inspired code. + * 13/03/00, Modified tracer so that the daemon mmaps the + * tracer's buffers in it's address space rather + * than use "read". + * 26/01/00, Added support for standardized buffer sizes and + * extensibility of events. + * 01/10/99, Modified tracer in order to used double-buffering. + * 28/09/99, Adding tracer configuration support. + * 09/09/99, Chaging the format of an event record in order to + * reduce the size of the traces. + * 04/03/99, Initial typing. + * Note : + * The sizes of the variables used to store the details of an + * event are planned for a system who gets at least one clock + * tick every 10milli-seconds. There has to be at least one + * event every 2^32-1 microseconds, otherwise the size of the + * variable holding the time doesn't work anymore. + *****************************************************************/ + +/* Module and initialization stuff */ +#include +#include + +/* Necessary includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Local defintions */ +#include "tracer.h" + +MODULE_AUTHOR ("Karim Yaghmour (karym@opersys.com)"); +MODULE_DESCRIPTION("Linux Trace Toolkit (LTT) kernel tracing driver"); +MODULE_LICENSE ("GPL"); + +/* Number of events tracable */ +#if !CONFIG_RTAI_TRACE +#define TRACE_EVENT_ID_MAX TRACE_EV_MAX +#else +#define TRACE_EVENT_ID_MAX TRACE_RTAI_EV_MAX +#endif + +/* Local variables */ +/* Driver */ +static int sMajorNumber; /* Major number of the tracer */ +static int sOpenCount; /* Number of times device is open */ +/* Locking */ +static int sTracLock; /* Tracer lock used to lock primary buffer */ +static spinlock_t sSpinLock; /* Spinlock in order to lock kernel */ +/* Daemon */ +static int sSignalSent; /* A signal has been sent to the daemon */ +static int sSendSignal = FALSE; /* Should the daemon be summoned */ +static struct task_struct* sDaemonTaskStruct; /* Task structure of the tracer daemon */ +/* Tracer configuration */ +static int sTracerStarted; /* Is the tracer started */ +static trace_event_mask sTracedEvents; /* Bit-field of events being traced */ +static trace_event_mask sLogEventDetailsMask; /* Log the details of the events mask */ +static int sLogCPUID; /* Log the CPUID associated with each event */ +static int sUseSyscallEIPBounds; /* Use adress bounds to fetch the EIP where call is made */ +static int sLowerEIPBoundSet; /* The lower bound EIP has been set */ +static int sUpperEIPBoundSet; /* The upper bound EIP has been set */ +static void* sLowerEIPBound; /* The lower bound EIP */ +static void* sUpperEIPBound; /* The upper bound EIP */ +static int sTracingPID; /* Tracing only the events for one pid */ +static int sTracingPGRP; /* Tracing only the events for one process group */ +static int sTracingGID; /* Tracing only the events for one gid */ +static int sTracingUID; /* Tracing only the events for one uid */ +static pid_t sTracedPID; /* PID being traced */ +static pid_t sTracedPGRP; /* Process group being traced */ +static gid_t sTracedGID; /* GID being traced */ +static uid_t sTracedUID; /* UID being traced */ +static int sSyscallEIPDepthSet; /* The call depth at which to fetch EIP has been set */ +static int sSyscallEIPDepth; /* The call depth at which to fetch the EIP */ +/* Event data buffers */ +static int sBufReadComplete; /* Number of buffers completely filled */ +static int sSizeReadIncomplete; /* Quantity of data read from incomplete buffers */ +static int sEventsLost; /* Number of events lost because of lack of buffer space */ +static uint32_t sBufSize; /* Buffer sizes */ +static uint32_t sAllocSize; /* Size of buffers allocated */ +static uint32_t sBufferID; /* Unique buffer ID */ +static char* sTracBuf = NULL; /* Trace buffer */ +static char* sWritBuf = NULL; /* Buffer used for writting */ +static char* sReadBuf = NULL; /* Buffer used for reading */ +static char* sWritBufEnd; /* End of write buffer */ +static char* sReadBufEnd; /* End of read buffer */ +static char* sWritPos; /* Current position for writting */ +static char* sReadLimit; /* Limit at which read should stop */ +static char* sWritLimit; /* Limit at which write should stop */ +/* Time */ +static struct timeval sBufferStartTime; /* The time at which the buffer was started */ +/* Large data components allocated at load time */ +static char* sUserEventData = NULL; /* The data associated with a user event */ + + +/* The size of the structures used to describe the events */ +static int sEventStructSize[TRACE_EVENT_ID_MAX + 1] = +{ + sizeof(trace_start) /* TRACE_START */, + sizeof(trace_syscall_entry) /* TRACE_SYSCALL_ENTRY */, + 0 /* TRACE_SYSCALL_EXIT */, + sizeof(trace_trap_entry) /* TRACE_TRAP_ENTRY */, + 0 /* TRACE_TRAP_EXIT */, + sizeof(trace_irq_entry) /* TRACE_IRQ_ENTRY */, + 0 /* TRACE_IRQ_EXIT */, + sizeof(trace_schedchange) /* TRACE_SCHEDCHANGE */, + 0 /* TRACE_KERNEL_TIMER */, + sizeof(trace_soft_irq) /* TRACE_SOFT_IRQ */, + sizeof(trace_process) /* TRACE_PROCESS */, + sizeof(trace_file_system) /* TRACE_FILE_SYSTEM */, + sizeof(trace_timer) /* TRACE_TIMER */, + sizeof(trace_memory) /* TRACE_MEMORY */, + sizeof(trace_socket) /* TRACE_SOCKET */, + sizeof(trace_ipc) /* TRACE_IPC */, + sizeof(trace_network) /* TRACE_NETWORK */, + sizeof(trace_buffer_start) /* TRACE_BUFFER_START */, + 0 /* TRACE_BUFFER_END */, + sizeof(trace_new_event) /* TRACE_NEW_EVENT */, + sizeof(trace_custom) /* TRACE_CUSTOM */, + sizeof(trace_change_mask) /* TRACE_CHANGE_MASK */ +#if CONFIG_RTAI_TRACE + , + 0 /* TRACE_RTAI_MOUNT */, + 0 /* TRACE_RTAI_UMOUNT */, + sizeof(trace_rtai_global_irq_entry) /* TRACE_RTAI_GLOBAL_IRQ_ENTRY */, + 0 /* TRACE_RTAI_GLOBAL_IRQ_EXIT */, + sizeof(trace_rtai_own_irq_entry) /* TRACE_RTAI_OWN_IRQ_ENTRY */, + 0 /* TRACE_RTAI_OWN_IRQ_EXIT */, + sizeof(trace_rtai_trap_entry) /* TRACE_RTAI_TRAP_ENTRY */, + 0 /* TRACE_RTAI_TRAP_EXIT */, + sizeof(trace_rtai_srq_entry) /* TRACE_RTAI_SRQ_ENTRY */, + 0 /* TRACE_RTAI_SRQ_EXIT */, + sizeof(trace_rtai_switchto_linux) /* TRACE_RTAI_SWITCHTO_LINUX */, + sizeof(trace_rtai_switchto_rt) /* TRACE_RTAI_SWITCHTO_RT */, + sizeof(trace_rtai_sched_change) /* TRACE_RTAI_SCHED_CHANGE */, + sizeof(trace_rtai_task) /* TRACE_RTAI_TASK */, + sizeof(trace_rtai_timer) /* TRACE_RTAI_TIMER */, + sizeof(trace_rtai_sem) /* TRACE_RTAI_SEM */, + sizeof(trace_rtai_msg) /* TRACE_RTAI_MSG */, + sizeof(trace_rtai_rpc) /* TRACE_RTAI_RPC */, + sizeof(trace_rtai_mbx) /* TRACE_RTAI_MBX */, + sizeof(trace_rtai_fifo) /* TRACE_RTAI_FIFO */, + sizeof(trace_rtai_shm) /* TRACE_RTAI_SHM */, + sizeof(trace_rtai_posix) /* TRACE_RTAI_POSIX */, + sizeof(trace_rtai_lxrt) /* TRACE_RTAI_LXRT */, + sizeof(trace_rtai_lxrti) /* TRACE_RTAI_LXRTI */ +#endif +}; + +/* The file operations available for the tracer */ +static struct file_operations sTracerFileOps = +{ + owner: THIS_MODULE, + ioctl: tracer_ioctl, + mmap: tracer_mmap, + open: tracer_open, + release: tracer_release, + fsync: tracer_fsync, +}; + +/************************************************************************************************************/ +/************************************** Code inspired from BTTV driver **************************************/ +/************************************************************************************************************/ +#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE /* This inspired by rtai/shmem */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + } + } + } + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} + +static void * rvmalloc(signed long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, signed long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +static int tracer_mmap_region(const char *adr, const char *start_pos, unsigned long size) +{ + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + pos=(unsigned long) start_pos; + while (size > 0) + { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + +/************************************************************** + * Macro : tracer_write_to_buffer() + * Description : + * Writes data to the destination buffer and updates the + * begining the buffer write position. + **************************************************************/ +#define tracer_write_to_buffer(DEST, SRC, SIZE) \ +do\ +{\ + memcpy(DEST, SRC, SIZE);\ + DEST += SIZE;\ +} while(0); + +/************************************************************** + * Function : trace() + * Description : Tracing function per se. + * Parameters : + * pmEventID, ID of event as defined in linux/trace.h + * pmEventStruct, struct describing the event + * Return values : + * 0, if everything went OK (event got registered) + * -ENODEV, no tracing daemon opened the driver. + * -ENOMEM, no more memory to store events. + * -EBUSY, tracer not started yet. + * Note : + * The kernel has to be locked here because trace() could + * be called from an interrupt handling routine and from + * a process service routine. + **************************************************************/ +int trace(uint8_t pmEventID, + void* pmEventStruct) +{ + int lVarDataLen = 0; /* Length of variable length data to be copied, if any */ + void* lVarDataBeg = NULL; /* Begining of variable length data to be copied */ + uint8_t lCPUID; /* CPUID of currently runing process */ + uint16_t lDataSize; /* Size of tracing data */ + struct siginfo lSigInfo; /* Signal information */ + struct timeval lTime; /* Event time */ + unsigned long int lFlags; /* CPU flags for lock */ + trace_time_delta lTimeDelta; /* The time elapsed between now and the last event */ + struct task_struct* pIncomingProcess = NULL; /* Pointer to incoming process */ + + /* Is there a tracing daemon */ + if(sDaemonTaskStruct == NULL) + return -ENODEV; + + /* Is this the exit of a process? */ + if((pmEventID == TRACE_EV_PROCESS) && + (pmEventStruct != NULL) && + ((((trace_process*) pmEventStruct)->event_sub_id) == TRACE_EV_PROCESS_EXIT)) + trace_destroy_owners_events(current->pid); + + /* Do we trace the event */ + if((sTracerStarted == TRUE) || (pmEventID == TRACE_EV_START) || (pmEventID == TRACE_EV_BUFFER_START)) + goto TraceEvent; + + /* We can't continue */ + return -EBUSY; + +TraceEvent: + + /* Are we monitoring this event */ + if(!ltt_test_bit(pmEventID, &sTracedEvents)) + return 0; + + /* Always let the start event pass, whatever the IDs */ + if((pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START)) + { + /* Is this a scheduling change */ + if(pmEventID == TRACE_EV_SCHEDCHANGE) + { + /* Get pointer to incoming process */ + pIncomingProcess = (struct task_struct*) (((trace_schedchange*) pmEventStruct)->in); + + /* Set PID information in schedchange event */ + (((trace_schedchange*) pmEventStruct)->in) = pIncomingProcess->pid; + } + + /* Are we monitoring a particular process */ + if((sTracingPID == TRUE) && (current->pid != sTracedPID)) + { + /* Record this event if it is the scheduling change bringing in the traced PID */ + if(pIncomingProcess == NULL) + return 0; + else if (pIncomingProcess->pid != sTracedPID) + return 0; + } + + /* Are we monitoring a particular process group */ + if((sTracingPGRP == TRUE) && (current->pgrp != sTracedPGRP)) + { + /* Record this event if it is the scheduling change bringing in a process of the traced PGRP */ + if(pIncomingProcess == NULL) + return 0; + else if (pIncomingProcess->pgrp != sTracedPGRP) + return 0; + } + + /* Are we monitoring the processes of a given group of users */ + if((sTracingGID == TRUE) && (current->egid != sTracedGID)) + { + /* Record this event if it is the scheduling change bringing in a process of the traced GID */ + if(pIncomingProcess == NULL) + return 0; + else if (pIncomingProcess->egid != sTracedGID) + return 0; + } + + /* Are we monitoring the processes of a given user */ + if((sTracingUID == TRUE) && (current->euid != sTracedUID)) + { + /* Record this event if it is the scheduling change bringing in a process of the traced UID */ + if(pIncomingProcess == NULL) + return 0; + else if (pIncomingProcess->euid != sTracedUID) + return 0; + } + } + + /* Compute size of tracing data */ + lDataSize = sizeof(pmEventID) + sizeof(lTimeDelta) + sizeof(lDataSize); + + /* Do we log the event details */ + if(ltt_test_bit(pmEventID, &sLogEventDetailsMask)) + { + /* Update the size of the data entry */ + lDataSize += sEventStructSize[pmEventID]; + + /* Some events have variable length */ + switch(pmEventID) + { + /* Is there a file name in this */ + case TRACE_EV_FILE_SYSTEM: + if((((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_EXEC) + || (((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_OPEN)) + { + /* Remember the string's begining and update size variables */ + lVarDataBeg = ((trace_file_system*) pmEventStruct)->file_name; + lVarDataLen = ((trace_file_system*) pmEventStruct)->event_data2 + 1; + lDataSize += (uint16_t) lVarDataLen; + } + break; + + /* Logging of a custom event */ + case TRACE_EV_CUSTOM: + lVarDataBeg = ((trace_custom*) pmEventStruct)->data; + lVarDataLen = ((trace_custom*) pmEventStruct)->data_size; + lDataSize += (uint16_t) lVarDataLen; + break; + } + } + + /* Do we record the CPUID */ + if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START)) + { + /* Remember the CPUID */ + lCPUID = smp_processor_id(); + + /* Update the size of the data entry */ + lDataSize += sizeof(lCPUID); + } + + /* Lock the kernel */ + RT_spin_lock_irqsave(&sSpinLock, lFlags); + + /* The following time calculations have to be done within the spinlock because + otherwise the event order could be inverted. */ + + /* Get the time of the event */ + do_gettimeofday(&lTime); + + /* Compute the time delta between this event and the time at which this buffer was started */ + lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000 + + (lTime.tv_usec - sBufferStartTime.tv_usec); + + /* Is there enough space left in the write buffer */ + if(sWritPos + lDataSize > sWritLimit) + { + /* Have we already switched buffers and informed the daemon of it */ + if(sSignalSent == TRUE) + { + /* We've lost another event */ + sEventsLost++; + + /* Bye, bye, now */ + RT_spin_unlock_irqrestore(&sSpinLock, lFlags); + return -ENOMEM; + } + + /* We need to inform the daemon */ + sSendSignal = TRUE; + + /* Switch buffers */ + tracer_switch_buffers(lTime); + + /* Recompute the time delta since sBufferStartTime has changed because of the buffer change */ + lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000 + + (lTime.tv_usec - sBufferStartTime.tv_usec); + } + + /* Write the CPUID to the tracing buffer, if required */ + if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START)) + tracer_write_to_buffer(sWritPos, + &lCPUID, + sizeof(lCPUID)); + + /* Write event type to tracing buffer */ + tracer_write_to_buffer(sWritPos, + &pmEventID, + sizeof(pmEventID)); + + /* Write event time delta to tracing buffer */ + tracer_write_to_buffer(sWritPos, + &lTimeDelta, + sizeof(lTimeDelta)); + + /* Do we log event details */ + if(ltt_test_bit(pmEventID, &sLogEventDetailsMask)) + { + /* Write event structure */ + tracer_write_to_buffer(sWritPos, + pmEventStruct, + sEventStructSize[pmEventID]); + + /* Write string if any */ + if(lVarDataLen) + tracer_write_to_buffer(sWritPos, + lVarDataBeg, + lVarDataLen); + } + + /* Write the length of the event description */ + tracer_write_to_buffer(sWritPos, + &lDataSize, + sizeof(lDataSize)); + + /* Should the tracing daemon be notified (make sure no RTAI event calls on send_sig_info()) */ + if((sSendSignal == TRUE) && (pmEventID <= TRACE_EV_MAX)) + { + /* We don't need to send the signal anymore */ + sSendSignal = FALSE; + + /* Remember that a signal has been sent */ + sSignalSent = TRUE; + + /* Unlock the kernel */ + RT_spin_unlock_irqrestore(&sSpinLock, lFlags); + + /* Setup signal information */ + lSigInfo.si_signo = SIGIO; + lSigInfo.si_errno = 0; + lSigInfo.si_code = SI_KERNEL; + + /* DEBUG */ +#if 0 + printk("<1> Sending SIGIO to %d \n", sDaemonTaskStruct->pid); +#endif + + /* Signal the tracing daemon */ + send_sig_info(SIGIO, &lSigInfo, sDaemonTaskStruct); + } + else + /* Unlock the kernel */ + RT_spin_unlock_irqrestore(&sSpinLock, lFlags); + + /* Indicate to the caller that everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_switch_buffers() + * Description : + * Put the current write buffer to be read and reset put + * the old read buffer to be written to. Set the tracer + * variables in consequence. + * Parameters : + * pmTime, current time + * Return values : + * NONE + * Note : + * This should be called from within a spin_lock. + *************************************************************/ +void tracer_switch_buffers(struct timeval pmTime) +{ + char* lTempBuf; /* Temporary buffer pointer */ + char* lTempBufEnd; /* Temporary buffer end pointer */ + char* lInitWritPos; /* Initial write position */ + uint8_t lEventID; /* Event ID of last event */ + uint8_t lCPUID; /* CPUID of currently runing process */ + uint16_t lDataSize; /* Size of tracing data */ + uint32_t lSizeLost; /* Size delta between last event and end of buffer */ + trace_time_delta lTimeDelta; /* The time elapsed between now and the last event */ + trace_buffer_start lStartBufferEvent; /* Start of the new buffer event */ + + /* Remember initial write position */ + lInitWritPos = sWritPos; + + /* Write the end event at the write of the buffer */ + + /* Write the CPUID to the tracing buffer, if required */ + if(sLogCPUID == TRUE) + { + lCPUID = smp_processor_id(); + tracer_write_to_buffer(sWritPos, + &lCPUID, + sizeof(lCPUID)); + } + + /* Write event type to tracing buffer */ + lEventID = TRACE_EV_BUFFER_END; + tracer_write_to_buffer(sWritPos, + &lEventID, + sizeof(lEventID)); + + /* Write event time delta to tracing buffer */ + lTimeDelta = 0; + tracer_write_to_buffer(sWritPos, + &lTimeDelta, + sizeof(lTimeDelta)); + + /* Get size lost */ + lSizeLost = sWritBufEnd - lInitWritPos; + + /* Write size lost at the end of the buffer */ + *((uint32_t*) (sWritBufEnd - sizeof(lSizeLost))) = lSizeLost; + + /* Switch buffers */ + lTempBuf = sReadBuf; + sReadBuf = sWritBuf; + sWritBuf = lTempBuf; + + /* Set buffer ends */ + lTempBufEnd = sReadBufEnd; + sReadBufEnd = sWritBufEnd; + sWritBufEnd = lTempBufEnd; + + /* Set read limit */ + sReadLimit = sReadBufEnd; + + /* Set write limit */ + sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE; + + /* Set write position */ + sWritPos = sWritBuf; + + /* Increment buffer ID */ + sBufferID++; + + /* Set the time of begining of this buffer */ + sBufferStartTime = pmTime; + + /* Write the start of buffer event */ + lStartBufferEvent.ID = sBufferID; + lStartBufferEvent.Time = pmTime; + + /* Write event type to tracing buffer */ + lEventID = TRACE_EV_BUFFER_START; + tracer_write_to_buffer(sWritPos, + &lEventID, + sizeof(lEventID)); + + /* Write event time delta to tracing buffer */ + lTimeDelta = 0; + tracer_write_to_buffer(sWritPos, + &lTimeDelta, + sizeof(lTimeDelta)); + + /* Write event structure */ + tracer_write_to_buffer(sWritPos, + &lStartBufferEvent, + sizeof(lStartBufferEvent)); + + /* Compute the data size */ + lDataSize = sizeof(lEventID) + + sizeof(lTimeDelta) + + sizeof(lStartBufferEvent) + + sizeof(lDataSize); + + /* Write the length of the event description */ + tracer_write_to_buffer(sWritPos, + &lDataSize, + sizeof(lDataSize)); +} + +/************************************************************* + * Function : tracer_ioctl() + * Description : "Ioctl" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * pmCmd, command given by the caller + * pmArg, arguments to the command + * Return values : + * >0, In case the caller requested the number of events + * lost. + * 0, Everything went OK + * -ENOSYS, no such command + * -EINVAL, tracer not properly configured + * -EBUSY, tracer can't be reconfigured while in operation + * -ENOMEM, no more memory + * -EFAULT, unable to access user space memory + * Note : + * In the future, this function should check to make sure + * that it's the server that make thes ioctl. + *************************************************************/ +int tracer_ioctl(struct inode* pmInode, + struct file* pmFile, + unsigned int pmCmd, + unsigned long pmArg) +{ + int lRetValue; /* Function return value */ + int lDevMinor; /* Device minor number */ + int lNewUserEventID; /* ID of newly created user event */ + trace_start lStartEvent; /* Event marking the begining of the trace */ + unsigned long int lFlags; /* CPU flags for lock */ + trace_custom lUserEvent; /* The user event to be logged */ + trace_change_mask lTraceMask; /* Event mask */ + trace_new_event lNewUserEvent; /* The event to be created for the user */ + trace_buffer_start lStartBufferEvent; /* Start of the new buffer event */ + +#if 0 + printk("Tracer: Command %d \n", pmCmd); +#endif + + /* Get device's minor number */ + lDevMinor = MINOR(pmInode->i_rdev) & 0xf; + + /* If the tracer is started, the daemon can't modify the configuration */ + if((lDevMinor == 0) + && (sTracerStarted == TRUE) && (pmCmd != TRACER_STOP) && (pmCmd != TRACER_DATA_COMITTED)) + return -EBUSY; + + /* Only some operation are permitted to user processes trying to log events */ + if((lDevMinor == 1) + && (pmCmd != TRACER_CREATE_USER_EVENT) + && (pmCmd != TRACER_DESTROY_USER_EVENT) + && (pmCmd != TRACER_TRACE_USER_EVENT) + && (pmCmd != TRACER_SET_EVENT_MASK) + && (pmCmd != TRACER_GET_EVENT_MASK)) + return -ENOSYS; + + /* Depending on the command executed */ + switch(pmCmd) + { + /* Start the tracer */ + case TRACER_START : + /* Check if the device has been properly set up */ + if(((sUseSyscallEIPBounds == TRUE) + &&(sSyscallEIPDepthSet == TRUE)) + ||((sUseSyscallEIPBounds == TRUE) + &&((sLowerEIPBoundSet != TRUE) + ||(sUpperEIPBoundSet != TRUE))) + ||((sTracingPID == TRUE) + &&(sTracingPGRP == TRUE))) + return -EINVAL; + + /* Set the kernel-side trace configuration */ + if(trace_set_config(trace, + sSyscallEIPDepthSet, + sUseSyscallEIPBounds, + sSyscallEIPDepth, + sLowerEIPBound, + sUpperEIPBound) < 0) + return -EINVAL; + + /* Always log the start event and the buffer start event */ + ltt_set_bit(TRACE_EV_BUFFER_START, &sTracedEvents); + ltt_set_bit(TRACE_EV_BUFFER_START, &sLogEventDetailsMask); + ltt_set_bit(TRACE_EV_START, &sTracedEvents); + ltt_set_bit(TRACE_EV_START, &sLogEventDetailsMask); + ltt_set_bit(TRACE_EV_CHANGE_MASK, &sTracedEvents); + ltt_set_bit(TRACE_EV_CHANGE_MASK, &sLogEventDetailsMask); + + /* Get the time of start */ + do_gettimeofday(&sBufferStartTime); + + /* Set the event description */ + lStartBufferEvent.ID = sBufferID; + lStartBufferEvent.Time = sBufferStartTime; + + /* Set the event description */ + lStartEvent.MagicNumber = TRACER_MAGIC_NUMBER; +#ifdef __i386__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_I386; + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_NONE; +#endif +#ifdef __powerpc__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_PPC; +#if defined(CONFIG_4xx) + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_PPC_4xx; +#elif defined(CONFIG_6xx) + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_PPC_6xx; +#elif defined(CONFIG_8xx) + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_PPC_8xx; +#elif defined(CONFIG_PPC_ISERIES) + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_PPC_ISERIES; +#endif +#endif +#ifdef __sh__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_SH; + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_NONE; +#endif +#ifdef __s390__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_S390; + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_NONE; +#endif +#ifdef __mips__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_MIPS; + lStartEvent.ArchVariant = TRACE_ARCH_VARIANT_NONE; +#endif +#if !CONFIG_RTAI_TRACE + lStartEvent.SystemType = TRACE_SYS_TYPE_VANILLA_LINUX; +#else + lStartEvent.SystemType = TRACE_SYS_TYPE_RTAI_LINUX; +#endif + lStartEvent.MajorVersion = TRACER_VERSION_MAJOR; + lStartEvent.MinorVersion = TRACER_VERSION_MINOR; + lStartEvent.BufferSize = sBufSize; + lStartEvent.EventMask = sTracedEvents; + lStartEvent.DetailsMask = sLogEventDetailsMask; + lStartEvent.LogCPUID = sLogCPUID; + + /* Trace the buffer start event */ + trace(TRACE_EV_BUFFER_START, &lStartBufferEvent); + + /* Trace the start event */ + trace(TRACE_EV_START, &lStartEvent); + + /* We can start tracing */ + sTracerStarted = TRUE; + + /* Reregister custom trace events created earlier */ + trace_reregister_custom_events(); + break; + + /* Stop the tracer */ + case TRACER_STOP : + /* Stop tracing */ + sTracerStarted = FALSE; + + /* Acquire the lock to avoid SMP case of where another CPU is writing a trace + while buffer is being switched */ + RT_spin_lock_irqsave(&sSpinLock, lFlags); + + /* Switch the buffers to ensure that the end of the buffer mark is set (time isn't important) */ + tracer_switch_buffers(sBufferStartTime); + + /* Release lock */ + RT_spin_unlock_irqrestore(&sSpinLock, lFlags); + break; + + /* Set the tracer to the default configuration */ + case TRACER_CONFIG_DEFAULT : + tracer_set_default_config(); + break; + + /* Set the memory buffers the daemon wants us to use */ + case TRACER_CONFIG_MEMORY_BUFFERS : + /* Is the given size "reasonnable" */ + if(pmArg < TRACER_MIN_BUF_SIZE) + return -EINVAL; + + /* Set the buffer's size */ + return tracer_set_buffer_size(pmArg); + break; + + /* Trace the given events */ + case TRACER_CONFIG_EVENTS : + if(copy_from_user(&sTracedEvents, (void*) pmArg, sizeof(sTracedEvents))) + return -EFAULT; + break; + + /* Record the details of the event, or not */ + case TRACER_CONFIG_DETAILS : + if(copy_from_user(&sLogEventDetailsMask, (void*) pmArg, sizeof(sLogEventDetailsMask))) + return -EFAULT; + break; + + /* Record the CPUID associated with the event */ + case TRACER_CONFIG_CPUID : + sLogCPUID = TRUE; + break; + + /* Trace only one process */ + case TRACER_CONFIG_PID : + sTracingPID = TRUE; + sTracedPID = pmArg; + break; + + /* Trace only the given process group */ + case TRACER_CONFIG_PGRP : + sTracingPGRP = TRUE; + sTracedPGRP = pmArg; + break; + + /* Trace the processes of a given group of users */ + case TRACER_CONFIG_GID : + sTracingGID = TRUE; + sTracedGID = pmArg; + break; + + /* Trace the processes of a given user */ + case TRACER_CONFIG_UID : + sTracingUID = TRUE; + sTracedUID = pmArg; + break; + + /* Set the call depth a which the EIP should be fetched on syscall */ + case TRACER_CONFIG_SYSCALL_EIP_DEPTH : + sSyscallEIPDepthSet = TRUE; + sSyscallEIPDepth = pmArg; + break; + + /* Set the lowerbound address from which EIP is recorded on syscall */ + case TRACER_CONFIG_SYSCALL_EIP_LOWER : + /* We are using bounds for fetching the EIP where syscall was made */ + sUseSyscallEIPBounds = TRUE; + + /* Set the lower bound */ + sLowerEIPBound = (void*) pmArg; + + /* The lower bound has been set */ + sLowerEIPBoundSet = TRUE; + break; + + /* Set the upperbound address from which EIP is recorded on syscall */ + case TRACER_CONFIG_SYSCALL_EIP_UPPER : + /* We are using bounds for fetching the EIP where syscall was made */ + sUseSyscallEIPBounds = TRUE; + + /* Set the lower bound */ + sUpperEIPBound = (void*) pmArg; + + /* The lower bound has been set */ + sUpperEIPBoundSet = TRUE; + break; + + /* The daemon has comitted the last trace */ + case TRACER_DATA_COMITTED : +#if 0 + printk("Tracer: Data has been comitted \n"); +#endif + + /* Safely set the signal sent flag to FALSE */ + RT_spin_lock_irqsave(&sSpinLock, lFlags); + sSignalSent = FALSE; + RT_spin_unlock_irqrestore(&sSpinLock, lFlags); + break; + + /* Get the number of events lost */ + case TRACER_GET_EVENTS_LOST : + return sEventsLost; + break; + + /* Create a user event */ + case TRACER_CREATE_USER_EVENT : + /* Copy the information from user space */ + if(copy_from_user(&lNewUserEvent, (void*) pmArg, sizeof(lNewUserEvent))) + return -EFAULT; + + /* Create the event */ + lNewUserEventID = trace_create_owned_event(lNewUserEvent.type, + lNewUserEvent.desc, + lNewUserEvent.format_type, + lNewUserEvent.form, + current->pid); + + /* Has the operation succeded */ + if(lNewUserEventID >= 0) + { + /* Set the event ID */ + lNewUserEvent.id = lNewUserEventID; + + /* Copy the event information back to user space */ + if(copy_to_user((void*) pmArg, &lNewUserEvent, sizeof(lNewUserEvent))) + { + /* Since we were unable to tell the user about the event, destroy it */ + trace_destroy_event(lNewUserEventID); + return -EFAULT; + } + } + else + /* Forward trace_create_event()'s error code */ + return lNewUserEventID; + break; + + /* Destroy a user event */ + case TRACER_DESTROY_USER_EVENT : + /* Pass on the user's request */ + trace_destroy_event((int) pmArg); + break; + + /* Trace a user event */ + case TRACER_TRACE_USER_EVENT : + /* Copy the information from user space */ + if(copy_from_user(&lUserEvent, (void*) pmArg, sizeof(lUserEvent))) + return -EFAULT; + + /* Copy the user event data */ + if(copy_from_user(sUserEventData, lUserEvent.data, lUserEvent.data_size)) + return -EFAULT; + + /* Log the raw event */ + lRetValue = trace_raw_event(lUserEvent.id, + lUserEvent.data_size, + sUserEventData); + + /* Has the operation failed */ + if(lRetValue < 0) + /* Forward trace_create_event()'s error code */ + return lRetValue; + break; + + /* Set event mask */ + case TRACER_SET_EVENT_MASK : + /* Copy the information from user space */ + if(copy_from_user(&(lTraceMask.mask), (void*) pmArg, sizeof(lTraceMask.mask))) + return -EFAULT; + + /* Trace the event */ + lRetValue = trace(TRACE_EV_CHANGE_MASK, &lTraceMask); + + /* Change the event mask. (This has to be done second or else may loose the + information if the user decides to stop logging "change mask" events) */ + memcpy(&sTracedEvents, &(lTraceMask.mask), sizeof(lTraceMask.mask)); + + /* Always trace the buffer start, the trace start and the change mask */ + ltt_set_bit(TRACE_EV_BUFFER_START, &sTracedEvents); + ltt_set_bit(TRACE_EV_START, &sTracedEvents); + ltt_set_bit(TRACE_EV_CHANGE_MASK, &sTracedEvents); + + /* Forward trace()'s error code */ + return lRetValue; + break; + + /* Get event mask */ + case TRACER_GET_EVENT_MASK : + /* Copy the information to user space */ + if(copy_to_user((void*) pmArg, &sTracedEvents, sizeof(sTracedEvents))) + return -EFAULT; + break; + + /* Unknow command */ + default : + return -ENOSYS; + } + + /* Everything went OK */ + return 0; +} + +/************************************************************* + * Function : tracer_mmap() + * Description : "Mmap" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * pmVmArea, Virtual memory area description structure + * Return values : + * 0 if ok + * -EAGAIN, when remap failed + * -EACCESS, permission denied + ************************************************************/ +int tracer_mmap(struct file* pmFile, + struct vm_area_struct* pmVmArea) +{ + int lRetValue; /* Function's return value */ + + /* Only the trace daemon is allowed access to mmap */ + if(current != sDaemonTaskStruct) + return -EACCES; + + /* Remap trace buffer into the process's memory space */ + lRetValue = tracer_mmap_region((char*) pmVmArea->vm_start, + sTracBuf, + pmVmArea->vm_end - pmVmArea->vm_start); + +#if 0 + printk("Tracer: Trace buffer virtual address => 0x%08X \n", (uint32_t)sTracBuf); + printk("Tracer: Trace buffer physical address => 0x%08X \n", (uint32_t)virt_to_phys(sTracBuf)); + printk("Tracer: Trace buffer virtual address in daemon space => 0x%08X \n", (uint32_t)pmVmArea->vm_start); + printk("Tracer: Trace buffer physical address in daemon space => 0x%08X \n", (uint32_t)virt_to_phys((void*)pmVmArea->vm_start)); +#endif + + /* Tell the caller that the memory mapping worked OK */ + return lRetValue; +} + +/************************************************************* + * Function : tracer_open() + * Description : "Open" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * Return values : + * 0, everything went OK + * -ENODEV, no such device. + * -EBUSY, daemon channel (minor number 0) already in use. + ************************************************************/ +int tracer_open(struct inode* pmInode, + struct file* pmFile) +{ + int lDevMinor = MINOR(pmInode->i_rdev) & 0xf; /* Device minor number */ + + /* Only minor number 0 and 1 are used */ + if((lDevMinor > 0) && (lDevMinor != 1)) + return -ENODEV; + + /* If the device has already been opened */ + if(sOpenCount) + { + /* Is there another process trying to open the daemon's channel (minor number 0) */ + if(lDevMinor == 0) + /* This isn't allowed */ + return -EBUSY; + else + /* Only increment use, this is just another user process trying to log user events */ + goto IncrementUse; + } + + /* Fetch the task structure of the process that opened the device */ + sDaemonTaskStruct = current; + + /* Reset the default configuration since this is the daemon and he will complete the setup */ + tracer_set_default_config(); + +#if 0 + /* DEBUG */ + printk("<1>Process %d opened the tracing device \n", sDaemonTaskStruct->pid); +#endif + +IncrementUse: + /* Lock the device */ + sOpenCount++; + +#ifdef MODULE + /* Increment module usage */ + MOD_INC_USE_COUNT; +#endif + + /* Everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_release() + * Description : "Release" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * Return values : + * 0, everything went OK + * Note : + * It is assumed that if the tracing daemon dies, exits + * or simply stops existing, the kernel or "someone" will + * call tracer_release. Otherwise, we're in trouble ... + *************************************************************/ +int tracer_release(struct inode* pmInode, + struct file* pmFile) +{ + int lDevMinor = MINOR(pmInode->i_rdev) & 0xf; /* Device minor number */ + + /* Is this a simple user process exiting? */ + if(lDevMinor != 0) + goto DecrementUse; + + /* Did we loose any events */ + if(sEventsLost > 0) + printk(KERN_ALERT "Tracer: Lost %d events \n", sEventsLost); + + /* Reset the daemon PID */ + sDaemonTaskStruct = NULL; + + /* Free the current buffers, if any */ + if(sTracBuf != NULL) + rvfree(sTracBuf, sAllocSize); + + /* Reset the read and write buffers */ + sTracBuf = NULL; + sWritBuf = NULL; + sReadBuf = NULL; + sWritBufEnd = NULL; + sReadBufEnd = NULL; + sWritPos = NULL; + sReadLimit = NULL; + sWritLimit = NULL; + + /* Reset the tracer's configuration */ + tracer_set_default_config(); + sTracerStarted = FALSE; + + /* Reset number of bytes recorded and number of events lost */ + sBufReadComplete = 0; + sSizeReadIncomplete = 0; + sEventsLost = 0; + + /* Reset signal sent */ + sSignalSent = FALSE; + +DecrementUse: + /* Unlock the device */ + sOpenCount--; + +#ifdef MODULE + /* Decrement module usage */ + MOD_DEC_USE_COUNT; +#endif + + /* Tell the caller that everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_fsync() + * Description : "Fsync" file op + * Parameters : + * pmFile, file structure given to the acting process + * pmDEntry, dentry associated with file + * Return values : + * 0, everything went OK + * -EACCESS, permission denied + * Note : + * We need to look the modifications of the values because + * they are read and written by trace(). + * Sonia : ne m oublie pas, je suis toujours a toi.... + *************************************************************/ +int tracer_fsync(struct file* pmFile, + struct dentry* pmDEntry, + int pmDataSync) +{ + unsigned long int lFlags; /* CPU flags for lock */ + + /* Only the trace daemon is allowed access to fsync */ + if(current != sDaemonTaskStruct) + return -EACCES; + + /* Lock the kernel */ + RT_spin_lock_irqsave(&sSpinLock, lFlags); + + /* Reset the write positions */ + sWritPos = sWritBuf; + + /* Reset read limit */ + sReadLimit = sReadBuf; + + /* Reset bytes recorded */ + sBufReadComplete = 0; + sSizeReadIncomplete = 0; + sEventsLost = 0; + + /* Reset signal sent */ + sSignalSent = FALSE; + + /* Unlock the kernel */ + RT_spin_unlock_irqrestore(&sSpinLock, lFlags); + + /* Tell the caller that everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_set_buffer_size() + * Description : + * Sets the size of the buffers containing the trace data. + * Parameters : + * pmSize, Size of buffers + * Return values : + * 0, Size setting went OK + * -ENOMEM, unable to get a hold of memory for tracer + *************************************************************/ +int tracer_set_buffer_size(int pmSize) +{ + int lSizeAlloc; /* Size to be allocated */ + + /* Set size to allocate (= pmSize * 2) and fix it's size to be on a page boundary */ + lSizeAlloc = FIX_SIZE(pmSize << 1); + + /* Free the current buffers, if any */ + if(sTracBuf != NULL) + rvfree(sTracBuf, sAllocSize); + + /* Allocate space for the tracing buffers */ + if((sTracBuf = (char*) rvmalloc(lSizeAlloc)) == NULL) + return -ENOMEM; + + /* Remember the size set */ + sBufSize = pmSize; + sAllocSize = lSizeAlloc; + + /* Set the read and write buffers */ + sWritBuf = sTracBuf; + sReadBuf = sTracBuf + sBufSize; + + /* Set end of buffers */ + sWritBufEnd = sWritBuf + sBufSize; + sReadBufEnd = sReadBuf + sBufSize; + + /* Set write position */ + sWritPos = sWritBuf; + + /* Set read limit */ + sReadLimit = sReadBuf; + + /* Set write limit */ + sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE; + + /* All is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_set_default_config() + * Description : Sets the tracer in its default config + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + *************************************************************/ +int tracer_set_default_config(void) +{ + int i; /* Generic index */ + int lError = 0; /* Error, if any */ + + /* Initialize the event mask */ + sTracedEvents = 0; + + /* Initialize the event mask with all existing events with their details*/ + for(i = 0; i <= TRACE_EVENT_ID_MAX; i++) + { + ltt_set_bit(i, &sTracedEvents); + ltt_set_bit(i, &sLogEventDetailsMask); + } + + /* Forget about the CPUID */ + sLogCPUID = FALSE; + + /* We aren't tracing any PID or GID in particular */ + sTracingPID = FALSE; + sTracingPGRP = FALSE; + sTracingGID = FALSE; + sTracingUID = FALSE; + + /* We aren't looking for a particular call depth */ + sSyscallEIPDepthSet = FALSE; + + /* We aren't going to place bounds on syscall EIP fetching */ + sUseSyscallEIPBounds = FALSE; + sLowerEIPBoundSet = FALSE; + sUpperEIPBoundSet = FALSE; + + /* Set the kernel trace configuration to it's basics */ + trace_set_config(trace, + sSyscallEIPDepthSet, + sUseSyscallEIPBounds, + 0, + 0, + 0); + + /* Return the error code */ + return lError; +} + +/************************************************************** + * Function : tracer_init() + * Description : Tracer initialization function. + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENONMEM, incapable of allocating necessary memory + * Forwarded error code otherwise + **************************************************************/ +int __init tracer_init(void) +{ + int lError = 0; /* Error, if any */ + + /* Initialize configuration */ + if((lError = tracer_set_default_config()) < 0) + return lError; + + /* Initialize open count */ + sOpenCount = 0; + + /* Initialize tracer lock */ + sTracLock = 0; + + /* Initialize signal sent */ + sSignalSent = FALSE; + + /* Initialize bytes read and events lost */ + sBufReadComplete = 0; + sSizeReadIncomplete = 0; + sEventsLost = 0; + + /* Initialize buffer ID */ + sBufferID = 0; + + /* Initialize tracing daemon task structure */ + sDaemonTaskStruct = NULL; + + /* Allocate memory for large data components */ + if((sUserEventData = vmalloc(CUSTOM_EVENT_MAX_SIZE)) < 0) + return -ENOMEM; + + /* Initialize spin lock */ + sSpinLock = SPIN_LOCK_UNLOCKED; + + /* Register the tracer as a char device */ + sMajorNumber = register_chrdev(0, TRACER_NAME, &sTracerFileOps); + + /* Register the tracer with the kernel */ + if((lError = register_tracer(trace)) < 0) + { + /* Tell the user about the problem */ + printk(KERN_ALERT "Tracer: Unable to register tracer with kernel, tracer disabled \n"); + + /* Make sure no one can open this device */ + sOpenCount = 1; + } + else + printk(KERN_INFO "Tracer: Initialization complete \n"); + + /* Are we configured to trace RTAI */ +#if CONFIG_RTAI_TRACE + /* Register the tracer with RTAI */ + rt_register_tracer(trace); +#endif + + /* Return error code */ + return lError; +} + +/* Is this loaded as a module */ +#ifdef MODULE +/************************************************************** + * Function : cleanup_module() + * Description : Cleanup of the tracer. + * Parameters : NONE + * Return values : NONE + * Note : The order of the unregesterings is important. First, + * rule out any possibility of getting more trace + * data. Second, rule out any possibility of being read + * by the tracing daemon. Last, free the tracing + * buffer. + **************************************************************/ +void tracer_exit(void) +{ + /* Are we configured to trace RTAI */ +#if CONFIG_RTAI_TRACE + /* Unregister the tracer from RTAI */ + rt_unregister_tracer(trace); +#endif + + /* Unregister the tracer from the kernel */ + unregister_tracer(trace); + + /* Unregister the tracer from being a char device */ + unregister_chrdev(sMajorNumber, TRACER_NAME); + + /* Free the current buffers, if any */ + if(sTracBuf != NULL) + rvfree(sTracBuf, sAllocSize); + + /* Paranoia */ + sTracBuf = NULL; +} +module_exit(tracer_exit); +#endif /* MODULE */ + +module_init(tracer_init); diff -urN linux-2.4.18/drivers/trace/tracer.h linux-2.4.18-rtai-rthal5g/drivers/trace/tracer.h --- linux-2.4.18/drivers/trace/tracer.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/drivers/trace/tracer.h 2002-04-15 23:30:11.000000000 -0400 @@ -0,0 +1,276 @@ +/* + * drivers/trace/tracer.h + * + * Copyright (C) 1999, 2000, 2001 Karim Yaghmour (karym@opersys.com) + * Portions contributed by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation + * + * This contains the necessary definitions the system tracer + */ + +#ifndef _TRACER_H +#define _TRACER_H + +/* Logic values */ +#define FALSE 0 +#define TRUE 1 + +/* Structure packing within the trace */ +#ifndef LTT_PACKED_STRUCT +#if LTT_UNPACKED_STRUCTS +#define LTT_PACKED_STRUCT +#else /* if LTT_UNPACKED_STRUCTS */ +#define LTT_PACKED_STRUCT __attribute__ ((packed)); +#endif /* if LTT_UNPACKED_STRUCTS */ +#endif /* if LTT_PACKED_STRUCT */ + +/* Tracer properties */ +#define TRACER_NAME "tracer" /* Name of the device as seen in /proc/devices */ + +/* Tracer buffer information */ +#define TRACER_DEFAULT_BUF_SIZE 50000 /* Default size of tracing buffer */ +#define TRACER_MIN_BUF_SIZE 1000 /* Minimum size of tracing buffer */ +#define TRACER_MAX_BUF_SIZE 500000 /* Maximum size of tracing buffer */ + +/* Local definitions */ +typedef uint32_t trace_time_delta; /* The type used to start the time delta between events */ + +/* Number of bytes set aside for last event */ +#define TRACER_LAST_EVENT_SIZE (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(trace_time_delta) + sizeof(uint32_t)) + +/* Architecture types */ +#define TRACE_ARCH_TYPE_I386 1 /* i386 system */ +#define TRACE_ARCH_TYPE_PPC 2 /* PPC system */ +#define TRACE_ARCH_TYPE_SH 3 /* SH system */ +#define TRACE_ARCH_TYPE_S390 4 /* S/390 system */ +#define TRACE_ARCH_TYPE_MIPS 5 /* MIPS system */ + +/* Standard definitions for variants */ +#define TRACE_ARCH_VARIANT_NONE 0 /* Main architecture implementation */ + +/* PowerPC variants */ +#define TRACE_ARCH_VARIANT_PPC_4xx 1 /* 4xx systems (IBM embedded series) */ +#define TRACE_ARCH_VARIANT_PPC_6xx 2 /* 6xx/7xx/74xx/8260/POWER3 systems (desktop flavor) */ +#define TRACE_ARCH_VARIANT_PPC_8xx 3 /* 8xx system (Motoral embedded series) */ +#define TRACE_ARCH_VARIANT_PPC_ISERIES 4 /* 8xx system (iSeries) */ + +/* System types */ +#define TRACE_SYS_TYPE_VANILLA_LINUX 1 /* Vanilla linux kernel */ +#define TRACE_SYS_TYPE_RTAI_LINUX 2 /* RTAI patched linux kernel */ + +/* The information logged when the tracing is started */ +#define TRACER_MAGIC_NUMBER 0x00D6B7ED /* That day marks an important historical event ... */ +#define TRACER_VERSION_MAJOR 1 /* Major version number */ +#define TRACER_VERSION_MINOR 14 /* Minor version number */ +typedef struct _trace_start +{ + uint32_t MagicNumber; /* Magic number to identify a trace */ + uint32_t ArchType; /* Type of architecture */ + uint32_t ArchVariant; /* Variant of the given type of architecture */ + uint32_t SystemType; /* Operating system type */ + uint8_t MajorVersion; /* Major version of trace */ + uint8_t MinorVersion; /* Minor version of trace */ + + uint32_t BufferSize; /* Size of buffers */ + trace_event_mask EventMask; /* The event mask */ + trace_event_mask DetailsMask; /* Are the event details logged */ + uint8_t LogCPUID; /* Is the CPUID logged */ +} LTT_PACKED_STRUCT trace_start; + +/* Start and end of trace buffer information */ +typedef struct _trace_buffer_start +{ + struct timeval Time; /* Time stamp of this buffer */ + uint32_t ID; /* Unique buffer ID */ +} LTT_PACKED_STRUCT trace_buffer_start; + +/* The configurations possible */ +#define TRACER_START TRACER_MAGIC_NUMBER + 0 /* Start tracing events using the current configuration */ +#define TRACER_STOP TRACER_MAGIC_NUMBER + 1 /* Stop tracing */ +#define TRACER_CONFIG_DEFAULT TRACER_MAGIC_NUMBER + 2 /* Set the tracer to the default configuration */ +#define TRACER_CONFIG_MEMORY_BUFFERS TRACER_MAGIC_NUMBER + 3 /* Set the memory buffers the daemon wants us to use */ +#define TRACER_CONFIG_EVENTS TRACER_MAGIC_NUMBER + 4 /* Trace the given events */ +#define TRACER_CONFIG_DETAILS TRACER_MAGIC_NUMBER + 5 /* Record the details of the event, or not */ +#define TRACER_CONFIG_CPUID TRACER_MAGIC_NUMBER + 6 /* Record the CPUID associated with the event */ +#define TRACER_CONFIG_PID TRACER_MAGIC_NUMBER + 7 /* Trace only one process */ +#define TRACER_CONFIG_PGRP TRACER_MAGIC_NUMBER + 8 /* Trace only the given process group */ +#define TRACER_CONFIG_GID TRACER_MAGIC_NUMBER + 9 /* Trace the processes of a given group of users */ +#define TRACER_CONFIG_UID TRACER_MAGIC_NUMBER + 10 /* Trace the processes of a given user */ +#define TRACER_CONFIG_SYSCALL_EIP_DEPTH TRACER_MAGIC_NUMBER + 11 /* Set the call depth at which the EIP should be fetched on syscall */ +#define TRACER_CONFIG_SYSCALL_EIP_LOWER TRACER_MAGIC_NUMBER + 12 /* Set the lowerbound address from which EIP is recorded on syscall */ +#define TRACER_CONFIG_SYSCALL_EIP_UPPER TRACER_MAGIC_NUMBER + 13 /* Set the upperbound address from which EIP is recorded on syscall */ +#define TRACER_DATA_COMITTED TRACER_MAGIC_NUMBER + 14 /* The daemon has comitted the last trace */ +#define TRACER_GET_EVENTS_LOST TRACER_MAGIC_NUMBER + 15 /* Get the number of events lost */ +#define TRACER_CREATE_USER_EVENT TRACER_MAGIC_NUMBER + 16 /* Create a user tracable event */ +#define TRACER_DESTROY_USER_EVENT TRACER_MAGIC_NUMBER + 17 /* Destroy a user tracable event */ +#define TRACER_TRACE_USER_EVENT TRACER_MAGIC_NUMBER + 18 /* Trace a user event */ +#define TRACER_SET_EVENT_MASK TRACER_MAGIC_NUMBER + 19 /* Set the trace event mask */ +#define TRACER_GET_EVENT_MASK TRACER_MAGIC_NUMBER + 20 /* Get the trace event mask */ + +#ifdef __powerpc__ +/* We need to replace the usual PPC kernel bit manipulation functions with + * equivalent functions that are cross-platform compatible. The PPC kernel + * functions define bit order as follows: + * + * bit 0: 0x0000000100000000 + * bit 1: 0x0000000200000000 + * . + * . + * . + * bit 7: 0x0000008000000000 + * bit 8: 0x0000010000000000 + * bit 9: 0x0000020000000000 + * . + * . + * . + * bit 31: 0x8000000000000000 + * bit 32: 0x0000000000000001 + * bit 33: 0x0000000000000002 + * . + * . + * . + * bit 63: 0x0000000080000000 + * + * Our redefined functions define bit order the same as the kernel bit functions + * for x86 targets: + * + * bit 0: 0x0100000000000000 + * bit 1: 0x0200000000000000 + * . + * . + * . + * bit 7: 0x8000000000000000 + * bit 8: 0x0001000000000000 + * bit 9: 0x0002000000000000 + * . + * . + * . + * bit 31: 0x0000000800000000 + * bit 32: 0x0000000001000000 + * bit 33: 0x0000000002000000 + * . + * . + * . + * bit 63: 0x0000000000000080 + */ +static inline int ltt_set_bit(int nr, volatile void * addr) +{ + unsigned long old, t; + unsigned long mask = 1 << (24 - (nr & 0x18) + (nr & 0x7)); + volatile unsigned long *p = ((volatile unsigned long *)addr) + (nr >> 5); + + __asm__ __volatile__( + "1:lwarx %0,0,%3 \n\t" + "or %1,%0,%2 \n\t" + "stwcx. %1,0,%3 \n\t" + "bne 1b \n\t" + : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/ + : "r" (mask), "r" (p) + /*: "cc" */); + + return (old & mask) != 0; +} + +static inline int ltt_clear_bit(unsigned long nr, volatile void *addr) +{ + unsigned long old, t; + unsigned long mask = 1 << (24 - (nr & 0x18) + (nr & 0x7)); + volatile unsigned long *p = ((volatile unsigned long *)addr) + (nr >> 5); + + __asm__ __volatile__("\n\ +1: lwarx %0,0,%3 + andc %1,%0,%2 + stwcx. %1,0,%3 + bne 1b" + : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/ + : "r" (mask), "r" (p) + /*: "cc"*/); + + return (old & mask) != 0; +} + +static inline int ltt_test_bit(int nr, __const__ volatile void *addr) +{ + __const__ volatile unsigned int *p = (__const__ volatile unsigned int *) addr; + + return ((p[nr >> 5] >> (24 - (nr & 0x18) + (nr & 0x7))) & 1) != 0; +} +#else /* ifdef __powerpc__ */ +#if defined(__s390__) || defined(__mips__) /* Added by T.H., modified by K.Y. for mips */ +/* Use functions taken from LTTTypes.h */ +extern __inline__ int ltt_set_bit(int nr, void * addr) +{ + unsigned char *p = addr; + unsigned char mask = 1 << (nr&7); + unsigned char old; + + p += nr>>3; + old = *p; + *p |= mask; + + return ((old & mask) != 0); +} + +extern __inline__ int ltt_clear_bit(int nr, void * addr) +{ + unsigned char *p = addr; + unsigned char mask = 1 << (nr&7); + unsigned char old; + + p += nr>>3; + old = *p; + *p &= ~mask; + + return ((old & mask) != 0); +} + +extern __inline__ int ltt_test_bit(int nr,void *addr) +{ + unsigned char *p = addr; + unsigned char mask = 1 << (nr&7); + + p += nr>>3; + + return ((*p & mask) != 0); +} +#else /* For non-powerpc and non-s390 processors we can use the kernel functions. */ +#define ltt_set_bit set_bit +#define ltt_clear_bit clear_bit +#define ltt_test_bit test_bit +#endif /* if defined(__s390__) || defined(__mips__) */ +#endif /* ifdef __powerpc__ */ + +/* Function prototypes */ +int trace + (uint8_t, + void*); +void tracer_switch_buffers + (struct timeval); +int tracer_ioctl + (struct inode*, + struct file*, + unsigned int, + unsigned long); +int tracer_mmap + (struct file*, + struct vm_area_struct*); +int tracer_open + (struct inode*, + struct file*); +int tracer_release + (struct inode*, + struct file*); +int tracer_fsync + (struct file*, + struct dentry*, + int); +#ifdef MODULE +void tracer_exit + (void); +#endif +int tracer_set_buffer_size + (int); +int tracer_set_default_config + (void); +int tracer_init + (void); +#endif /* _TRACER_H */ diff -urN linux-2.4.18/fs/buffer.c linux-2.4.18-rtai-rthal5g/fs/buffer.c --- linux-2.4.18/fs/buffer.c 2002-02-25 14:38:08.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/fs/buffer.c 2003-11-26 16:58:47.000000000 -0500 @@ -48,6 +48,8 @@ #include #include +#include + #include #include #include @@ -146,6 +148,7 @@ get_bh(bh); add_wait_queue(&bh->b_wait, &wait); do { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_START, 0, 0, NULL); run_task_queue(&tq_disk); set_task_state(tsk, TASK_UNINTERRUPTIBLE); if (!buffer_locked(bh)) @@ -153,6 +156,7 @@ schedule(); } while (buffer_locked(bh)); tsk->state = TASK_RUNNING; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_END, 0, 0, NULL); remove_wait_queue(&bh->b_wait, &wait); put_bh(bh); } diff -urN linux-2.4.18/fs/exec.c linux-2.4.18-rtai-rthal5g/fs/exec.c --- linux-2.4.18/fs/exec.c 2001-12-21 12:41:55.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/fs/exec.c 2003-11-26 16:59:59.000000000 -0500 @@ -38,6 +38,8 @@ #define __NO_VERSION__ #include +#include + #include #include #include @@ -866,6 +868,11 @@ if (IS_ERR(file)) return retval; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_EXEC, + 0, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); diff -urN linux-2.4.18/fs/ioctl.c linux-2.4.18-rtai-rthal5g/fs/ioctl.c --- linux-2.4.18/fs/ioctl.c 2001-02-09 14:29:44.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/fs/ioctl.c 2003-11-26 17:01:20.000000000 -0500 @@ -8,6 +8,8 @@ #include #include +#include + #include #include @@ -56,6 +58,10 @@ if (!filp) goto out; error = 0; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_IOCTL, + fd, + cmd, + NULL); lock_kernel(); switch (cmd) { case FIOCLEX: diff -urN linux-2.4.18/fs/open.c linux-2.4.18-rtai-rthal5g/fs/open.c --- linux-2.4.18/fs/open.c 2001-10-12 16:48:42.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/fs/open.c 2003-11-26 17:02:41.000000000 -0500 @@ -16,6 +16,8 @@ #include #include +#include + #include #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) @@ -789,6 +791,10 @@ error = PTR_ERR(f); if (IS_ERR(f)) goto out_error; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_OPEN, + fd, + f->f_dentry->d_name.len, + f->f_dentry->d_name.name); fd_install(fd, f); } out: @@ -855,6 +861,10 @@ filp = files->fd[fd]; if (!filp) goto out_unlock; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_CLOSE, + fd, + 0, + NULL); files->fd[fd] = NULL; FD_CLR(fd, files->close_on_exec); __put_unused_fd(files, fd); diff -urN linux-2.4.18/fs/read_write.c linux-2.4.18-rtai-rthal5g/fs/read_write.c --- linux-2.4.18/fs/read_write.c 2002-02-25 14:38:09.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/fs/read_write.c 2003-11-26 17:11:02.000000000 -0500 @@ -12,6 +12,8 @@ #include #include +#include + #include struct file_operations generic_ro_fops = { @@ -106,6 +108,10 @@ if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK, + fd, + offset, + NULL); fput(file); bad: return retval; @@ -131,6 +137,12 @@ offset = llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK, + fd, + offset, + NULL); + + retval = (int)offset; if (offset >= 0) { retval = -EFAULT; @@ -158,8 +170,13 @@ if (!ret) { ssize_t (*read)(struct file *, char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (read = file->f_op->read) != NULL) + if (file->f_op && (read = file->f_op->read) != NULL) { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ, + fd, + count, + NULL); ret = read(file, buf, count, &file->f_pos); + } } } if (ret > 0) @@ -184,8 +201,13 @@ if (!ret) { ssize_t (*write)(struct file *, const char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (write = file->f_op->write) != NULL) + if (file->f_op && (write = file->f_op->write) != NULL) { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE, + fd, + count, + NULL); ret = write(file, buf, count, &file->f_pos); + } } } if (ret > 0) @@ -309,6 +331,10 @@ file = fget(fd); if (!file) goto bad_file; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ, + fd, + count, + NULL); if (file->f_op && (file->f_mode & FMODE_READ) && (file->f_op->readv || file->f_op->read)) ret = do_readv_writev(VERIFY_WRITE, file, vector, count); @@ -329,6 +355,10 @@ file = fget(fd); if (!file) goto bad_file; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE, + fd, + count, + NULL); if (file->f_op && (file->f_mode & FMODE_WRITE) && (file->f_op->writev || file->f_op->write)) ret = do_readv_writev(VERIFY_READ, file, vector, count); @@ -364,6 +394,12 @@ goto out; if (pos < 0) goto out; + + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ, + fd, + count, + NULL); + ret = read(file, buf, count, &pos); if (ret > 0) dnotify_parent(file->f_dentry, DN_ACCESS); @@ -396,6 +432,11 @@ if (pos < 0) goto out; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE, + fd, + count, + NULL); + ret = write(file, buf, count, &pos); if (ret > 0) dnotify_parent(file->f_dentry, DN_MODIFY); diff -urN linux-2.4.18/fs/select.c linux-2.4.18-rtai-rthal5g/fs/select.c --- linux-2.4.18/fs/select.c 2001-09-10 16:04:33.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/fs/select.c 2003-11-26 17:12:28.000000000 -0500 @@ -20,6 +20,8 @@ #include /* for STICKY_TIMEOUTS */ #include +#include + #include #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) @@ -193,6 +195,10 @@ file = fget(i); mask = POLLNVAL; if (file) { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SELECT, + i /* The fd*/, + __timeout, + NULL); mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) mask = file->f_op->poll(file, wait); @@ -367,6 +373,10 @@ struct file * file = fget(fd); mask = POLLNVAL; if (file != NULL) { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_POLL, + fd, + 0, + NULL); mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) mask = file->f_op->poll(file, *pwait); diff -urN linux-2.4.18/include/asm-i386/hw_irq.h linux-2.4.18-rtai-rthal5g/include/asm-i386/hw_irq.h --- linux-2.4.18/include/asm-i386/hw_irq.h 2001-11-22 14:46:18.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/asm-i386/hw_irq.h 2003-11-27 23:12:25.000000000 -0500 @@ -37,18 +37,31 @@ * * Vectors 0xf0-0xfa are free (reserved for future Linux use). */ +#ifdef CONFIG_RTHAL +/* the standard definitions conflict with LXRT */ +#define SPURIOUS_APIC_VECTOR 0xdf +#define ERROR_APIC_VECTOR 0xde +#define INVALIDATE_TLB_VECTOR 0xdd +#define RESCHEDULE_VECTOR 0xdc +#define CALL_FUNCTION_VECTOR 0xdb +#else #define SPURIOUS_APIC_VECTOR 0xff #define ERROR_APIC_VECTOR 0xfe #define INVALIDATE_TLB_VECTOR 0xfd #define RESCHEDULE_VECTOR 0xfc #define CALL_FUNCTION_VECTOR 0xfb +#endif /* * Local APIC timer IRQ vector is on a different priority level, * to work around the 'lost local interrupt if more than 2 IRQ * sources per level' errata. */ +#ifdef CONFIG_RTHAL +#define LOCAL_TIMER_VECTOR 0xcf +#else #define LOCAL_TIMER_VECTOR 0xef +#endif /* * First APIC vector available to drivers: (vectors 0x30-0xee) @@ -56,7 +69,11 @@ * levels. (0x80 is the syscall vector) */ #define FIRST_DEVICE_VECTOR 0x31 +#ifdef CONFIG_RTHAL +#define FIRST_SYSTEM_VECTOR 0xcf +#else #define FIRST_SYSTEM_VECTOR 0xef +#endif extern int irq_vector[NR_IRQS]; #define IO_APIC_VECTOR(irq) irq_vector[irq] diff -urN linux-2.4.18/include/asm-i386/pgalloc.h linux-2.4.18-rtai-rthal5g/include/asm-i386/pgalloc.h --- linux-2.4.18/include/asm-i386/pgalloc.h 2001-12-21 12:42:03.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/asm-i386/pgalloc.h 2003-11-27 23:12:25.000000000 -0500 @@ -158,6 +158,33 @@ extern int do_check_pgt_cache(int, int); +extern inline void set_pgdir(unsigned long address, pgd_t entry) +{ + struct task_struct * p; + pgd_t *pgd; +#ifdef CONFIG_SMP + int i; +#endif + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); +#ifndef CONFIG_SMP + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#else + /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can + modify pgd caches of other CPUs as well. -jj */ + for (i = 0; i < NR_CPUS; i++) + for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#endif +} + /* * TLB flushing: * diff -urN linux-2.4.18/include/asm-i386/rtai.h linux-2.4.18-rtai-rthal5g/include/asm-i386/rtai.h --- linux-2.4.18/include/asm-i386/rtai.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/asm-i386/rtai.h 2003-11-27 23:12:25.000000000 -0500 @@ -0,0 +1,21 @@ +#ifndef __RTAI_H__ +#define __RTAI_H__ + +#include +#include + +static inline unsigned long rt_spin_lock_irqsave(spinlock_t *lock) +{ + unsigned long flags; + hard_save_flags_and_cli(flags); + spin_lock(lock); + return flags; +} + +static inline void rt_spin_unlock_irqrestore(unsigned long flags,spinlock_t *lock) +{ + spin_unlock(lock); + hard_restore_flags(flags); +} + +#endif diff -urN linux-2.4.18/include/asm-i386/system.h linux-2.4.18-rtai-rthal5g/include/asm-i386/system.h --- linux-2.4.18/include/asm-i386/system.h 2001-11-22 14:46:18.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/asm-i386/system.h 2003-11-27 23:12:25.000000000 -0500 @@ -12,7 +12,12 @@ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); -#define prepare_to_switch() do { } while(0) +#define prepare_to_switch() do { \ + if (rthal.lxrt_global_cli) { \ + rthal.lxrt_global_cli(); \ + } \ +} while(0) + #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ "pushl %%edi\n\t" \ @@ -23,6 +28,7 @@ "pushl %4\n\t" /* restore EIP */ \ "jmp __switch_to\n" \ "1:\t" \ + "sti\n\t" \ "popl %%ebp\n\t" \ "popl %%edi\n\t" \ "popl %%esi\n\t" \ @@ -310,18 +316,52 @@ #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ -#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) -#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") -#define __cli() __asm__ __volatile__("cli": : :"memory") -#define __sti() __asm__ __volatile__("sti": : :"memory") +#define hard_save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) +#define hard_restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") +#define hard_cli() __asm__ __volatile__("cli": : :"memory") +#define hard_sti() __asm__ __volatile__("sti": : :"memory") +#define hard_save_flags_and_cli(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */) /* used in the idle loop; sti takes one instruction cycle to complete */ -#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") - +#define safe_halt() __asm__ __volatile__("call *"SYMBOL_NAME_STR(rthal + 16)"; hlt": : :"memory") + /* For spinlocks etc */ -#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +//#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") +//#define local_irq_restore(x) __restore_flags(x) +//#define local_irq_disable() __cli() +//#define local_irq_enable() __sti() + +struct rt_hal { + void *ret_from_intr; + void *__switch_to; + struct desc_struct *idt_table; + void (*disint)(void); + void (*enint)(void); + unsigned int (*getflags)(void); + void (*setflags)(unsigned int flags); + unsigned int (*getflags_and_cli)(void); + void *irq_desc; + int *irq_vector; + unsigned long *irq_affinity; + void (*smp_invalidate_interrupt)(void); + void (*ack_8259_irq)(unsigned int); + int *idle_weight; + void (*lxrt_global_cli)(void); + void (*switch_mem)(struct task_struct *, struct task_struct *, int); + struct task_struct **init_tasks; + unsigned int *apicmap; +}; + +extern struct rt_hal rthal; + +#define __cli() (rthal.disint()) +#define __sti() (rthal.enint()) +#define __save_flags(x) ((x) = rthal.getflags()) +#define __restore_flags(x) (rthal.setflags(x)) + +#define local_irq_disable() (rthal.disint()) +#define local_irq_enable() (rthal.enint()) +#define local_irq_save(x) ((x) = rthal.getflags_and_cli()) +#define local_irq_restore(x) (rthal.setflags(x)) #ifdef CONFIG_SMP diff -urN linux-2.4.18/include/asm-ppc/system.h linux-2.4.18-rtai-rthal5g/include/asm-ppc/system.h --- linux-2.4.18/include/asm-ppc/system.h 2001-08-28 09:58:33.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/include/asm-ppc/system.h 2003-11-26 15:08:58.000000000 -0500 @@ -81,6 +81,7 @@ struct task_struct; #define prepare_to_switch() do { } while(0) +#define end_switch() do { } while(0) #define switch_to(prev,next,last) _switch_to((prev),(next),&(last)) extern void _switch_to(struct task_struct *, struct task_struct *, struct task_struct **); diff -urN linux-2.4.18/include/linux/rtai_trace.h linux-2.4.18-rtai-rthal5g/include/linux/rtai_trace.h --- linux-2.4.18/include/linux/rtai_trace.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/linux/rtai_trace.h 2003-11-27 23:14:31.000000000 -0500 @@ -0,0 +1,600 @@ +/* + * include/rtai_trace.h + * + * Copyright (C) 2000, Karim Yaghmour (karym@opersys.com) + * + * This contains the necessary definitions for the RTAI tracer + */ + +#ifndef __RTAI_TRACE_H__ +#define __RTAI_TRACE_H__ + +#if defined(CONFIG_RTAI_TRACE) + +#include + +/* Is RTAI tracing enabled */ + +/* The functions to the tracer management code */ +int rt_register_tracer + (tracer_call /* The tracer function */); +int rt_unregister_tracer + (tracer_call /* The tracer function */); +int rt_trace_event + (uint8_t /* Event ID (as defined in this header file) */, + void* /* Structure describing the event */); + +/* Generic macros */ +#define RT_TRACE_EVENT(ID, DATA) rt_trace_event(ID, DATA) + +#define TRACE_RTAI_START TRACE_EV_MAX + +/* Traced events */ +#define TRACE_RTAI_EV_MOUNT TRACE_RTAI_START + 1 /* The RTAI subsystem was mounted */ +#define TRACE_RTAI_EV_UMOUNT TRACE_RTAI_START + 2 /* The RTAI subsystem was unmounted */ +#define TRACE_RTAI_EV_GLOBAL_IRQ_ENTRY TRACE_RTAI_START + 3 /* Entry in a global IRQ */ +#define TRACE_RTAI_EV_GLOBAL_IRQ_EXIT TRACE_RTAI_START + 4 /* Exit from a global IRQ */ +#define TRACE_RTAI_EV_OWN_IRQ_ENTRY TRACE_RTAI_START + 5 /* Entry in a CPU own IRQ */ +#define TRACE_RTAI_EV_OWN_IRQ_EXIT TRACE_RTAI_START + 6 /* Exit from a CPU own IRQ */ +#define TRACE_RTAI_EV_TRAP_ENTRY TRACE_RTAI_START + 7 /* Entry in a trap */ +#define TRACE_RTAI_EV_TRAP_EXIT TRACE_RTAI_START + 8 /* Exit from a trap */ +#define TRACE_RTAI_EV_SRQ_ENTRY TRACE_RTAI_START + 9 /* Entry in a SRQ */ +#define TRACE_RTAI_EV_SRQ_EXIT TRACE_RTAI_START + 10 /* Exit from a SRQ */ +#define TRACE_RTAI_EV_SWITCHTO_LINUX TRACE_RTAI_START + 11 /* Switch a CPU to Linux */ +#define TRACE_RTAI_EV_SWITCHTO_RT TRACE_RTAI_START + 12 /* Switch a CPU to real-time */ +#define TRACE_RTAI_EV_SCHED_CHANGE TRACE_RTAI_START + 13 /* A scheduling change has occured */ +#define TRACE_RTAI_EV_TASK TRACE_RTAI_START + 14 /* Hit key part of task services */ +#define TRACE_RTAI_EV_TIMER TRACE_RTAI_START + 15 /* Hit key part of timer services */ +#define TRACE_RTAI_EV_SEM TRACE_RTAI_START + 16 /* Hit key part of semaphore services */ +#define TRACE_RTAI_EV_MSG TRACE_RTAI_START + 17 /* Hit key part of message services */ +#define TRACE_RTAI_EV_RPC TRACE_RTAI_START + 18 /* Hit key part of RPC services */ +#define TRACE_RTAI_EV_MBX TRACE_RTAI_START + 19 /* Hit key part of mail box services */ +#define TRACE_RTAI_EV_FIFO TRACE_RTAI_START + 20 /* Hit key part of FIFO services */ +#define TRACE_RTAI_EV_SHM TRACE_RTAI_START + 21 /* Hit key part of shared memory services */ +#define TRACE_RTAI_EV_POSIX TRACE_RTAI_START + 22 /* Hit key part of Posix services */ +#define TRACE_RTAI_EV_LXRT TRACE_RTAI_START + 23 /* Hit key part of LXRT services */ +#define TRACE_RTAI_EV_LXRTI TRACE_RTAI_START + 24 /* Hit key part of LXRT-Informed services */ + +/* Max number of traced events */ +#define TRACE_RTAI_EV_MAX TRACE_RTAI_EV_LXRTI + +/* Structures and macros for traced events */ +/* TRACE_RTAI_MOUNT */ +#define TRACE_RTAI_MOUNT() rt_trace_event(TRACE_RTAI_EV_MOUNT, NULL) + +/* TRACE_RTAI_UMOUNT */ +#define TRACE_RTAI_UMOUNT() rt_trace_event(TRACE_RTAI_EV_UMOUNT, NULL) + +/* TRACE_RTAI_GLOBAL_IRQ_ENTRY */ +typedef struct _trace_rtai_global_irq_entry +{ + uint8_t irq_id; /* IRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_rtai_global_irq_entry; +#if CONFIG_X86 +#define TRACE_RTAI_GLOBAL_IRQ_ENTRY(ID) \ + do \ + {\ + uint32_t eflags, xcs; \ + trace_rtai_global_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + __asm__ __volatile__("pushfl; pop %0": "=g" (eflags)); \ + __asm__ __volatile__("pushl %%cs; pop %0": "=g" (xcs)); \ + irq_entry.kernel = !((VM_MASK & eflags) || (3 & xcs));\ + rt_trace_event(TRACE_RTAI_EV_GLOBAL_IRQ_ENTRY, &irq_entry);\ + } while(0) +#endif +#if CONFIG_PPC +#define TRACE_RTAI_GLOBAL_IRQ_ENTRY(ID, KERNEL) \ + do \ + {\ + trace_rtai_global_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + irq_entry.kernel = KERNEL;\ + rt_trace_event(TRACE_RTAI_EV_GLOBAL_IRQ_ENTRY, &irq_entry);\ + } while(0) +#endif + +/* TRACE_RTAI_GLOBAL_IRQ_EXIT */ +#define TRACE_RTAI_GLOBAL_IRQ_EXIT() rt_trace_event(TRACE_RTAI_EV_GLOBAL_IRQ_EXIT, NULL) + +/* TRACE_RTAI_OWN_IRQ_ENTRY */ +typedef struct _trace_rtai_own_irq_entry +{ + uint8_t irq_id; /* IRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_rtai_own_irq_entry; +#if CONFIG_X86 +#define TRACE_RTAI_OWN_IRQ_ENTRY(ID) \ + do \ + {\ + uint32_t eflags, xcs; \ + trace_rtai_own_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + __asm__ __volatile__("pushfl; pop %0": "=g" (eflags)); \ + __asm__ __volatile__("pushl %%cs; pop %0": "=g" (xcs)); \ + irq_entry.kernel = !((VM_MASK & eflags) || (3 & xcs));\ + rt_trace_event(TRACE_RTAI_EV_OWN_IRQ_ENTRY, &irq_entry);\ + } while(0) +#endif +#if CONFIG_PPC +#define TRACE_RTAI_OWN_IRQ_ENTRY(ID, KERNEL) \ + do \ + {\ + trace_rtai_own_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + irq_entry.kernel = KERNEL;\ + rt_trace_event(TRACE_RTAI_EV_OWN_IRQ_ENTRY, &irq_entry);\ + } while(0) +#endif + +/* TRACE_RTAI_OWN_IRQ_EXIT */ +#define TRACE_RTAI_OWN_IRQ_EXIT() rt_trace_event(TRACE_RTAI_EV_OWN_IRQ_EXIT, NULL) + +/* TRACE_RTAI_TRAP_ENTRY */ +typedef struct _trace_rtai_trap_entry +{ + uint8_t trap_id; /* Trap number */ + uint32_t address; /* Address where trap occured */ +} LTT_PACKED_STRUCT trace_rtai_trap_entry; +#define TRACE_RTAI_TRAP_ENTRY(ID, ADDR) \ + do \ + {\ + trace_rtai_trap_entry trap_event;\ + trap_event.trap_id = ID;\ + trap_event.address = ADDR; \ + rt_trace_event(TRACE_RTAI_EV_TRAP_ENTRY, &trap_event);\ + } while(0) +/* + uint32_t eip; \ + __asm__ __volatile__("pushl %%ip; pop %0": "=g" (eip)); \ + trap_event.address = eip;\ +*/ + +/* TRACE_RTAI_TRAP_EXIT */ +#define TRACE_RTAI_TRAP_EXIT() rt_trace_event(TRACE_RTAI_EV_TRAP_EXIT, NULL) + +/* TRACE_RTAI_SRQ_ENTRY */ +typedef struct _trace_rtai_srq_entry +{ + uint8_t srq_id; /* SRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_rtai_srq_entry; +#if CONFIG_X86 +#define TRACE_RTAI_SRQ_ENTRY(ID) \ + do \ + {\ + uint32_t eflags, xcs; \ + trace_rtai_srq_entry srq_entry;\ + srq_entry.srq_id = ID;\ + __asm__ __volatile__("pushfl; pop %0": "=g" (eflags)); \ + __asm__ __volatile__("pushl %%cs; pop %0": "=g" (xcs)); \ + srq_entry.kernel = !((VM_MASK & eflags) || (3 & xcs));\ + rt_trace_event(TRACE_RTAI_EV_SRQ_ENTRY, &srq_entry);\ + } while(0) +#endif +#if CONFIG_PPC +#define TRACE_RTAI_SRQ_ENTRY(ID, KERNEL) \ + do \ + {\ + trace_rtai_srq_entry srq_entry;\ + srq_entry.srq_id = ID;\ + srq_entry.kernel = KERNEL;\ + rt_trace_event(TRACE_RTAI_EV_SRQ_ENTRY, &srq_entry);\ + } while(0) +#endif + +/* TRACE_RTAI_SRQ_EXIT */ +#define TRACE_RTAI_SRQ_EXIT() rt_trace_event(TRACE_RTAI_EV_SRQ_EXIT, NULL) + +/* TRACE_RTAI_SWITCHTO_LINUX */ +typedef struct _trace_rtai_switchto_linux +{ + uint8_t cpu_id; /* The CPUID being switched to Linux */ +} LTT_PACKED_STRUCT trace_rtai_switchto_linux; +#define TRACE_RTAI_SWITCHTO_LINUX(ID) \ + do \ + {\ + trace_rtai_switchto_linux switch_event; \ + switch_event.cpu_id = (uint8_t) ID; \ + rt_trace_event(TRACE_RTAI_EV_SWITCHTO_LINUX, &switch_event); \ + } while(0) + +/* TRACE_RTAI_SWITCHTO_RT */ +typedef struct _trace_rtai_switchto_rt +{ + uint8_t cpu_id; /* The CPUID being switched to RT */ +} LTT_PACKED_STRUCT trace_rtai_switchto_rt; +#define TRACE_RTAI_SWITCHTO_RT(ID) \ + do \ + {\ + trace_rtai_switchto_rt switch_event; \ + switch_event.cpu_id = (uint8_t) ID; \ + rt_trace_event(TRACE_RTAI_EV_SWITCHTO_RT, &switch_event); \ + } while(0) + +/* TRACE_RTAI_SCHED_CHANGE */ +typedef struct _trace_rtai_sched_change +{ + uint32_t out; /* Outgoing process */ + uint32_t in; /* Incoming process */ + uint32_t out_state; /* Outgoing process' state */ +} LTT_PACKED_STRUCT trace_rtai_sched_change; +#define TRACE_RTAI_SCHED_CHANGE(OUT, IN, OUT_STATE) \ + do \ + {\ + trace_rtai_sched_change sched_event;\ + sched_event.out = (uint32_t) OUT;\ + sched_event.in = (uint32_t) IN;\ + sched_event.out_state = (uint32_t) OUT_STATE; \ + rt_trace_event(TRACE_RTAI_EV_SCHED_CHANGE, &sched_event);\ + } while(0) + +/* TRACE_RTAI_TASK */ +#define TRACE_RTAI_EV_TASK_INIT 1 /* Initialize task */ +#define TRACE_RTAI_EV_TASK_DELETE 2 /* Delete task */ +#define TRACE_RTAI_EV_TASK_SIG_HANDLER 3 /* Set signal handler */ +#define TRACE_RTAI_EV_TASK_YIELD 4 /* Yield CPU control */ +#define TRACE_RTAI_EV_TASK_SUSPEND 5 /* Suspend task */ +#define TRACE_RTAI_EV_TASK_RESUME 6 /* Resume task */ +#define TRACE_RTAI_EV_TASK_MAKE_PERIOD_RELATIVE 7 /* Make task periodic relative in nanoseconds */ +#define TRACE_RTAI_EV_TASK_MAKE_PERIOD 8 /* Make task periodic */ +#define TRACE_RTAI_EV_TASK_WAIT_PERIOD 9 /* Wait until the next period */ +#define TRACE_RTAI_EV_TASK_BUSY_SLEEP 10 /* Busy sleep */ +#define TRACE_RTAI_EV_TASK_SLEEP 11 /* Sleep */ +#define TRACE_RTAI_EV_TASK_SLEEP_UNTIL 12 /* Sleep until */ +typedef struct _trace_rtai_task +{ + uint8_t event_sub_id; /* Task event ID */ + uint32_t event_data1; /* Event data */ + uint64_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_task; +#define TRACE_RTAI_TASK(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_task task_event;\ + task_event.event_sub_id = (uint8_t) ID;\ + task_event.event_data1 = (uint32_t) DATA1; \ + task_event.event_data2 = (uint64_t) DATA2; \ + task_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_TASK, &task_event);\ + } while(0) + +/* TRACE_RTAI_TIMER */ +#define TRACE_RTAI_EV_TIMER_REQUEST 1 /* Request timer */ +#define TRACE_RTAI_EV_TIMER_FREE 2 /* Free timer */ +#define TRACE_RTAI_EV_TIMER_REQUEST_APIC 3 /* Request APIC timers */ +#define TRACE_RTAI_EV_TIMER_APIC_FREE 4 /* Free APIC timers */ +#define TRACE_RTAI_EV_TIMER_HANDLE_EXPIRY 5 /* Handle timer expiry */ +typedef struct _trace_rtai_timer +{ + uint8_t event_sub_id; /* Timer event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ +} LTT_PACKED_STRUCT trace_rtai_timer; +#define TRACE_RTAI_TIMER(ID, DATA1, DATA2) \ + do \ + {\ + trace_rtai_timer timer_event; \ + timer_event.event_sub_id = (uint8_t) ID; \ + timer_event.event_data1 = (uint32_t) DATA1; \ + timer_event.event_data2 = (uint32_t) DATA2; \ + rt_trace_event(TRACE_RTAI_EV_TIMER, &timer_event); \ + } while(0) + +/* TRACE_RTAI_SEM */ +#define TRACE_RTAI_EV_SEM_INIT 1 /* Initialize semaphore */ +#define TRACE_RTAI_EV_SEM_DELETE 2 /* Delete semaphore */ +#define TRACE_RTAI_EV_SEM_SIGNAL 3 /* Signal semaphore */ +#define TRACE_RTAI_EV_SEM_WAIT 4 /* Wait on semaphore */ +#define TRACE_RTAI_EV_SEM_WAIT_IF 5 /* Take semaphore if possible */ +#define TRACE_RTAI_EV_SEM_WAIT_UNTIL 6 /* Wait on semaphore until a certain time */ +typedef struct _trace_rtai_sem +{ + uint8_t event_sub_id; /* Semaphore event ID */ + uint32_t event_data1; /* Event data 1 */ + uint64_t event_data2; /* Event data 2 */ +} LTT_PACKED_STRUCT trace_rtai_sem; +#define TRACE_RTAI_SEM(ID, DATA1, DATA2) \ + do \ + {\ + trace_rtai_sem sem_event; \ + sem_event.event_sub_id = (uint8_t) ID; \ + sem_event.event_data1 = (uint32_t) DATA1; \ + sem_event.event_data2 = (uint64_t) DATA2; \ + rt_trace_event(TRACE_RTAI_EV_SEM, &sem_event); \ + } while(0) + +/* TRACE_RTAI_MSG */ +#define TRACE_RTAI_EV_MSG_SEND 1 /* Send a message */ +#define TRACE_RTAI_EV_MSG_SEND_IF 2 /* Send if possible */ +#define TRACE_RTAI_EV_MSG_SEND_UNTIL 3 /* Try sending until a certain time */ +#define TRACE_RTAI_EV_MSG_RECV 4 /* Receive a message */ +#define TRACE_RTAI_EV_MSG_RECV_IF 5 /* Receive if possible */ +#define TRACE_RTAI_EV_MSG_RECV_UNTIL 6 /* Try receiving until a certain time */ +typedef struct _trace_rtai_msg +{ + uint8_t event_sub_id; /* Message event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_msg; +#define TRACE_RTAI_MSG(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_msg msg_event; \ + msg_event.event_sub_id = (uint8_t) ID; \ + msg_event.event_data1 = (uint32_t) DATA1; \ + msg_event.event_data2 = (uint32_t) DATA2; \ + msg_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_MSG, &msg_event); \ + } while(0) + +/* TRACE_RTAI_RPC */ +#define TRACE_RTAI_EV_RPC_MAKE 1 /* Make a remote procedure call */ +#define TRACE_RTAI_EV_RPC_MAKE_IF 2 /* Make RPC if receiver is ready */ +#define TRACE_RTAI_EV_RPC_MAKE_UNTIL 3 /* Try making an RPC until a certain time */ +#define TRACE_RTAI_EV_RPC_RETURN 4 /* Send result of RPC back to caller */ +typedef struct _trace_rtai_rpc +{ + uint8_t event_sub_id; /* RPC event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_rpc; +#define TRACE_RTAI_RPC(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_rpc rpc_event; \ + rpc_event.event_sub_id = (uint8_t) ID; \ + rpc_event.event_data1 = (uint32_t) DATA1; \ + rpc_event.event_data2 = (uint32_t) DATA2; \ + rpc_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_RPC, &rpc_event); \ + } while(0) + +/* TRACE_RTAI_MBX */ +#define TRACE_RTAI_EV_MBX_INIT 1 /* Initialize Message BoX */ +#define TRACE_RTAI_EV_MBX_DELETE 2 /* Delete message box */ +#define TRACE_RTAI_EV_MBX_SEND 3 /* Send a message to a message box */ +#define TRACE_RTAI_EV_MBX_SEND_WP 4 /* Send as many bytes as possible */ +#define TRACE_RTAI_EV_MBX_SEND_IF 5 /* Send a message if possible */ +#define TRACE_RTAI_EV_MBX_SEND_UNTIL 6 /* Try sending until a certain time */ +#define TRACE_RTAI_EV_MBX_RECV 7 /* Receive a message */ +#define TRACE_RTAI_EV_MBX_RECV_WP 8 /* Receive as many bytes as possible */ +#define TRACE_RTAI_EV_MBX_RECV_IF 9 /* Receive a message if available */ +#define TRACE_RTAI_EV_MBX_RECV_UNTIL 10 /* Try receiving until a certain time */ +typedef struct _trace_rtai_mbx +{ + uint8_t event_sub_id; /* Message Box event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_mbx; +#define TRACE_RTAI_MBX(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_mbx mbx_event; \ + mbx_event.event_sub_id = (uint8_t) ID; \ + mbx_event.event_data1 = (uint32_t) DATA1; \ + mbx_event.event_data2 = (uint32_t) DATA2; \ + mbx_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_MBX, &mbx_event); \ + } while(0) + +/* TRACE_RTAI_FIFO */ +#define TRACE_RTAI_EV_FIFO_CREATE 1 /* Create FIFO */ +#define TRACE_RTAI_EV_FIFO_DESTROY 2 /* Destroy FIFO */ +#define TRACE_RTAI_EV_FIFO_RESET 3 /* Reset FIFO */ +#define TRACE_RTAI_EV_FIFO_RESIZE 4 /* Resize FIFO */ +#define TRACE_RTAI_EV_FIFO_PUT 5 /* Write data to FIFO */ +#define TRACE_RTAI_EV_FIFO_GET 6 /* Get data from FIFO */ +#define TRACE_RTAI_EV_FIFO_CREATE_HANDLER 7 /* Install FIFO handler */ +#define TRACE_RTAI_EV_FIFO_OPEN 8 /* Open FIFO */ +#define TRACE_RTAI_EV_FIFO_RELEASE 9 /* Release FIFO */ +#define TRACE_RTAI_EV_FIFO_READ 10 /* Read from FIFO */ +#define TRACE_RTAI_EV_FIFO_WRITE 11 /* Write to FIFO */ +#define TRACE_RTAI_EV_FIFO_READ_TIMED 12 /* Read with time limit */ +#define TRACE_RTAI_EV_FIFO_WRITE_TIMED 13 /* Write with time limit */ +#define TRACE_RTAI_EV_FIFO_READ_ALLATONCE 14 /* Read all the data from FIFO */ +#define TRACE_RTAI_EV_FIFO_LLSEEK 15 /* Seek position into FIFO */ +#define TRACE_RTAI_EV_FIFO_FASYNC 16 /* Asynchronous notification */ +#define TRACE_RTAI_EV_FIFO_IOCTL 17 /* IO control on FIFO */ +#define TRACE_RTAI_EV_FIFO_POLL 18 /* Poll FIFO */ +#define TRACE_RTAI_EV_FIFO_SUSPEND_TIMED 19 /* Suspend task for given period */ +#define TRACE_RTAI_EV_FIFO_SET_ASYNC_SIG 20 /* Set asynchrounous signal */ +#define TRACE_RTAI_EV_FIFO_SEM_INIT 21 /* Initialize semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_POST 22 /* Post semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_WAIT 23 /* Wait on semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_TRY_WAIT 24 /* Try waiting on semaphore */ +#define TRACE_RTAI_EV_FIFO_SEM_TIMED_WAIT 25 /* Wait on semaphore until a certain time */ +#define TRACE_RTAI_EV_FIFO_SEM_DESTROY 26 /* Destroy semaphore */ +typedef struct _trace_rtai_fifo +{ + uint8_t event_sub_id; /* FIFO event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ +} LTT_PACKED_STRUCT trace_rtai_fifo; +#define TRACE_RTAI_FIFO(ID, DATA1, DATA2) \ + do \ + {\ + trace_rtai_fifo fifo_event; \ + fifo_event.event_sub_id = (uint8_t) ID; \ + fifo_event.event_data1 = (uint32_t) DATA1; \ + fifo_event.event_data2 = (uint32_t) DATA2; \ + rt_trace_event(TRACE_RTAI_EV_FIFO, &fifo_event); \ + } while(0) + +/* TRACE_RTAI_SHM */ +#define TRACE_RTAI_EV_SHM_MALLOC 1 /* Allocate shared memory */ +#define TRACE_RTAI_EV_SHM_KMALLOC 2 /* Allocate shared memory in kernel space */ +#define TRACE_RTAI_EV_SHM_GET_SIZE 3 /* Get the size of the shared memory area */ +#define TRACE_RTAI_EV_SHM_FREE 4 /* Free shared memory */ +#define TRACE_RTAI_EV_SHM_KFREE 5 /* Free kernel space shared memory */ +typedef struct _trace_rtai_shm +{ + uint8_t event_sub_id; /* SHared Memory event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint32_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_shm; +#define TRACE_RTAI_SHM(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_shm shm_event; \ + shm_event.event_sub_id = (uint8_t) ID; \ + shm_event.event_data1 = (uint32_t) DATA1; \ + shm_event.event_data2 = (uint32_t) DATA2; \ + shm_event.event_data3 = (uint32_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_SHM, &shm_event); \ + } while(0) + +/* TRACE_RTAI_POSIX */ +#define TRACE_RTAI_EV_POSIX_MQ_OPEN 1 /* Open/create message queue */ +#define TRACE_RTAI_EV_POSIX_MQ_CLOSE 2 /* Close message queue */ +#define TRACE_RTAI_EV_POSIX_MQ_SEND 3 /* Send message to queue */ +#define TRACE_RTAI_EV_POSIX_MQ_RECV 4 /* Receive message from queue */ +#define TRACE_RTAI_EV_POSIX_MQ_GET_ATTR 5 /* Get message queue attributes */ +#define TRACE_RTAI_EV_POSIX_MQ_SET_ATTR 6 /* Set message queue attributes */ +#define TRACE_RTAI_EV_POSIX_MQ_NOTIFY 7 /* Register to be notified of message arrival */ +#define TRACE_RTAI_EV_POSIX_MQ_UNLINK 8 /* Destroy message queue */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_CREATE 9 /* Create RT task */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_EXIT 10 /* Terminate calling thread */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_SELF 11 /* Get thread ID */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_INIT 12 /* Initialize thread attribute */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_DESTROY 13 /* Destroy thread attribute */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_SETDETACHSTATE 14 /* Set detach state of thread */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_GETDETACHSTATE 15 /* Get detach state of thread */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_SETSCHEDPARAM 16 /* Set thread scheduling parameters */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_GETSCHEDPARAM 17 /* Get thread scheduling parameters */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_SETSCHEDPOLICY 18 /* Set thread scheduling policy */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_GETSCHEDPOLICY 19 /* Get thread scheduling policy */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_SETINHERITSCHED 20 /* Set thread scheduling inheritance */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_GETINHERITSCHED 21 /* Get thread scheduling inheritance */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_SETSCOPE 22 /* Set thread scheduling scope */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_ATTR_GETSCOPE 23 /* Get thread scheduling scope */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_SCHED_YIELD 24 /* Yield processor control */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_CLOCK_GETTIME 25 /* Get current clock count */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEX_INIT 26 /* Initialize mutex */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEX_DESTROY 27 /* Destroy mutex */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEXATTR_INIT 28 /* Initiatize mutex attribute */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEXATTR_DESTROY 29 /* Destroy mutex attribute */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEXATTR_SETKIND_NP 30 /* Set kind of attribute */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEXATTR_GETKIND_NP 31 /* Get kind of attribute */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_SETSCHEDPARAM 32 /* Set scheduling parameters */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_GETSCHEDPARAM 33 /* Get scheduling parameters */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEX_TRY_LOCK 34 /* Non-blocking mutex lock */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEX_LOCK 35 /* Blocking mutex lock */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_MUTEX_UNLOCK 36 /* Mutex unlock */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_COND_INIT 37 /* Initialize conditionnal variable */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_COND_DESTROY 38 /* Destroy cond. variable */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_CONDATTR_INIT 39 /* Initialize cond. attribute variable */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_CONDATTR_DESTROY 40 /* Destroy cond. attribute variable */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_COND_WAIT 41 /* Wait for cond. variable to be signaled */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_COND_TIMEDWAIT 42 /* Wait for a certain time */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_COND_SIGNAL 43 /* Signal a waiting thread */ +#define TRACE_RTAI_EV_POSIX_PTHREAD_COND_BROADCAST 44 /* Signal all waiting threads */ +typedef struct _trace_rtai_posix +{ + uint8_t event_sub_id; /* POSIX event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint32_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_posix; +#define TRACE_RTAI_POSIX(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_posix posix_event; \ + posix_event.event_sub_id = (uint8_t) ID; \ + posix_event.event_data1 = (uint32_t) DATA1; \ + posix_event.event_data2 = (uint32_t) DATA2; \ + posix_event.event_data3 = (uint32_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_POSIX, &posix_event); \ + } while(0) + +/* TRACE_RTAI_LXRT */ +#define TRACE_RTAI_EV_LXRT_RTAI_SYSCALL_ENTRY 1 /* Entry in LXRT syscall */ +#define TRACE_RTAI_EV_LXRT_RTAI_SYSCALL_EXIT 2 /* Exit from LXRT syscall */ +#define TRACE_RTAI_EV_LXRT_SCHED_CHANGE 3 /* Scheduling change */ +#define TRACE_RTAI_EV_LXRT_STEAL_TASK 4 /* Take task control from Linux */ +#define TRACE_RTAI_EV_LXRT_GIVE_BACK_TASK 5 /* Give task control back to Linux */ +#define TRACE_RTAI_EV_LXRT_SUSPEND 6 /* Suspend a task */ +#define TRACE_RTAI_EV_LXRT_RESUME 7 /* Resume task's execution */ +#define TRACE_RTAI_EV_LXRT_HANDLE 8 /* Handle a request for an RTAI service */ +typedef struct _trace_rtai_lxrt +{ + uint8_t event_sub_id; /* LXRT event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint32_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_lxrt; +#define TRACE_RTAI_LXRT(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_lxrt lxrt_event; \ + lxrt_event.event_sub_id = (uint8_t) ID; \ + lxrt_event.event_data1 = (uint32_t) DATA1; \ + lxrt_event.event_data2 = (uint32_t) DATA2; \ + lxrt_event.event_data3 = (uint32_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_LXRT, &lxrt_event); \ + } while(0) + +/* TRACE_RTAI_LXRTI */ +#define TRACE_RTAI_EV_LXRTI_NAME_ATTACH 1 /* Register current process as name */ +#define TRACE_RTAI_EV_LXRTI_NAME_LOCATE 2 /* Locate a given process usint it's name */ +#define TRACE_RTAI_EV_LXRTI_NAME_DETACH 3 /* Detach process from name */ +#define TRACE_RTAI_EV_LXRTI_SEND 4 /* Send message to PID */ +#define TRACE_RTAI_EV_LXRTI_RECV 5 /* Receive message */ +#define TRACE_RTAI_EV_LXRTI_CRECV 6 /* Non-blocking receive */ +#define TRACE_RTAI_EV_LXRTI_REPLY 7 /* Reply to message received */ +#define TRACE_RTAI_EV_LXRTI_PROXY_ATTACH 8 /* Attach proxy to process */ +#define TRACE_RTAI_EV_LXRTI_PROXY_DETACH 9 /* Detach proxy from process */ +#define TRACE_RTAI_EV_LXRTI_TRIGGER 10 /* Trigger proxy */ +typedef struct _trace_rtai_lxrti +{ + uint8_t event_sub_id; /* LXRT event ID */ + uint32_t event_data1; /* Event data 1 */ + uint32_t event_data2; /* Event data 2 */ + uint64_t event_data3; /* Event data 3 */ +} LTT_PACKED_STRUCT trace_rtai_lxrti; +#define TRACE_RTAI_LXRTI(ID, DATA1, DATA2, DATA3) \ + do \ + {\ + trace_rtai_lxrti lxrti_event; \ + lxrti_event.event_sub_id = (uint8_t) ID; \ + lxrti_event.event_data1 = (uint32_t) DATA1; \ + lxrti_event.event_data2 = (uint32_t) DATA2; \ + lxrti_event.event_data3 = (uint64_t) DATA3; \ + rt_trace_event(TRACE_RTAI_EV_LXRTI, &lxrti_event); \ + } while(0) + +#else /* RTAI is configured without tracing */ +#define RT_TRACE_EVENT(ID, DATA) +#define TRACE_RTAI_MOUNT() +#define TRACE_RTAI_UMOUNT() +#define TRACE_RTAI_GLOBAL_IRQ_ENTRY(ID) +#define TRACE_RTAI_GLOBAL_IRQ_EXIT() +#define TRACE_RTAI_OWN_IRQ_ENTRY(ID) +#define TRACE_RTAI_OWN_IRQ_EXIT() +#define TRACE_RTAI_TRAP_ENTRY(ID, ADDR) +#define TRACE_RTAI_TRAP_EXIT() +#define TRACE_RTAI_SRQ_ENTRY(a) +#define TRACE_RTAI_SRQ_EXIT() +#define TRACE_RTAI_SWITCHTO_LINUX(ID) +#define TRACE_RTAI_SWITCHTO_RT(ID) +#define TRACE_RTAI_SCHED_CHANGE(OUT, IN, OUT_STATE) +#define TRACE_RTAI_TASK(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_TIMER(ID, DATA1, DATA2) +#define TRACE_RTAI_SEM(ID, DATA1, DATA2) +#define TRACE_RTAI_MSG(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_RPC(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_MBX(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_FIFO(ID, DATA1, DATA2) +#define TRACE_RTAI_SHM(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_POSIX(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_LXRT(ID, DATA1, DATA2, DATA3) +#define TRACE_RTAI_LXRTI(ID, DATA1, DATA2, DATA3) +#endif + +#endif /* __RTAI_TRACE_H__ */ diff -urN linux-2.4.18/include/linux/sched.h linux-2.4.18-rtai-rthal5g/include/linux/sched.h --- linux-2.4.18/include/linux/sched.h 2001-12-21 12:42:03.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/linux/sched.h 2003-11-27 23:12:25.000000000 -0500 @@ -410,6 +410,8 @@ /* journalling filesystem info */ void *journal_info; + + void *this_rt_task[2]; }; /* @@ -501,6 +503,7 @@ blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + this_rt_task: {0,0}, \ } diff -urN linux-2.4.18/include/linux/trace.h linux-2.4.18-rtai-rthal5g/include/linux/trace.h --- linux-2.4.18/include/linux/trace.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/include/linux/trace.h 2003-11-27 23:12:25.000000000 -0500 @@ -0,0 +1,442 @@ +/* + * linux/include/linux/trace.h + * + * Copyright (C) 1999, Karim Yaghmour + * + * This contains the necessary definitions for tracing the + * the system. + */ + +#ifndef _LINUX_TRACE_H +#define _LINUX_TRACE_H + +#include +#include + +/* Is kernel tracing enabled */ +#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) + +#ifdef CONFIG_RTAI_TRACE +#include +#define RT_spin_lock_irqsave(lock,flags) ((flags)=rt_spin_lock_irqsave(lock)) +#define RT_spin_unlock_irqrestore(lock,flags) rt_spin_unlock_irqrestore(flags,lock) +#else +#define RT_spin_lock_irqsave(lock,flags) spin_lock_irqsave(lock,flags) +#define RT_spin_unlock_irqrestore(lock,flags) spin_unlock_irqrestore(lock,flags) +#endif + +/* Structure packing within the trace */ +#if LTT_UNPACKED_STRUCTS +#define LTT_PACKED_STRUCT +#else /* if LTT_UNPACKED_STRUCTS */ +#define LTT_PACKED_STRUCT __attribute__ ((packed)) +#endif /* if LTT_UNPACKED_STRUCTS */ + +/* The prototype of the tracer call (EventID, *EventStruct) */ +typedef int (*tracer_call) (uint8_t, void*); + +/* This structure contains all the information needed to be known + about the tracing module. */ +struct tracer +{ + /* The tracing routine itself */ + tracer_call trace; + + /* Fetch of eip origin of syscall */ + int fetch_syscall_eip_use_depth; /* Use the given depth */ + int fetch_syscall_eip_use_bounds; /* Find eip in bounds */ + int syscall_eip_depth; /* Call depth at which eip is fetched */ + void* syscall_lower_eip_bound; /* Lower eip bound */ + void* syscall_upper_eip_bound; /* Higher eip bound */ +}; + +/* Maximal size a custom event can have */ +#define CUSTOM_EVENT_MAX_SIZE 8192 + +/* String length limits for custom events creation */ +#define CUSTOM_EVENT_TYPE_STR_LEN 20 +#define CUSTOM_EVENT_DESC_STR_LEN 100 +#define CUSTOM_EVENT_FORM_STR_LEN 256 +#define CUSTOM_EVENT_FINAL_STR_LEN 200 + +/* Type of custom event formats */ +#define CUSTOM_EVENT_FORMAT_TYPE_NONE 0 +#define CUSTOM_EVENT_FORMAT_TYPE_STR 1 +#define CUSTOM_EVENT_FORMAT_TYPE_HEX 2 +#define CUSTOM_EVENT_FORMAT_TYPE_XML 3 +#define CUSTOM_EVENT_FORMAT_TYPE_IBM 4 + +/* The functions to the tracer management code */ +int register_tracer + (tracer_call /* The tracer function */); +int unregister_tracer + (tracer_call /* The tracer function */); +int trace_set_config + (tracer_call /* The tracer function */, + int /* Use depth to fetch eip */, + int /* Use bounds to fetch eip */, + int /* Detph to fetch eip */, + void* /* Lower bound eip address */, + void* /* Upper bound eip address */); +int trace_register_callback + (tracer_call /* The callback to add */, + uint8_t /* The event ID targeted */); +int trace_unregister_callback + (tracer_call /* The callback to remove */, + uint8_t /* The event ID targeted */); +int trace_get_config + (int* /* Use depth to fetch eip */, + int* /* Use bounds to fetch eip */, + int* /* Detph to fetch eip */, + void** /* Lower bound eip address */, + void** /* Upper bound eip address */); +int trace_create_event + (char* /* String describing event type */, + char* /* String to format standard event description */, + int /* Type of formatting used to log event data */, + char* /* Data specific to format */); +int trace_create_owned_event + (char* /* String describing event type */, + char* /* String to format standard event description */, + int /* Type of formatting used to log event data */, + char* /* Data specific to format */, + pid_t /* PID of event's owner */); +void trace_destroy_event + (int /* The event ID given by trace_create_event() */); +void trace_destroy_owners_events + (pid_t /* The PID of the process' who's events are to be deleted */); +void trace_reregister_custom_events + (void); +int trace_std_formatted_event + (int /* The event ID given by trace_create_event() */, + ... /* The parameters to be printed out in the event string */); +int trace_raw_event + (int /* The event ID given by trace_create_event() */, + int /* The size of the raw data */, + void* /* Pointer to the raw event data */); +int trace_event + (uint8_t /* Event ID (as defined in this header file) */, + void* /* Structure describing the event */); + +/* Generic macros */ +#define TRACE_EVENT(ID, DATA) trace_event(ID, DATA) + +/* Traced events */ +#define TRACE_EV_START 0 /* This is to mark the trace's start */ +#define TRACE_EV_SYSCALL_ENTRY 1 /* Entry in a given system call */ +#define TRACE_EV_SYSCALL_EXIT 2 /* Exit from a given system call */ +#define TRACE_EV_TRAP_ENTRY 3 /* Entry in a trap */ +#define TRACE_EV_TRAP_EXIT 4 /* Exit from a trap */ +#define TRACE_EV_IRQ_ENTRY 5 /* Entry in an irq */ +#define TRACE_EV_IRQ_EXIT 6 /* Exit from an irq */ +#define TRACE_EV_SCHEDCHANGE 7 /* Scheduling change */ +#define TRACE_EV_KERNEL_TIMER 8 /* The kernel timer routine has been called */ +#define TRACE_EV_SOFT_IRQ 9 /* Hit key part of soft-irq management */ +#define TRACE_EV_PROCESS 10 /* Hit key part of process management */ +#define TRACE_EV_FILE_SYSTEM 11 /* Hit key part of file system */ +#define TRACE_EV_TIMER 12 /* Hit key part of timer management */ +#define TRACE_EV_MEMORY 13 /* Hit key part of memory management */ +#define TRACE_EV_SOCKET 14 /* Hit key part of socket communication */ +#define TRACE_EV_IPC 15 /* Hit key part of System V IPC */ +#define TRACE_EV_NETWORK 16 /* Hit key part of network communication */ + +#define TRACE_EV_BUFFER_START 17 /* Mark the begining of a trace buffer */ +#define TRACE_EV_BUFFER_END 18 /* Mark the ending of a trace buffer */ +#define TRACE_EV_NEW_EVENT 19 /* New event type */ +#define TRACE_EV_CUSTOM 20 /* Custom event */ + +#define TRACE_EV_CHANGE_MASK 21 /* Change in event mask */ + +/* Number of traced events */ +#define TRACE_EV_MAX TRACE_EV_CHANGE_MASK + +/* Structures and macros for events */ +/* TRACE_SYSCALL_ENTRY */ +typedef struct _trace_syscall_entry +{ + uint8_t syscall_id; /* Syscall entry number in entry.S */ + uint32_t address; /* Address from which call was made */ +} LTT_PACKED_STRUCT trace_syscall_entry; + +/* TRACE_TRAP_ENTRY */ +#ifndef __s390__ +typedef struct _trace_trap_entry +{ + uint16_t trap_id; /* Trap number */ + uint32_t address; /* Address where trap occured */ +} LTT_PACKED_STRUCT trace_trap_entry; +#else +typedef uint64_t trapid_t; +typedef struct _trace_trap_entry +{ + trapid_t trap_id; /* Trap number */ + uint32_t address; /* Address where trap occured */ +} LTT_PACKED_STRUCT trace_trap_entry; +#endif +#define TRACE_TRAP_ENTRY(ID, EIP) \ + do \ + {\ + trace_trap_entry trap_event;\ + trap_event.trap_id = ID;\ + trap_event.address = EIP;\ + trace_event(TRACE_EV_TRAP_ENTRY, &trap_event);\ + } while(0) + +/* TRACE_TRAP_EXIT */ +#define TRACE_TRAP_EXIT() trace_event(TRACE_EV_TRAP_EXIT, NULL) + +/* TRACE_IRQ_ENTRY */ +typedef struct _trace_irq_entry +{ + uint8_t irq_id; /* IRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT trace_irq_entry; +#define TRACE_IRQ_ENTRY(ID, KERNEL) \ + do \ + {\ + trace_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + irq_entry.kernel = KERNEL;\ + trace_event(TRACE_EV_IRQ_ENTRY, &irq_entry);\ + } while(0) + +/* TRACE_IRQ_EXIT */ +#define TRACE_IRQ_EXIT() trace_event(TRACE_EV_IRQ_EXIT, NULL) + +/* TRACE_SCHEDCHANGE */ +typedef struct _trace_schedchange +{ + uint32_t out; /* Outgoing process */ + uint32_t in; /* Incoming process */ + uint32_t out_state; /* Outgoing process' state */ +} LTT_PACKED_STRUCT trace_schedchange; +#define TRACE_SCHEDCHANGE(OUT, IN) \ + do \ + {\ + trace_schedchange sched_event;\ + sched_event.out = OUT->pid;\ + sched_event.in = (uint32_t) IN;\ + sched_event.out_state = OUT->state; \ + trace_event(TRACE_EV_SCHEDCHANGE, &sched_event);\ + } while(0) + +/* TRACE_SOFT_IRQ */ +#define TRACE_EV_SOFT_IRQ_BOTTOM_HALF 1 /* Conventional bottom-half */ +#define TRACE_EV_SOFT_IRQ_SOFT_IRQ 2 /* Real soft-irq */ +#define TRACE_EV_SOFT_IRQ_TASKLET_ACTION 3 /* Tasklet action */ +#define TRACE_EV_SOFT_IRQ_TASKLET_HI_ACTION 4 /* Tasklet hi-action */ +typedef struct _trace_soft_irq +{ + uint8_t event_sub_id; /* Soft-irq event Id */ + uint32_t event_data; /* Data associated with event */ +} LTT_PACKED_STRUCT trace_soft_irq; +#define TRACE_SOFT_IRQ(ID, DATA) \ + do \ + {\ + trace_soft_irq soft_irq_event;\ + soft_irq_event.event_sub_id = ID;\ + soft_irq_event.event_data = DATA;\ + trace_event(TRACE_EV_SOFT_IRQ, &soft_irq_event);\ + } while(0) + +/* TRACE_PROCESS */ +#define TRACE_EV_PROCESS_KTHREAD 1 /* Creation of a kernel thread */ +#define TRACE_EV_PROCESS_FORK 2 /* A fork or clone occured */ +#define TRACE_EV_PROCESS_EXIT 3 /* An exit occured */ +#define TRACE_EV_PROCESS_WAIT 4 /* A wait occured */ +#define TRACE_EV_PROCESS_SIGNAL 5 /* A signal has been sent */ +#define TRACE_EV_PROCESS_WAKEUP 6 /* Wake up a process */ +typedef struct _trace_process +{ + uint8_t event_sub_id; /* Process event ID */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; +} LTT_PACKED_STRUCT trace_process; +#define TRACE_PROCESS(ID, DATA1, DATA2) \ + do \ + {\ + trace_process proc_event;\ + proc_event.event_sub_id = ID;\ + proc_event.event_data1 = DATA1;\ + proc_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_PROCESS, &proc_event);\ + } while(0) + +/* TRACE_FILE_SYSTEM */ +#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_START 1 /* Starting to wait for a data buffer */ +#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_END 2 /* End to wait for a data buffer */ +#define TRACE_EV_FILE_SYSTEM_EXEC 3 /* An exec occured */ +#define TRACE_EV_FILE_SYSTEM_OPEN 4 /* An open occured */ +#define TRACE_EV_FILE_SYSTEM_CLOSE 5 /* A close occured */ +#define TRACE_EV_FILE_SYSTEM_READ 6 /* A read occured */ +#define TRACE_EV_FILE_SYSTEM_WRITE 7 /* A write occured */ +#define TRACE_EV_FILE_SYSTEM_SEEK 8 /* A seek occured */ +#define TRACE_EV_FILE_SYSTEM_IOCTL 9 /* An ioctl occured */ +#define TRACE_EV_FILE_SYSTEM_SELECT 10 /* A select occured */ +#define TRACE_EV_FILE_SYSTEM_POLL 11 /* A poll occured */ +typedef struct _trace_file_system +{ + uint8_t event_sub_id; /* File system event ID */ + uint32_t event_data1; /* Event data */ + uint32_t event_data2; /* Event data 2 */ + char* file_name; /* Name of file operated on */ +} LTT_PACKED_STRUCT trace_file_system; +#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME) \ + do \ + {\ + trace_file_system fs_event;\ + fs_event.event_sub_id = ID;\ + fs_event.event_data1 = DATA1;\ + fs_event.event_data2 = DATA2;\ + fs_event.file_name = (char*)FILE_NAME;\ + trace_event(TRACE_EV_FILE_SYSTEM, &fs_event);\ + } while(0) + +/* TRACE_TIMER */ +#define TRACE_EV_TIMER_EXPIRED 1 /* Timer expired */ +#define TRACE_EV_TIMER_SETITIMER 2 /* Setting itimer occurred */ +#define TRACE_EV_TIMER_SETTIMEOUT 3 /* Setting sched timeout occurred */ +typedef struct _trace_timer +{ + uint8_t event_sub_id; /* Timer event ID */ + uint8_t event_sdata; /* Short data */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; +} LTT_PACKED_STRUCT trace_timer; +#define TRACE_TIMER(ID, SDATA, DATA1, DATA2) \ + do \ + {\ + trace_timer timer_event;\ + timer_event.event_sub_id = ID;\ + timer_event.event_sdata = SDATA;\ + timer_event.event_data1 = DATA1;\ + timer_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_TIMER, &timer_event);\ + } while(0) + +/* TRACE_MEMORY */ +#define TRACE_EV_MEMORY_PAGE_ALLOC 1 /* Allocating pages */ +#define TRACE_EV_MEMORY_PAGE_FREE 2 /* Freing pages */ +#define TRACE_EV_MEMORY_SWAP_IN 3 /* Swaping pages in */ +#define TRACE_EV_MEMORY_SWAP_OUT 4 /* Swaping pages out */ +#define TRACE_EV_MEMORY_PAGE_WAIT_START 5 /* Start to wait for page */ +#define TRACE_EV_MEMORY_PAGE_WAIT_END 6 /* End to wait for page */ +typedef struct _trace_memory +{ + uint8_t event_sub_id; /* Memory event ID */ + unsigned long event_data; /* Data associated with event */ +} LTT_PACKED_STRUCT trace_memory; +#define TRACE_MEMORY(ID, DATA) \ + do \ + {\ + trace_memory memory_event;\ + memory_event.event_sub_id = ID;\ + memory_event.event_data = DATA;\ + trace_event(TRACE_EV_MEMORY, &memory_event);\ + } while(0) + +/* TRACE_SOCKET */ +#define TRACE_EV_SOCKET_CALL 1 /* A socket call occured */ +#define TRACE_EV_SOCKET_CREATE 2 /* A socket has been created */ +#define TRACE_EV_SOCKET_SEND 3 /* Data was sent to a socket */ +#define TRACE_EV_SOCKET_RECEIVE 4 /* Data was read from a socket */ +typedef struct _trace_socket +{ + uint8_t event_sub_id; /* Socket event ID */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; /* Data associated with event */ +} LTT_PACKED_STRUCT trace_socket; +#define TRACE_SOCKET(ID, DATA1, DATA2) \ + do \ + {\ + trace_socket socket_event;\ + socket_event.event_sub_id = ID;\ + socket_event.event_data1 = DATA1;\ + socket_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_SOCKET, &socket_event);\ + } while(0) + +/* TRACE_IPC */ +#define TRACE_EV_IPC_CALL 1 /* A System V IPC call occured */ +#define TRACE_EV_IPC_MSG_CREATE 2 /* A message queue has been created */ +#define TRACE_EV_IPC_SEM_CREATE 3 /* A semaphore was created */ +#define TRACE_EV_IPC_SHM_CREATE 4 /* A shared memory segment has been created */ +typedef struct _trace_ipc +{ + uint8_t event_sub_id; /* IPC event ID */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; /* Data associated with event */ +} LTT_PACKED_STRUCT trace_ipc; +#define TRACE_IPC(ID, DATA1, DATA2) \ + do \ + {\ + trace_ipc ipc_event;\ + ipc_event.event_sub_id = ID;\ + ipc_event.event_data1 = DATA1;\ + ipc_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_IPC, &ipc_event);\ + } while(0) + +/* TRACE_NETWORK */ +#define TRACE_EV_NETWORK_PACKET_IN 1 /* A packet came in */ +#define TRACE_EV_NETWORK_PACKET_OUT 2 /* A packet was sent */ +typedef struct _trace_network +{ + uint8_t event_sub_id; /* Network event ID */ + uint32_t event_data; /* Event data */ +} LTT_PACKED_STRUCT trace_network; +#define TRACE_NETWORK(ID, DATA) \ + do \ + {\ + trace_network net_event;\ + net_event.event_sub_id = ID;\ + net_event.event_data = DATA;\ + trace_event(TRACE_EV_NETWORK, &net_event);\ + } while(0) + +/* Custom declared events */ +/* ***WARNING*** These structures should never be used as is, use the provided custom event creation + and logging functions. */ +typedef struct _trace_new_event +{ + /* Basics */ + uint32_t id; /* Custom event ID */ + char type[CUSTOM_EVENT_TYPE_STR_LEN]; /* Event type description */ + char desc[CUSTOM_EVENT_DESC_STR_LEN]; /* Detailed event description */ + + /* Custom formatting */ + uint32_t format_type; /* Type of formatting */ + char form[CUSTOM_EVENT_FORM_STR_LEN]; /* Data specific to format */ +} LTT_PACKED_STRUCT trace_new_event; +typedef struct _trace_custom +{ + uint32_t id; /* Event ID */ + uint32_t data_size; /* Size of data recorded by event */ + void* data; /* Data recorded by event */ +} LTT_PACKED_STRUCT trace_custom; + +/* TRACE_CHANGE_MASK */ +typedef uint64_t trace_event_mask; /* The event mask type */ +typedef struct _trace_change_mask +{ + trace_event_mask mask; /* Event mask */ +} LTT_PACKED_STRUCT trace_change_mask; + +#else /* Kernel is configured without tracing */ +#define TRACE_EVENT(ID, DATA) +#define TRACE_TRAP_ENTRY(ID, EIP) +#define TRACE_TRAP_EXIT() +#define TRACE_IRQ_ENTRY(ID, KERNEL) +#define TRACE_IRQ_EXIT() +#define TRACE_SCHEDCHANGE(OUT, IN) +#define TRACE_SOFT_IRQ(ID, DATA) +#define TRACE_PROCESS(ID, DATA1, DATA2) +#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME) +#define TRACE_TIMER(ID, SDATA, DATA1, DATA2) +#define TRACE_MEMORY(ID, DATA) +#define TRACE_SOCKET(ID, DATA1, DATA2) +#define TRACE_IPC(ID, DATA1, DATA2) +#define TRACE_NETWORK(ID, DATA) +#endif /* defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) */ + +#endif /* _LINUX_TRACE_H */ diff -urN linux-2.4.18/ipc/msg.c linux-2.4.18-rtai-rthal5g/ipc/msg.c --- linux-2.4.18/ipc/msg.c 2001-09-14 17:17:00.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/ipc/msg.c 2003-11-26 17:16:06.000000000 -0500 @@ -25,6 +25,8 @@ #include #include "util.h" +#include + /* sysctl: */ int msg_ctlmax = MSGMAX; int msg_ctlmnb = MSGMNB; @@ -326,6 +328,7 @@ msg_unlock(id); } up(&msg_ids.sem); + TRACE_IPC(TRACE_EV_IPC_MSG_CREATE, ret, msgflg); return ret; } diff -urN linux-2.4.18/ipc/sem.c linux-2.4.18-rtai-rthal5g/ipc/sem.c --- linux-2.4.18/ipc/sem.c 2001-09-30 15:26:42.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/ipc/sem.c 2003-11-26 17:16:48.000000000 -0500 @@ -65,6 +65,7 @@ #include #include "util.h" +#include #define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id)) #define sem_unlock(id) ipc_unlock(&sem_ids,id) @@ -181,6 +182,7 @@ } up(&sem_ids.sem); + TRACE_IPC(TRACE_EV_IPC_SEM_CREATE, err, semflg); return err; } diff -urN linux-2.4.18/ipc/shm.c linux-2.4.18-rtai-rthal5g/ipc/shm.c --- linux-2.4.18/ipc/shm.c 2001-12-21 12:42:04.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/ipc/shm.c 2003-11-26 17:17:42.000000000 -0500 @@ -24,6 +24,8 @@ #include #include +#include + #include "util.h" struct shmid_kernel /* private to the kernel */ @@ -252,6 +254,7 @@ shm_unlock(id); } up(&shm_ids.sem); + TRACE_IPC(TRACE_EV_IPC_SHM_CREATE, err, shmflg); return err; } diff -urN linux-2.4.18/kernel/exit.c linux-2.4.18-rtai-rthal5g/kernel/exit.c --- linux-2.4.18/kernel/exit.c 2002-02-25 14:38:13.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/exit.c 2003-11-26 17:20:38.000000000 -0500 @@ -16,6 +16,8 @@ #include #endif +#include + #include #include #include @@ -429,6 +431,71 @@ write_unlock_irq(&tasklist_lock); } +// +// PGGC added these lines to callback rtai when a task dies. +// A list of functions allows different rt_modules to be informed. +// +static struct t_callback { + void (*rtai_callback)(struct task_struct *tsk); + struct t_callback *next; + } *rtai_callback_list; + +extern int set_rtai_callback( void (*fun)(struct task_struct *tsk)); +extern void remove_rtai_callback( void (*fun)(struct task_struct *tsk)); + +void inform_rtai(void) +{ + struct t_callback *pt; + + pt = rtai_callback_list; + while (pt) { + (*(pt->rtai_callback))(current); + pt = pt->next; + } +//printk( "Task pid %d going down\n", current->pid); +} + +int set_rtai_callback( void (*pt)(struct task_struct *tsk)) +{ + struct t_callback *ptn; + + ptn = kmalloc(sizeof(struct t_callback), GFP_KERNEL); + if (!ptn) { + return -ENOMEM; + } + ptn->rtai_callback = pt; + ptn->next = rtai_callback_list ? rtai_callback_list : 0; + rtai_callback_list = ptn; + return 0; +} + +void remove_rtai_callback(void (*pt)(struct task_struct *tsk)) +{ + struct t_callback *pto, *ptoo, *ptd; + + pto = rtai_callback_list; + ptoo = 0; + while (pto) { + if (pto->rtai_callback == pt) { + if (!ptoo) { + rtai_callback_list = pto->next; + } else { + ptoo->next = pto->next; + } + ptd = pto; + pto = pto->next; + kfree(ptd); + } else { + ptoo = pto; + pto = pto->next; + } + } +//printk("rtai_callback_list %X\n", rtai_callback_list); +} +// +// +// + NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; @@ -446,8 +513,22 @@ #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif + +/* + * PGGC added these lines to callback rtai when a task dies. + * This assumes that a LXRT task should/will always set its + * scheduling police to SCHED_FIFO or SCHED_RR. + * We may want to enforce this in rt_task_init(...). + * (For the moment it is not so, thus let's inform LXRT anyhow (Paolo)) + */ + if(tsk->this_rt_task[0]) { + inform_rtai(); + } + __exit_mm(tsk); + TRACE_PROCESS(TRACE_EV_PROCESS_EXIT, 0, 0); + lock_kernel(); sem_exit(); __exit_files(tsk); @@ -504,6 +585,8 @@ if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL)) return -EINVAL; + TRACE_PROCESS(TRACE_EV_PROCESS_WAIT, pid, 0); + add_wait_queue(¤t->wait_chldexit,&wait); repeat: flag = 0; diff -urN linux-2.4.18/kernel/fork.c linux-2.4.18-rtai-rthal5g/kernel/fork.c --- linux-2.4.18/kernel/fork.c 2002-02-25 14:38:13.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/fork.c 2003-11-26 17:21:39.000000000 -0500 @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -220,7 +222,9 @@ atomic_set(&mm->mm_count, 1); init_rwsem(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; + lock_kernel(); mm->pgd = pgd_alloc(mm); + unlock_kernel(); mm->def_flags = 0; if (mm->pgd) return mm; @@ -252,7 +256,9 @@ inline void __mmdrop(struct mm_struct *mm) { if (mm == &init_mm) BUG(); + lock_kernel(); pgd_free(mm->pgd); + unlock_kernel(); destroy_context(mm); free_mm(mm); } @@ -732,6 +738,9 @@ if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); + /* Trace the event */ + TRACE_PROCESS(TRACE_EV_PROCESS_FORK, retval, 0); + wake_up_process(p); /* do this last */ ++total_forks; if (clone_flags & CLONE_VFORK) diff -urN linux-2.4.18/kernel/itimer.c linux-2.4.18-rtai-rthal5g/kernel/itimer.c --- linux-2.4.18/kernel/itimer.c 2000-06-29 13:07:36.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/kernel/itimer.c 2003-11-26 17:22:49.000000000 -0500 @@ -10,6 +10,8 @@ #include #include +#include + #include /* @@ -95,6 +97,8 @@ struct task_struct * p = (struct task_struct *) __data; unsigned long interval; + TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0); + send_sig(SIGALRM, p, 1); interval = p->it_real_incr; if (interval) { @@ -114,6 +118,7 @@ j = tvtojiffies(&value->it_value); if (ovalue && (k = do_getitimer(which, ovalue)) < 0) return k; + TRACE_TIMER(TRACE_EV_TIMER_SETITIMER, which, i, j); switch (which) { case ITIMER_REAL: del_timer_sync(¤t->real_timer); diff -urN linux-2.4.18/kernel/ksyms.c linux-2.4.18-rtai-rthal5g/kernel/ksyms.c --- linux-2.4.18/kernel/ksyms.c 2002-02-25 14:38:13.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/ksyms.c 2003-11-26 15:08:58.000000000 -0500 @@ -559,3 +559,44 @@ EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(pidhash); + +/* + * used to inform rtai a task is about to die. + */ +extern int set_rtai_callback( void (*fun)(struct task_struct *tsk)); +extern void remove_rtai_callback(void (*fun)(struct task_struct *tsk)); +extern NORET_TYPE void do_exit(long code); +EXPORT_SYMBOL(set_rtai_callback); +EXPORT_SYMBOL(remove_rtai_callback); +EXPORT_SYMBOL(do_exit); + +/* + * used to inform RTAI LXRT a task should deal with a Linux signal, and for rt_lxrt_fork() + */ +extern int (*rtai_signal_handler)(struct task_struct *lnxt, int sig); +EXPORT_SYMBOL(rtai_signal_handler); +extern int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size); +EXPORT_SYMBOL(do_fork); + +/* + * used to provide async io support (aio) to RTAI LXRT. + */ +extern ssize_t sys_read(unsigned int fd, char * buf, size_t count); +extern ssize_t sys_write(unsigned int fd, const char * buf, size_t count); +extern ssize_t sys_pread(unsigned int fd, char * buf, + size_t count, loff_t pos); +extern ssize_t sys_pwrite(unsigned int fd, const char * buf, + size_t count, loff_t pos); +extern long sys_fsync(unsigned int fd); +extern long sys_fdatasync(unsigned int fd); +extern long sys_open(const char * filename, int flags, int mode); +extern long sys_close(unsigned int fd); + +EXPORT_SYMBOL(sys_read); +EXPORT_SYMBOL(sys_write); +EXPORT_SYMBOL(sys_open); +//EXPORT_SYMBOL(sys_close); +EXPORT_SYMBOL(sys_pread); +EXPORT_SYMBOL(sys_pwrite); +EXPORT_SYMBOL(sys_fsync); +EXPORT_SYMBOL(sys_fdatasync); diff -urN linux-2.4.18/kernel/Makefile linux-2.4.18-rtai-rthal5g/kernel/Makefile --- linux-2.4.18/kernel/Makefile 2001-09-17 00:22:40.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/kernel/Makefile 2003-11-26 17:18:24.000000000 -0500 @@ -9,7 +9,7 @@ O_TARGET := kernel.o -export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o +export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o trace.o obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ @@ -20,6 +20,10 @@ obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +ifdef CONFIG_TRACE +obj-y += trace.o +endif + ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is # needed for x86 only. Why this used to be enabled for all architectures is beyond diff -urN linux-2.4.18/kernel/sched.c linux-2.4.18-rtai-rthal5g/kernel/sched.c --- linux-2.4.18/kernel/sched.c 2001-12-21 12:42:04.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/sched.c 2003-11-26 17:25:40.000000000 -0500 @@ -30,6 +30,8 @@ #include #include +#include + #include #include @@ -353,6 +355,8 @@ unsigned long flags; int success = 0; + TRACE_PROCESS(TRACE_EV_PROCESS_WAKEUP, p->pid, p->state); + /* * We want the common case fall through straight, thus the goto. */ @@ -378,6 +382,7 @@ { struct task_struct * p = (struct task_struct *) __data; + TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0); wake_up_process(p); } @@ -442,6 +447,8 @@ } } + TRACE_TIMER(TRACE_EV_TIMER_SETTIMEOUT, 0, timeout, 0); + expire = timeout + jiffies; init_timer(&timer); @@ -546,6 +553,75 @@ * tasks can run. It can not be killed, and it cannot sleep. The 'state' * information in task[0] is never used. */ + +int idle_weight = -1000; +#define MAX_MM 4096 // How large should it be? +static struct smm_t { int in, out; struct mm_struct *mm[MAX_MM]; } smm[NR_CPUS]; +#define incpnd(x) do { x = (x + 1) & (MAX_MM - 1); } while(0) + +#ifdef CONFIG_X86 +static inline void pend_mm(struct mm_struct *mm, int cpu) +{ + if (rthal.lxrt_global_cli) { + struct smm_t *p = smm + cpu; + p->mm[p->in] = mm; + incpnd(p->in); + } else { + mmdrop(mm); + } +} + +static inline void drop_mm(void) +{ + if (rthal.lxrt_global_cli) { + struct smm_t *p = smm + smp_processor_id(); + while (p->out != p->in) { + mmdrop(p->mm[p->out]); + incpnd(p->out); + } + } +} + +void switch_mem(struct task_struct *prevp, struct task_struct *nextp, int cpuid) +{ + if (cpuid < 0) { + struct mm_struct *next = nextp->active_mm; + if (prevp->active_mm != next || (cpuid & 0x40000000)) { + if ((prevp->active_mm)->context.segments != next->context.segments) { + load_LDT(next); + } + set_bit(cpuid & 0xFFFFFFF, &next->context.cpuvalid); + asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd))); + } +#ifdef CONFIG_SMP + else if (!test_and_set_bit(cpuid & 0xFFFFFFF, &next->context.cpuvalid)) { + load_LDT(next); + } +#endif + } else { + struct mm_struct *oldmm = prevp->active_mm; + if (nextp->mm) { + switch_mm(oldmm, nextp->mm, nextp, cpuid); + } else { + nextp->active_mm = oldmm; + atomic_inc(&oldmm->mm_count); + enter_lazy_tlb(oldmm, nextp, cpuid); + } + if (!prevp->mm) { + prevp->active_mm = NULL; + pend_mm(oldmm, cpuid); + } + } +} +#else +static inline void pend_mm(struct mm_struct *mm, int cpu) +{ + mmdrop(mm); +} +static inline void drop_mm(void) {} +void switch_mem(struct task_struct *prevp, struct task_struct *nextp, int cpuid) {} +#endif + asmlinkage void schedule(void) { struct schedule_data * sched_data; @@ -604,7 +680,7 @@ * Default process to select.. */ next = idle_task(this_cpu); - c = -1000; + c = idle_weight; list_for_each(tmp, &runqueue_head) { p = list_entry(tmp, struct task_struct, run_list); if (can_schedule(p, this_cpu)) { @@ -686,15 +762,18 @@ if (!prev->mm) { prev->active_mm = NULL; - mmdrop(oldmm); + pend_mm(oldmm, this_cpu); } } + TRACE_SCHEDCHANGE(prev, next); + /* * This just switches the register state and the * stack. */ switch_to(prev, next, prev); + drop_mm(); __schedule_tail(prev); same_process: diff -urN linux-2.4.18/kernel/signal.c linux-2.4.18-rtai-rthal5g/kernel/signal.c --- linux-2.4.18/kernel/signal.c 2001-11-21 19:26:27.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/signal.c 2003-11-26 17:26:23.000000000 -0500 @@ -14,6 +14,8 @@ #include #include +#include + #include /* @@ -541,6 +543,8 @@ if (sig < SIGRTMIN && sigismember(&t->pending.signal, sig)) goto out; + TRACE_PROCESS(TRACE_EV_PROCESS_SIGNAL, sig, t->pid); + ret = deliver_signal(sig, info, t); out: spin_unlock_irqrestore(&t->sigmask_lock, flags); @@ -974,9 +978,30 @@ return ret; } +// +// Add this pointer to the RTAI signal handler. +// +int (*rtai_signal_handler)(struct task_struct *lnxt, int sig); + asmlinkage long sys_kill(int pid, int sig) { +// Add this section to call the RTAI signal handler. +// + { + struct task_struct *p; + int ret; + + if (rtai_signal_handler) { + p = find_task_by_pid(pid); + if(p && (p->policy == SCHED_FIFO || p->policy == SCHED_RR) && p->this_rt_task[0]) { + ret = rtai_signal_handler(p, sig); + if(!ret) return 0; //let Linux deal with it. + } + } + } + + { struct siginfo info; info.si_signo = sig; @@ -986,6 +1011,7 @@ info.si_uid = current->uid; return kill_something_info(sig, &info, pid); + } } asmlinkage long diff -urN linux-2.4.18/kernel/softirq.c linux-2.4.18-rtai-rthal5g/kernel/softirq.c --- linux-2.4.18/kernel/softirq.c 2001-10-31 13:26:02.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/softirq.c 2003-11-26 17:29:55.000000000 -0500 @@ -17,6 +17,8 @@ #include #include +#include + /* - No shared variables, all the data are CPU local. - If a softirq needs serialization, let it serialize itself @@ -86,8 +88,10 @@ h = softirq_vec; do { - if (pending & 1) + if (pending & 1) { + TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_SOFT_IRQ, (h - softirq_vec)); h->action(h); + } h++; pending >>= 1; } while (pending); @@ -192,6 +196,9 @@ if (!atomic_read(&t->count)) { if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG(); + + TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_TASKLET_ACTION, (unsigned long) (t->func)); + t->func(t->data); tasklet_unlock(t); continue; @@ -226,6 +233,9 @@ if (!atomic_read(&t->count)) { if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG(); + + TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_TASKLET_HI_ACTION, (unsigned long) (t->func)); + t->func(t->data); tasklet_unlock(t); continue; @@ -296,8 +306,10 @@ if (!hardirq_trylock(cpu)) goto resched_unlock; - if (bh_base[nr]) + if (bh_base[nr]){ + TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_BOTTOM_HALF, (nr)); bh_base[nr](); + } hardirq_endlock(cpu); spin_unlock(&global_bh_lock); diff -urN linux-2.4.18/kernel/time.c linux-2.4.18-rtai-rthal5g/kernel/time.c --- linux-2.4.18/kernel/time.c 2002-02-25 14:38:13.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/time.c 2003-11-26 17:33:07.000000000 -0500 @@ -28,6 +28,8 @@ #include #include +#include + #include /* @@ -38,7 +40,11 @@ /* The xtime_lock is not only serializing the xtime read/writes but it's also serializing all accesses to the global NTP variables now. */ +#if !CONFIG_RTAI_TRACE extern rwlock_t xtime_lock; +#else +extern spinlock_t xtime_lock; +#endif #if !defined(__alpha__) && !defined(__ia64__) @@ -74,19 +80,30 @@ asmlinkage long sys_stime(int * tptr) { int value; +#if CONFIG_RTAI_TRACE + unsigned long flags; +#endif if (!capable(CAP_SYS_TIME)) return -EPERM; if (get_user(value, tptr)) return -EFAULT; +#if !CONFIG_RTAI_TRACE write_lock_irq(&xtime_lock); +#else + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif xtime.tv_sec = value; xtime.tv_usec = 0; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; +#if !CONFIG_RTAI_TRACE write_unlock_irq(&xtime_lock); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif return 0; } @@ -125,9 +142,18 @@ */ inline static void warp_clock(void) { +#if !CONFIG_RTAI_TRACE write_lock_irq(&xtime_lock); +#else + unsigned long flags; + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif xtime.tv_sec += sys_tz.tz_minuteswest * 60; +#if !CONFIG_RTAI_TRACE write_unlock_irq(&xtime_lock); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif } /* @@ -209,6 +235,9 @@ { long ltemp, mtemp, save_adjust; int result; +#if CONFIG_RTAI_TRACE + unsigned long flags; +#endif /* In order to modify anything, you gotta be super-user! */ if (txc->modes && !capable(CAP_SYS_TIME)) @@ -226,7 +255,11 @@ if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) return -EINVAL; +#if !CONFIG_RTAI_TRACE write_lock_irq(&xtime_lock); +#else + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif result = time_state; /* mostly `TIME_OK' */ /* Save for later - semantics of adjtime is to return old value */ @@ -381,7 +414,11 @@ txc->calcnt = pps_calcnt; txc->errcnt = pps_errcnt; txc->stbcnt = pps_stbcnt; +#if !CONFIG_RTAI_TRACE write_unlock_irq(&xtime_lock); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif do_gettimeofday(&txc->time); return(result); } diff -urN linux-2.4.18/kernel/timer.c linux-2.4.18-rtai-rthal5g/kernel/timer.c --- linux-2.4.18/kernel/timer.c 2001-10-08 13:41:41.000000000 -0400 +++ linux-2.4.18-rtai-rthal5g/kernel/timer.c 2003-11-26 17:34:30.000000000 -0500 @@ -23,6 +23,8 @@ #include #include +#include + #include /* @@ -643,30 +645,46 @@ /* * This spinlock protect us from races in SMP while playing with xtime. -arca */ +#if !CONFIG_RTAI_TRACE rwlock_t xtime_lock = RW_LOCK_UNLOCKED; +#else +spinlock_t xtime_lock = SPIN_LOCK_UNLOCKED; +#endif static inline void update_times(void) { unsigned long ticks; +#if CONFIG_RTAI_TRACE + unsigned long flags; +#endif /* * update_times() is run from the raw timer_bh handler so we * just know that the irqs are locally enabled and so we don't * need to save/restore the flags of the local CPU here. -arca */ +#if !CONFIG_RTAI_TRACE write_lock_irq(&xtime_lock); +#else + RT_spin_lock_irqsave(&xtime_lock, flags); +#endif ticks = jiffies - wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); } +#if !CONFIG_RTAI_TRACE write_unlock_irq(&xtime_lock); +#else + RT_spin_unlock_irqrestore(&xtime_lock, flags); +#endif calc_load(ticks); } void timer_bh(void) { + TRACE_EVENT(TRACE_EV_KERNEL_TIMER, NULL); update_times(); run_timer_list(); } diff -urN linux-2.4.18/kernel/trace.c linux-2.4.18-rtai-rthal5g/kernel/trace.c --- linux-2.4.18/kernel/trace.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/kernel/trace.c 2002-04-18 14:32:43.000000000 -0400 @@ -0,0 +1,692 @@ +/* + * linux/kernel/trace.c + * + * (C) Copyright 1999, 2000, 2001, 2002 - Karim Yaghmour (karym@opersys.com) + * + * This code is distributed under the GPL license + * + * Tracing management + * + */ + +#include /* For __init */ +#include /* Tracing definitions */ +#include /* Miscellaneous error codes */ +#include /* NULL */ +#include /* kmalloc() */ +#include /* EXPORT_SYMBOL */ +#include /* pid_t */ + +/* Local variables */ +static int tracer_registered = 0; /* Is there a tracer registered */ +struct tracer * tracer = NULL; /* The registered tracer */ + +/* Registration lock */ +rwlock_t tracer_register_lock = RW_LOCK_UNLOCKED; + +/* Trace callback table entry */ +struct trace_callback_table_entry +{ + tracer_call callback; /* The callback function */ + + struct trace_callback_table_entry* next; /* Next entry */ +}; + +/* Trace callback table */ +struct trace_callback_table_entry trace_callback_table[TRACE_EV_MAX]; + +/* Custom event description */ +struct custom_event_desc +{ + /* The event itself */ + trace_new_event event; + + /* PID of event owner, if any */ + pid_t owner_pid; + + /* List links */ + struct custom_event_desc* next; + struct custom_event_desc* prev; +}; + +/* Next event ID to be used */ +int next_event_id; + +/* Circular list of custom events */ +struct custom_event_desc custom_events_head; +struct custom_event_desc* custom_events; + +/* Circular list lock */ +rwlock_t custom_list_lock = RW_LOCK_UNLOCKED; + +/**************************************************** + * Register the tracer to the kernel + * Return values : + * 0, all is OK + * -EBUSY, there already is a registered tracer + * -ENOMEM, couldn't allocate memory + ****************************************************/ +int register_tracer(tracer_call pm_trace_function) +{ + unsigned long l_flags; /* Flags for irqsave */ + + /* Is there a tracer already registered */ + if(tracer_registered == 1) + return -EBUSY; + + /* Allocate memory for the tracer */ + if((tracer = (struct tracer *) kmalloc(sizeof(struct tracer), GFP_ATOMIC)) == NULL) + /* We couldn't allocate any memory */ + return -ENOMEM; + + /* Lock registration variables */ + write_lock_irqsave(&tracer_register_lock, l_flags); + + /* There is a tracer registered */ + tracer_registered = 1; + + /* Set the tracer to the one being passed by the caller */ + tracer->trace = pm_trace_function; + + /* Unlock registration variables */ + write_unlock_irqrestore(&tracer_register_lock, l_flags); + + /* Initialize the tracer settings */ + tracer->fetch_syscall_eip_use_bounds = 0; + tracer->fetch_syscall_eip_use_depth = 0; + + /* Tell the caller that everything went fine */ + return 0; +} + +/*************************************************** + * Unregister the currently registered tracer + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -ENXIO, unregestering wrong tracer + ***************************************************/ +int unregister_tracer(tracer_call pm_trace_function) +{ + unsigned long l_flags; /* Flags for irqsave */ + + /* Is there a tracer already registered */ + if(tracer_registered == 0) + /* Nothing to unregister */ + return -ENOMEDIUM; + + /* Lock registration variables */ + write_lock_irqsave(&tracer_register_lock, l_flags); + + /* Is it the tracer that was registered */ + if(tracer->trace == pm_trace_function) + /* There isn't any tracer in here */ + tracer_registered = 0; + else + { + /* Unlock registration variables */ + write_unlock_irqrestore(&tracer_register_lock, l_flags); + + /* We're done here */ + return -ENXIO; + } + + /* Free the memory used by the tracing structure */ + kfree(tracer); + tracer = NULL; + + /* Unlock registration variables */ + write_unlock_irqrestore(&tracer_register_lock, l_flags); + + /* Tell the caller that everything went OK */ + return 0; +} + +/******************************************************* + * Set the tracing configuration + * Parameters : + * pm_trace_function, the trace function. + * pm_fetch_syscall_use_depth, Use depth to fetch eip + * pm_fetch_syscall_use_bounds, Use bounds to fetch eip + * pm_syscall_eip_depth, Detph to fetch eip + * pm_syscall_lower_bound, Lower bound eip address + * pm_syscall_upper_bound, Upper bound eip address + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -ENXIO, wrong tracer + * -EINVAL, invalid configuration + *******************************************************/ +int trace_set_config(tracer_call pm_trace_function, + int pm_fetch_syscall_use_depth, + int pm_fetch_syscall_use_bounds, + int pm_syscall_eip_depth, + void* pm_syscall_lower_bound, + void* pm_syscall_upper_bound) +{ + /* Is there a tracer already registered */ + if(tracer_registered == 0) + return -ENOMEDIUM; + + /* Is it the tracer that was registered */ + if(tracer->trace != pm_trace_function) + return -ENXIO; + + /* Is this a valid configuration */ + if((pm_fetch_syscall_use_depth && pm_fetch_syscall_use_bounds) + ||(pm_syscall_lower_bound > pm_syscall_upper_bound) + ||(pm_syscall_eip_depth < 0)) + return -EINVAL; + + /* Set the configuration */ + tracer->fetch_syscall_eip_use_depth = pm_fetch_syscall_use_depth; + tracer->fetch_syscall_eip_use_bounds = pm_fetch_syscall_use_bounds; + tracer->syscall_eip_depth = pm_syscall_eip_depth; + tracer->syscall_lower_eip_bound = pm_syscall_lower_bound; + tracer->syscall_upper_eip_bound = pm_syscall_upper_bound; + + /* Tell the caller that everything was OK */ + return 0; +} + +/******************************************************* + * Get the tracing configuration + * Parameters : + * pm_fetch_syscall_use_depth, Use depth to fetch eip + * pm_fetch_syscall_use_bounds, Use bounds to fetch eip + * pm_syscall_eip_depth, Detph to fetch eip + * pm_syscall_lower_bound, Lower bound eip address + * pm_syscall_upper_bound, Upper bound eip address + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + *******************************************************/ +int trace_get_config(int* pm_fetch_syscall_use_depth, + int* pm_fetch_syscall_use_bounds, + int* pm_syscall_eip_depth, + void** pm_syscall_lower_bound, + void** pm_syscall_upper_bound) +{ + /* Is there a tracer already registered */ + if(tracer_registered == 0) + return -ENOMEDIUM; + + /* Get the configuration */ + *pm_fetch_syscall_use_depth = tracer->fetch_syscall_eip_use_depth; + *pm_fetch_syscall_use_bounds = tracer->fetch_syscall_eip_use_bounds; + *pm_syscall_eip_depth = tracer->syscall_eip_depth; + *pm_syscall_lower_bound = tracer->syscall_lower_eip_bound; + *pm_syscall_upper_bound = tracer->syscall_upper_eip_bound; + + /* Tell the caller that everything was OK */ + return 0; +} + +/******************************************************* + * Register a callback function to be called on occurence + * of given event + * Parameters : + * pm_trace_function, the callback function. + * pm_event_id, the event ID to be monitored. + * Return values : + * 0, all is OK + * -ENOMEM, unable to allocate memory for callback + *******************************************************/ +int trace_register_callback(tracer_call pm_trace_function, + uint8_t pm_event_id) +{ + struct trace_callback_table_entry* p_tct_entry; + + /* Search for an empty entry in the callback table */ + for(p_tct_entry = &(trace_callback_table[pm_event_id - 1]); + p_tct_entry->next != NULL; + p_tct_entry = p_tct_entry->next); + + /* Allocate a new callback */ + if((p_tct_entry->next = kmalloc(sizeof(struct trace_callback_table_entry), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + /* Setup the new callback */ + p_tct_entry->next->callback = pm_trace_function; + p_tct_entry->next->next = NULL; + + /* Tell the caller everything is ok */ + return 0; +} + +/******************************************************* + * UnRegister a callback function. + * Parameters : + * pm_trace_function, the callback function. + * pm_event_id, the event ID that had to be monitored. + * Return values : + * 0, all is OK + * -ENOMEDIUM, no such callback resigtered + *******************************************************/ +int trace_unregister_callback(tracer_call pm_trace_function, + uint8_t pm_event_id) +{ + struct trace_callback_table_entry* p_tct_entry; /* Pointer to trace callback table entry */ + struct trace_callback_table_entry* p_temp_entry; /* Pointer to trace callback table entry */ + + /* Search for the callback in the callback table */ + for(p_tct_entry = &(trace_callback_table[pm_event_id - 1]); + ((p_tct_entry->next != NULL) && (p_tct_entry->next->callback != pm_trace_function)); + p_tct_entry = p_tct_entry->next); + + /* Did we find anything */ + if(p_tct_entry == NULL) + return -ENOMEDIUM; + + /* Free the callback entry */ + p_temp_entry = p_tct_entry->next->next; + kfree(p_tct_entry->next); + p_tct_entry->next = p_temp_entry; + + /* Tell the caller everything is ok */ + return 0; +} + +/******************************************************* + * Create a new traceable event type + * Parameters : + * pm_event_type, string describing event type + * pm_event_desc, string used for standard formatting + * pm_format_type, type of formatting used to log event + * data + * pm_format_data, data specific to format + * pm_owner_pid, PID of event's owner (0 if none) + * Return values : + * New Event ID if all is OK + * -ENOMEM, Unable to allocate new event + *******************************************************/ +int _trace_create_event(char* pm_event_type, + char* pm_event_desc, + int pm_format_type, + char* pm_format_data, + pid_t pm_owner_pid) +{ + struct custom_event_desc* p_new_event; /* Newly created event */ + + /* Create event */ + if((p_new_event = (struct custom_event_desc*) kmalloc(sizeof(struct custom_event_desc), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + /* Initialize event properties */ + p_new_event->event.type[0] = '\0'; + p_new_event->event.desc[0] = '\0'; + p_new_event->event.form[0] = '\0'; + + /* Set basic event properties */ + if(pm_event_type != NULL) + strncpy(p_new_event->event.type, pm_event_type, CUSTOM_EVENT_TYPE_STR_LEN); + if(pm_event_desc != NULL) + strncpy(p_new_event->event.desc, pm_event_desc, CUSTOM_EVENT_DESC_STR_LEN); + if(pm_format_data != NULL) + strncpy(p_new_event->event.form, pm_format_data, CUSTOM_EVENT_FORM_STR_LEN); + + /* Ensure that strings are bound */ + p_new_event->event.type[CUSTOM_EVENT_TYPE_STR_LEN - 1] = '\0'; + p_new_event->event.desc[CUSTOM_EVENT_DESC_STR_LEN - 1] = '\0'; + p_new_event->event.form[CUSTOM_EVENT_FORM_STR_LEN - 1] = '\0'; + + /* Set format type */ + p_new_event->event.format_type = pm_format_type; + + /* Give the new event a unique event ID */ + p_new_event->event.id = next_event_id; + next_event_id++; + + /* Set event's owner */ + p_new_event->owner_pid = pm_owner_pid; + + /* Insert new event in event list */ + write_lock(&custom_list_lock); + p_new_event->next = custom_events; + p_new_event->prev = custom_events->prev; + custom_events->prev->next = p_new_event; + custom_events->prev = p_new_event; + write_unlock(&custom_list_lock); + + /* Log the event creation event */ + trace_event(TRACE_EV_NEW_EVENT, &(p_new_event->event)); + + /* Return new event ID */ + return p_new_event->event.id; +} +int trace_create_event(char* pm_event_type, + char* pm_event_desc, + int pm_format_type, + char* pm_format_data) +{ + return _trace_create_event(pm_event_type, pm_event_desc, pm_format_type, pm_format_data, 0); +} +int trace_create_owned_event(char* pm_event_type, + char* pm_event_desc, + int pm_format_type, + char* pm_format_data, + pid_t pm_owner_pid) +{ + return _trace_create_event(pm_event_type, pm_event_desc, pm_format_type, pm_format_data, pm_owner_pid); +} + +/******************************************************* + * Destroy a created event type + * Parameters : + * pm_event_id, the Id returned by trace_create_event() + * Return values : + * NONE + *******************************************************/ +void trace_destroy_event(int pm_event_id) +{ + struct custom_event_desc* p_event_desc; /* Generic event description pointer */ + + /* Lock the table for writting */ + write_lock(&custom_list_lock); + + /* Go through the event description list */ + for(p_event_desc = custom_events->next; + p_event_desc != custom_events; + p_event_desc = p_event_desc->next) + if(p_event_desc->event.id == pm_event_id) + break; + + /* If we found something */ + if(p_event_desc != custom_events) + { + /* Remove the event fromt the list */ + p_event_desc->next->prev = p_event_desc->prev; + p_event_desc->prev->next = p_event_desc->next; + + /* Free the memory used by this event */ + kfree(p_event_desc); + } + + /* Unlock the table for writting */ + write_unlock(&custom_list_lock); +} + +/******************************************************* + * Destroy an owner's events + * Parameters : + * pm_owner_pid, the PID of the owner who's events are to + * be deleted. + * Return values : + * NONE + *******************************************************/ +void trace_destroy_owners_events(pid_t pm_owner_pid) +{ + struct custom_event_desc* p_temp_event; /* Temporary event */ + struct custom_event_desc* p_event_desc; /* Generic event description pointer */ + + /* Lock the table for writting */ + write_lock(&custom_list_lock); + + /* Start at the first event in the list */ + p_event_desc = custom_events->next; + + /* Go through the event description list */ + while(p_event_desc != custom_events) + { + /* Keep pointer to next event */ + p_temp_event = p_event_desc->next; + + /* Does this event belong to the same owner */ + if(p_event_desc->owner_pid == pm_owner_pid) + { + /* Remove the event fromt the list */ + p_event_desc->next->prev = p_event_desc->prev; + p_event_desc->prev->next = p_event_desc->next; + + /* Free the memory used by this event */ + kfree(p_event_desc); + } + + /* Go to next event */ + p_event_desc = p_temp_event; + } + + /* Unlock the table for writting */ + write_unlock(&custom_list_lock); +} + +/******************************************************* + * Relog the declarations of custom events. This is + * necessary to make sure that even though the event + * creation might not have taken place during a trace, + * that all custom events be part of all traces. Hence, + * if a custom event occurs during a trace, we can be + * sure that it's definition is part of the trace. + * Parameters : + * NONE + * Return values : + * NONE + *******************************************************/ +void trace_reregister_custom_events(void) +{ + struct custom_event_desc* p_event_desc; /* Generic event description pointer */ + + /* Lock the table for reading */ + read_lock(&custom_list_lock); + + /* Go through the event description list */ + for(p_event_desc = custom_events->next; + p_event_desc != custom_events; + p_event_desc = p_event_desc->next) + /* Log the event creation event */ + trace_event(TRACE_EV_NEW_EVENT, &(p_event_desc->event)); + + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); +} + +/******************************************************* + * Trace a formatted event + * Parameters : + * pm_event_id, the event Id provided upon creation + * ..., printf-like data that will be used to fill the + * event string. + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer or this + * event doesn't exist. + * -EBUSY, tracing hasn't started yet + *******************************************************/ +int trace_std_formatted_event(int pm_event_id, ...) +{ + int l_string_size; /* Size of the string outputed by vsprintf() */ + char l_string[CUSTOM_EVENT_FINAL_STR_LEN]; /* Final formatted string */ + va_list l_var_arg_list; /* Variable argument list */ + trace_custom l_custom; /* Custom event */ + struct custom_event_desc* p_event_desc; /* Generic event description pointer */ + + /* Lock the table for reading */ + read_lock(&custom_list_lock); + + /* Go through the event description list */ + for(p_event_desc = custom_events->next; + p_event_desc != custom_events; + p_event_desc = p_event_desc->next) + if(p_event_desc->event.id == pm_event_id) + break; + + /* If we haven't found anything */ + if(p_event_desc == custom_events) + { + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); + + /* No such thing */ + return -ENOMEDIUM; + } + + /* Set custom event Id */ + l_custom.id = pm_event_id; + + /* Initialize variable argument list access */ + va_start(l_var_arg_list, pm_event_id); + + /* Print the description out to the temporary buffer */ + l_string_size = vsprintf(l_string, p_event_desc->event.desc, l_var_arg_list); + + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); + + /* Facilitate return to caller */ + va_end(l_var_arg_list); + + /* Set the size of the event */ + l_custom.data_size = (uint32_t) (l_string_size + 1); + + /* Set the pointer to the event data */ + l_custom.data = l_string; + + /* Log the custom event */ + return trace_event(TRACE_EV_CUSTOM, &l_custom); +} + +/******************************************************* + * Trace a raw event + * Parameters : + * pm_event_id, the event Id provided upon creation + * pm_event_size, the size of the data provided + * pm_event_data, data buffer describing event + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer or this + * event doesn't exist. + * -EBUSY, tracing hasn't started yet + *******************************************************/ +int trace_raw_event(int pm_event_id, int pm_event_size, void* pm_event_data) +{ + trace_custom l_custom; /* Custom event */ + struct custom_event_desc* p_event_desc; /* Generic event description pointer */ + + /* Lock the table for reading */ + read_lock(&custom_list_lock); + + /* Go through the event description list */ + for(p_event_desc = custom_events->next; + p_event_desc != custom_events; + p_event_desc = p_event_desc->next) + if(p_event_desc->event.id == pm_event_id) + break; + + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); + + /* If we haven't found anything */ + if(p_event_desc == custom_events) + /* No such thing */ + return -ENOMEDIUM; + + /* Set custom event Id */ + l_custom.id = pm_event_id; + + /* Set the data size */ + if(pm_event_size <= CUSTOM_EVENT_MAX_SIZE) + l_custom.data_size = (uint32_t) pm_event_size; + else + l_custom.data_size = (uint32_t) CUSTOM_EVENT_MAX_SIZE; + + /* Set the pointer to the event data */ + l_custom.data = pm_event_data; + + /* Log the custom event */ + return trace_event(TRACE_EV_CUSTOM, &l_custom); +} + +/******************************************************* + * Trace an event + * Parameters : + * pm_event_id, the event's ID (check out trace.h) + * pm_event_struct, the structure describing the event + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -EBUSY, tracing hasn't started yet + *******************************************************/ +int trace_event(uint8_t pm_event_id, + void* pm_event_struct) +{ + int l_ret_value; /* The return value */ + struct trace_callback_table_entry* p_tct_entry; /* Pointer to trace callback table entry */ + + /* Lock registration variables */ + read_lock(&tracer_register_lock); + + /* Is there a tracer registered */ + if(tracer_registered != 1) + l_ret_value = -ENOMEDIUM; + else + /* Call the tracer */ + l_ret_value = tracer->trace(pm_event_id, pm_event_struct); + + /* Unlock registration variables */ + read_unlock(&tracer_register_lock); + + /* Is this a native event */ + if(pm_event_id <= TRACE_EV_MAX) + { + /* Are there any callbacks to call */ + if(trace_callback_table[pm_event_id - 1].next != NULL) + { + /* Call all the callbacks linked to this event */ + for(p_tct_entry = trace_callback_table[pm_event_id - 1].next; + p_tct_entry != NULL; + p_tct_entry = p_tct_entry->next) + p_tct_entry->callback(pm_event_id, pm_event_struct); + } + } + + /* Give the return value */ + return l_ret_value; +} + +/******************************************************* + * Initialize trace facility + * Parameters : + * NONE + * Return values : + * NONE + *******************************************************/ +static int __init trace_init(void) +{ + int i; /* Generic index */ + + /* Initialize callback table */ + for(i = 0; i < TRACE_EV_MAX; i++) + { + trace_callback_table[i].callback = NULL; + trace_callback_table[i].next = NULL; + } + + /* Next event ID to be used */ + next_event_id = TRACE_EV_MAX + 1; + + /* Initialize custom events list */ + custom_events = &custom_events_head; + custom_events->next = custom_events; + custom_events->prev = custom_events; + + /* Everything is OK */ + return 0; +} + +module_init(trace_init); + +/* Export symbols so that can be visible from outside this file */ +EXPORT_SYMBOL(register_tracer); +EXPORT_SYMBOL(unregister_tracer); +EXPORT_SYMBOL(trace_set_config); +EXPORT_SYMBOL(trace_get_config); +EXPORT_SYMBOL(trace_register_callback); +EXPORT_SYMBOL(trace_unregister_callback); +EXPORT_SYMBOL(trace_create_event); +EXPORT_SYMBOL(trace_create_owned_event); +EXPORT_SYMBOL(trace_destroy_event); +EXPORT_SYMBOL(trace_destroy_owners_events); +EXPORT_SYMBOL(trace_reregister_custom_events); +EXPORT_SYMBOL(trace_std_formatted_event); +EXPORT_SYMBOL(trace_raw_event); +EXPORT_SYMBOL(trace_event); diff -urN linux-2.4.18/Makefile linux-2.4.18-rtai-rthal5g/Makefile --- linux-2.4.18/Makefile 2002-02-25 14:37:52.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/Makefile 2003-11-26 15:59:34.000000000 -0500 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 18 -EXTRAVERSION = +EXTRAVERSION = -rthal5-trace KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -185,6 +185,7 @@ DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o +DRIVERS-$(CONFIG_TRACE) += drivers/trace/trace_driver.o DRIVERS := $(DRIVERS-y) diff -urN linux-2.4.18/mm/filemap.c linux-2.4.18-rtai-rthal5g/mm/filemap.c --- linux-2.4.18/mm/filemap.c 2002-02-25 14:38:13.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/mm/filemap.c 2003-11-26 17:35:30.000000000 -0500 @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -762,10 +764,12 @@ set_task_state(tsk, TASK_UNINTERRUPTIBLE); if (!PageLocked(page)) break; + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_START, 0); sync_page(page); schedule(); } while (PageLocked(page)); tsk->state = TASK_RUNNING; + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_END, 0); remove_wait_queue(&page->wait, &wait); } diff -urN linux-2.4.18/mm/memory.c linux-2.4.18-rtai-rthal5g/mm/memory.c --- linux-2.4.18/mm/memory.c 2002-02-25 14:38:13.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/mm/memory.c 2003-11-26 17:36:34.000000000 -0500 @@ -45,6 +45,8 @@ #include #include +#include + #include #include #include @@ -1120,6 +1122,7 @@ spin_unlock(&mm->page_table_lock); page = lookup_swap_cache(entry); if (!page) { + TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_IN, address); swapin_readahead(entry); page = read_swap_cache_async(entry); if (!page) { diff -urN linux-2.4.18/mm/page_alloc.c linux-2.4.18-rtai-rthal5g/mm/page_alloc.c --- linux-2.4.18/mm/page_alloc.c 2002-02-25 14:38:14.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/mm/page_alloc.c 2003-11-26 17:37:55.000000000 -0500 @@ -19,6 +19,8 @@ #include #include +#include + int nr_swap_pages; int nr_active_pages; int nr_inactive_pages; @@ -90,6 +92,9 @@ BUG(); if (PageActive(page)) BUG(); + + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_FREE, order); + page->flags &= ~((1<flags & PF_FREE_PAGES) @@ -416,6 +421,7 @@ page = alloc_pages(gfp_mask, order); if (!page) return 0; + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_ALLOC, order); return (unsigned long) page_address(page); } diff -urN linux-2.4.18/mm/swap_state.c linux-2.4.18-rtai-rthal5g/mm/swap_state.c --- linux-2.4.18/mm/swap_state.c 2001-10-31 18:31:03.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/mm/swap_state.c 2003-11-26 17:38:36.000000000 -0500 @@ -15,6 +15,8 @@ #include #include +#include + #include /* @@ -27,6 +29,9 @@ UnlockPage(page); return 0; } + + TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_OUT, (unsigned long) page); + rw_swap_page(WRITE, page); return 0; } diff -urN linux-2.4.18/mm/vmalloc.c linux-2.4.18-rtai-rthal5g/mm/vmalloc.c --- linux-2.4.18/mm/vmalloc.c 2002-02-25 14:38:14.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/mm/vmalloc.c 2003-11-26 15:08:58.000000000 -0500 @@ -148,6 +148,9 @@ spin_lock(&init_mm.page_table_lock); do { pmd_t *pmd; +#ifdef CONFIG_X86 + pgd_t olddir = *dir; +#endif pmd = pmd_alloc(&init_mm, dir, address); ret = -ENOMEM; @@ -157,6 +160,10 @@ ret = -ENOMEM; if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot)) break; +#ifdef CONFIG_X86 + if (pgd_val(olddir) != pgd_val(*dir)) + set_pgdir(address, *dir); +#endif address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; diff -urN linux-2.4.18/net/core/dev.c linux-2.4.18-rtai-rthal5g/net/core/dev.c --- linux-2.4.18/net/core/dev.c 2002-02-25 14:38:14.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/net/core/dev.c 2003-11-26 17:42:53.000000000 -0500 @@ -103,6 +103,9 @@ #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) #include /* Note : will define WIRELESS_EXT */ #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + +#include + #ifdef CONFIG_PLIP extern int plip_init(void); #endif @@ -1006,6 +1009,8 @@ return -ENOMEM; } + TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_OUT, skb->protocol); + /* Grab device queue */ spin_lock_bh(&dev->queue_lock); q = dev->qdisc; @@ -1440,6 +1445,8 @@ rx_dev = skb->dev; + TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_IN, skb->protocol); + #ifdef CONFIG_NET_FASTROUTE if (skb->pkt_type == PACKET_FASTROUTE) { netdev_rx_stat[this_cpu].fastroute_deferred_out++; diff -urN linux-2.4.18/net/socket.c linux-2.4.18-rtai-rthal5g/net/socket.c --- linux-2.4.18/net/socket.c 2001-12-21 12:42:06.000000000 -0500 +++ linux-2.4.18-rtai-rthal5g/net/socket.c 2003-11-26 17:46:53.000000000 -0500 @@ -79,6 +79,8 @@ #include #endif +#include + #include #include @@ -504,6 +506,8 @@ int err; struct scm_cookie scm; + TRACE_SOCKET(TRACE_EV_SOCKET_SEND, sock->type, size); + err = scm_send(sock, msg, &scm); if (err >= 0) { err = sock->ops->sendmsg(sock, msg, size, &scm); @@ -518,6 +522,8 @@ memset(&scm, 0, sizeof(scm)); + TRACE_SOCKET(TRACE_EV_SOCKET_RECEIVE, sock->type, size); + size = sock->ops->recvmsg(sock, msg, size, flags, &scm); if (size >= 0) scm_recv(sock, msg, &scm, flags); @@ -920,6 +926,8 @@ if (retval < 0) goto out_release; + TRACE_SOCKET(TRACE_EV_SOCKET_CREATE, retval, type); + out: /* It may be already another descriptor 8) Not kernel problem. */ return retval; @@ -1557,6 +1565,8 @@ a0=a[0]; a1=a[1]; + + TRACE_SOCKET(TRACE_EV_SOCKET_CALL, call, a0); switch(call) {