diff -urN linux-2.6.19/arch/i386/Kconfig linux-2.6.19-mync/arch/i386/Kconfig --- linux-2.6.19/arch/i386/Kconfig 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/Kconfig 2007-01-28 15:47:32.000000000 +0300 @@ -182,6 +182,42 @@ endchoice +config SDEBUG + bool "Serial port debugging" + default n + depends on !(SERIAL_8250) + help + Enable debugging through serial port + +config PF + bool "Performance tracing (\"-pf\")" + default y + help + Enable Performance Tracing Toolkit ("-pf") support + +config PF_BUFFER_ORDER + int "Trace buffer size order" + default 12 + depends on PF + help + The count of pages in a trace buffer as the power of two. + The default value is 12 (16 Mb). + +config RTI + bool "Real-time interrupts" + depends on X86_LOCAL_APIC + default y + help + Emulate cli/sti commands through interrupt controller hardware. + This allows the developer to make some interrupt vectors + priveleged. Priveleged interrupt handlers can preempt conventional + Linux code at any time. + +config WRAP_IRQ + bool + default y + depends on (RTI || PF) + config ACPI_SRAT bool default y diff -urN linux-2.6.19/arch/i386/kernel/apic.c linux-2.6.19-mync/arch/i386/kernel/apic.c --- linux-2.6.19/arch/i386/kernel/apic.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/apic.c 2007-01-28 15:47:32.000000000 +0300 @@ -43,6 +43,35 @@ #include "io_ports.h" +#ifdef CONFIG_RTI +#undef spin_lock_irqsave +#undef spin_unlock_irqrestore + +#define spin_lock_irqsave(a, b) \ + do { \ + direct_irq_save (b); \ + spin_lock (a); \ + } while (0) + +#define spin_unlock_irqrestore(a, b) \ + do { \ + spin_unlock (a); \ + direct_irq_restore (b); \ + } while (0) + +#undef local_irq_save +#undef local_irq_restore + +#define local_irq_save(a) direct_irq_save (a) +#define local_irq_restore(a) direct_irq_restore (a) + +#undef local_irq_enable +#undef local_irq_disable + +#define local_irq_enable(a) direct_irq_enable (a) +#define local_irq_disable(a) direct_irq_disable (a) +#endif + /* * cpu_mask that denotes the CPUs that needs timer interrupt coming in as * IPIs in place of local APIC timers @@ -1198,6 +1227,10 @@ profile_tick(CPU_PROFILING); #ifdef CONFIG_SMP update_process_times(user_mode_vm(get_irq_regs())); +#else +#ifdef CONFIG_RTI + update_process_times(user_mode_vm(get_irq_regs())); +#endif #endif /* diff -urN linux-2.6.19/arch/i386/kernel/cpu/common.c linux-2.6.19-mync/arch/i386/kernel/cpu/common.c --- linux-2.6.19/arch/i386/kernel/cpu/common.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/cpu/common.c 2007-01-28 15:47:32.000000000 +0300 @@ -431,7 +431,9 @@ } /* SEP disabled? */ +#ifndef CONFIG_WRAP_IRQ if (disable_x86_sep) +#endif clear_bit(X86_FEATURE_SEP, c->x86_capability); if (disable_pse) diff -urN linux-2.6.19/arch/i386/kernel/cpu/mtrr/generic.c linux-2.6.19-mync/arch/i386/kernel/cpu/mtrr/generic.c --- linux-2.6.19/arch/i386/kernel/cpu/mtrr/generic.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/cpu/mtrr/generic.c 2007-01-28 15:47:32.000000000 +0300 @@ -11,6 +11,35 @@ #include #include "mtrr.h" +#ifdef CONFIG_RTI +#undef spin_lock_irqsave +#undef spin_unlock_irqrestore + +#define spin_lock_irqsave(a, b) \ + do { \ + direct_irq_save (b); \ + spin_lock (a); \ + } while (0) + +#define spin_unlock_irqrestore(a, b) \ + do { \ + spin_unlock (a); \ + direct_irq_restore (b); \ + } while (0) + +#undef local_irq_save +#undef local_irq_restore + +#define local_irq_save(a) direct_irq_save (a) +#define local_irq_restore(a) direct_irq_restore (a) + +#undef local_irq_enable +#undef local_irq_disable + +#define local_irq_enable(a) direct_irq_enable (a) +#define local_irq_disable(a) direct_irq_disable (a) +#endif + struct mtrr_state { struct mtrr_var_range *var_ranges; mtrr_type fixed_ranges[NUM_FIXED_RANGES]; diff -urN linux-2.6.19/arch/i386/kernel/cpu/mtrr/main.c linux-2.6.19-mync/arch/i386/kernel/cpu/mtrr/main.c --- linux-2.6.19/arch/i386/kernel/cpu/mtrr/main.c 2007-01-28 15:38:59.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/cpu/mtrr/main.c 2007-01-28 15:47:32.000000000 +0300 @@ -45,6 +45,35 @@ #include #include "mtrr.h" +#ifdef CONFIG_RTI +#undef spin_lock_irqsave +#undef spin_unlock_irqrestore + +#define spin_lock_irqsave(a, b) \ + do { \ + direct_irq_save (b); \ + spin_lock (a); \ + } while (0) + +#define spin_unlock_irqrestore(a, b) \ + do { \ + spin_unlock (a); \ + direct_irq_restore (b); \ + } while (0) + +#undef local_irq_save +#undef local_irq_restore + +#define local_irq_save(a) direct_irq_save (a) +#define local_irq_restore(a) direct_irq_restore (a) + +#undef local_irq_enable +#undef local_irq_disable + +#define local_irq_enable(a) direct_irq_enable (a) +#define local_irq_disable(a) direct_irq_disable (a) +#endif + u32 num_var_ranges = 0; unsigned int *usage_table; diff -urN linux-2.6.19/arch/i386/kernel/crash.c linux-2.6.19-mync/arch/i386/kernel/crash.c --- linux-2.6.19/arch/i386/kernel/crash.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/crash.c 2007-01-28 15:47:32.000000000 +0300 @@ -27,6 +27,34 @@ #include +#ifdef CONFIG_RTI +#undef spin_lock_irqsave +#undef spin_unlock_irqrestore + +#define spin_lock_irqsave(a, b) \ + do { \ + direct_irq_save (b); \ + spin_lock (a); \ + } while (0) + +#define spin_unlock_irqrestore(a, b) \ + do { \ + spin_unlock (a); \ + direct_irq_restore (b); \ + } while (0) + +#undef local_irq_save +#undef local_irq_restore + +#define local_irq_save(a) direct_irq_save (a) +#define local_irq_restore(a) direct_irq_restore (a) + +#undef local_irq_enable +#undef local_irq_disable + +#define local_irq_enable(a) direct_irq_enable (a) +#define local_irq_disable(a) direct_irq_disable (a) +#endif /* This keeps a track of which one is crashing cpu. */ static int crashing_cpu; diff -urN linux-2.6.19/arch/i386/kernel/entry.S linux-2.6.19-mync/arch/i386/kernel/entry.S --- linux-2.6.19/arch/i386/kernel/entry.S 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/entry.S 2007-01-28 15:47:32.000000000 +0300 @@ -77,8 +77,8 @@ VM_MASK = 0x00020000 /* These are replaces for paravirtualization */ -#define DISABLE_INTERRUPTS cli -#define ENABLE_INTERRUPTS sti +#define DISABLE_INTERRUPTS rti_cli +#define ENABLE_INTERRUPTS rti_sti #define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit #define INTERRUPT_RETURN iret #define GET_CR0_INTO_EAX movl %cr0, %eax @@ -181,6 +181,8 @@ .long 2b,4b; \ .previous +#include "wrap_irq.inc.S" + #define RING0_INT_FRAME \ CFI_STARTPROC simple;\ CFI_SIGNAL_FRAME;\ @@ -250,6 +252,7 @@ DISABLE_INTERRUPTS # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret + RTI_ACTIVATE_USERSPACE movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? @@ -262,6 +265,7 @@ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? jnz restore_nocheck need_resched: + RTI_ACTIVATE_USERSPACE movl TI_flags(%ebp), %ecx # need_resched set ? testb $_TIF_NEED_RESCHED, %cl jz restore_all @@ -390,6 +394,7 @@ TRACE_IRQS_IRET restore_nocheck_notrace: RESTORE_REGS + RESTORE_WRAP_IRQ addl $4, %esp CFI_ADJUST_CFA_OFFSET -4 1: INTERRUPT_RETURN @@ -429,6 +434,7 @@ CFI_ADJUST_CFA_OFFSET -8 # frame has moved TRACE_IRQS_IRET RESTORE_REGS + RESTORE_WRAP_IRQ lss 20+4(%esp), %esp # switch to 16bit stack 1: INTERRUPT_RETURN .section __ex_table,"a" @@ -821,6 +827,7 @@ xorl %edx,%edx # zero error code call do_nmi RESTORE_REGS + RESTORE_WRAP_IRQ lss 12+4(%esp), %esp # back to 16bit stack 1: INTERRUPT_RETURN CFI_ENDPROC diff -urN linux-2.6.19/arch/i386/kernel/head.S linux-2.6.19-mync/arch/i386/kernel/head.S --- linux-2.6.19/arch/i386/kernel/head.S 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/head.S 2007-01-28 15:47:32.000000000 +0300 @@ -433,6 +433,9 @@ /* This is the default interrupt "handler" :-) */ ALIGN ignore_int: +#ifdef CONFIG_RTI + iret +#else cld #ifdef CONFIG_PRINTK pushl %eax @@ -464,6 +467,7 @@ popl %eax #endif iret +#endif /* * Real beginning of normal "text" segment diff -urN linux-2.6.19/arch/i386/kernel/i8259.c linux-2.6.19-mync/arch/i386/kernel/i8259.c --- linux-2.6.19/arch/i386/kernel/i8259.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/i8259.c 2007-01-28 15:47:32.000000000 +0300 @@ -25,6 +25,35 @@ #include +#ifdef CONFIG_RTI +#undef spin_lock_irqsave +#undef spin_unlock_irqrestore + +#define spin_lock_irqsave(a, b) \ + do { \ + direct_irq_save (b); \ + spin_lock (a); \ + } while (0) + +#define spin_unlock_irqrestore(a, b) \ + do { \ + spin_unlock (a); \ + direct_irq_restore (b); \ + } while (0) + +#undef local_irq_save +#undef local_irq_restore + +#define local_irq_save(a) direct_irq_save (a) +#define local_irq_restore(a) direct_irq_restore (a) + +#undef local_irq_enable +#undef local_irq_disable + +#define local_irq_enable(a) direct_irq_enable (a) +#define local_irq_disable(a) direct_irq_disable (a) +#endif + /* * This is the 'legacy' 8259A Programmable Interrupt Controller, * present in the majority of PC/AT boxes. @@ -65,7 +94,11 @@ */ unsigned long io_apic_irqs; +#ifndef CONFIG_RTI void disable_8259A_irq(unsigned int irq) +#else +asmlinkage void disable_8259A_irq(unsigned int irq) +#endif { unsigned int mask = 1 << irq; unsigned long flags; diff -urN linux-2.6.19/arch/i386/kernel/io_apic.c linux-2.6.19-mync/arch/i386/kernel/io_apic.c --- linux-2.6.19/arch/i386/kernel/io_apic.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/io_apic.c 2007-01-28 15:47:32.000000000 +0300 @@ -49,6 +49,35 @@ #include "io_ports.h" +#ifdef CONFIG_RTI +#undef spin_lock_irqsave +#undef spin_unlock_irqrestore + +#define spin_lock_irqsave(a, b) \ + do { \ + direct_irq_save (b); \ + spin_lock (a); \ + } while (0) + +#define spin_unlock_irqrestore(a, b) \ + do { \ + spin_unlock (a); \ + direct_irq_restore (b); \ + } while (0) + +#undef local_irq_save +#undef local_irq_restore + +#define local_irq_save(a) direct_irq_save (a) +#define local_irq_restore(a) direct_irq_restore (a) + +#undef local_irq_enable +#undef local_irq_disable + +#define local_irq_enable(a) direct_irq_enable (a) +#define local_irq_disable(a) direct_irq_disable (a) +#endif + int (*ioapic_renumber_irq)(int ioapic, int irq); atomic_t irq_mis_count; @@ -266,7 +295,11 @@ __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); } +#ifndef CONFIG_RTI static void mask_IO_APIC_irq (unsigned int irq) +#else +asmlinkage void mask_IO_APIC_irq (unsigned int irq) +#endif { unsigned long flags; @@ -1237,6 +1270,10 @@ /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; +#ifdef CONFIG_RTI +extern volatile unsigned long rti_vector_irq [NR_VECTORS]; +#endif + static int __assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; @@ -1260,6 +1297,9 @@ vector = current_vector; irq_vector[irq] = vector; +#ifdef CONFIG_RTI + rti_vector_irq [vector] = irq; +#endif return vector; } @@ -1295,6 +1335,10 @@ set_intr_gate(vector, interrupt[irq]); } +#ifdef CONFIG_RTI +extern unsigned long rti_io_apic_enabled; +#endif + static void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; @@ -1303,6 +1347,8 @@ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); + rti_io_apic_enabled = 1; + for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -2000,12 +2046,17 @@ static void ack_ioapic_irq(unsigned int irq) { +#ifndef CONFIG_RTI +// SIMPLE move_native_irq(irq); +#endif ack_APIC_irq(); } static void ack_ioapic_quirk_irq(unsigned int irq) { +#ifndef CONFIG_RTI +// SIMPLE unsigned long v; int i; @@ -2032,9 +2083,12 @@ i = irq_vector[irq]; v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); +#endif ack_APIC_irq(); +#ifndef CONFIG_RTI +// SIMPLE if (!(v & (1 << (i & 0x1f)))) { atomic_inc(&irq_mis_count); spin_lock(&ioapic_lock); @@ -2042,6 +2096,9 @@ __unmask_and_level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); } +#else + unmask_IO_APIC_irq (irq); +#endif } static int ioapic_retrigger_irq(unsigned int irq) diff -urN linux-2.6.19/arch/i386/kernel/Makefile linux-2.6.19-mync/arch/i386/kernel/Makefile --- linux-2.6.19/arch/i386/kernel/Makefile 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/Makefile 2007-01-28 15:47:32.000000000 +0300 @@ -39,6 +39,9 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o +obj-$(CONFIG_PF) += pf.o +obj-$(CONFIG_RTI) += rti.o +obj-$(CONFIG_SDEBUG) += sdebug.o EXTRA_AFLAGS := -traditional diff -urN linux-2.6.19/arch/i386/kernel/pf.c linux-2.6.19-mync/arch/i386/kernel/pf.c --- linux-2.6.19/arch/i386/kernel/pf.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/pf.c 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,290 @@ +#include +#include +#include +#include +#include +#include +#include + +volatile unsigned char *pf_trace_buffer = NULL; +unsigned long pf_trace_size; + +volatile struct pf_trace_info *pf_trace_info; + +EXPORT_SYMBOL (pf_trace_buffer); +EXPORT_SYMBOL (pf_trace_info); +EXPORT_SYMBOL (pf_trace_size); + +/* Traced event types and formats: + * A) Interrupt/trap gate entrance + * Occurs when the CPU enters an interrupt or a trap gate. + * + * 0 1 9 10 11 15 + * +----+---------+---+------+---+ + * |type|timestamp|cpu|vector|EIP| + * +----+---------+---+------+---+ + * + * type = 7 + * timestamp - TSC value at the moment + * cpu - CPU that the event belongs to + * vector - interrupt/trap gate vector No. + * EIP - EIP value on the stack + * + * B) iret to kernelspace (CPL = 0) + * Is triggered before each iret when CS on the stack + * indicate that CPL after iret will be 0. + * This is a very simple event. We have almost nothing to trace, + * e.g. there's no process context. + * + * 0 1 9 10 + * +----+---------+---+ + * |type|timestamp|cpu| + * +----+---------+---+ + * + * type = 2 + * timestamp - TSC value at the moment + * cpu - CPU that the event belongs to + * + * C) iret to userspace (CPL != 0) + * Is triggered before each iret when CS on the stack + * indicate that CPL after iret will be nonzero. + * + * 0 1 9 10 14 + * +----+---------+---+---+ + * |type|timestamp|cpu|PID| + * +----+---------+---+---+ + * + * type = 1 + * cpu - CPU that the event belongs to + * timestamp - TSC value at the moment + * PID - current process's PID + * + * D) Text message + * + * 0 1 9 13 + * +----+---------+---+-----> + * |type|timestamp|len|text + * +----+---------+---+-----> + * + * type = 3 + * timestamp - TSC value at the moment + * len - message length + * text - message text + */ + +asmlinkage void +pf_trace_interrupt (unsigned long vector, + unsigned long eip) +{ + unsigned char msg [15]; + unsigned char emsg [2 * sizeof msg]; + unsigned long elen; + + if (pf_trace_buffer == NULL || + pf_trace_info->enabled == 0) + return; + + msg [0] = PF_MSGTYPE_INTERRUPT; + rdtscll (*(unsigned long long*) (msg + 1)); + msg [9] = current->thread_info->cpu; + msg [10] = (unsigned char) vector; + *(unsigned long*) (msg + 11) = eip; + + elen = pf_escape_message (emsg, msg, sizeof msg); + pf_trace_message (emsg, elen); +} + +asmlinkage void +pf_trace_iret_to_user (void) +{ + unsigned char msg [14]; + unsigned char emsg [2 * sizeof msg]; + unsigned long elen; + + if (pf_trace_buffer == NULL || + pf_trace_info->enabled == 0) + return; + + msg [0] = PF_MSGTYPE_IRET_TO_USER; + rdtscll (*(unsigned long long*) (msg + 1)); + msg [9] = current->thread_info->cpu; + *(unsigned long*) (msg + 10) = (unsigned long) current->pid; + + elen = pf_escape_message (emsg, msg, sizeof msg); + pf_trace_message (emsg, elen); +} + +asmlinkage void +pf_trace_iret_to_kernel (void) +{ + unsigned char msg [10]; + unsigned char emsg [2 * sizeof msg]; + unsigned long elen; + + if (pf_trace_buffer == NULL || + pf_trace_info->enabled == 0) + return; + + msg [0] = PF_MSGTYPE_IRET_TO_KERNEL; + rdtscll (*(unsigned long long*) (msg + 1)); + msg [9] = current->thread_info->cpu; + + elen = pf_escape_message (emsg, msg, sizeof msg); + pf_trace_message (emsg, elen); +} + +unsigned long +pf_escape_message (unsigned char *to, + unsigned char *from, + unsigned long fromLen) +{ + unsigned long toPos, + fromPos; + + toPos = 0; + for (fromPos = 0; fromPos < fromLen; fromPos++) { + if (from [fromPos] == 'E') { + to [toPos] = 'e'; + toPos ++; + to [toPos] = 'a'; + toPos ++; + } else + if (from [fromPos] == 'e') { + to [toPos] = 'e'; + toPos ++; + to [toPos] = 'b'; + toPos ++; + } else { + to [toPos] = from [fromPos]; + toPos ++; + } + } + + return toPos; +} + +/* Returns 0 on success, -1 on failure. */ +static int +pf_trace_position_add (unsigned long n, unsigned long *pos) +{ + unsigned long oldval, + newval, + exchanged; + + for (;;) { + oldval = pf_trace_info->position; + newval = oldval + n; + + if (newval < oldval || + newval > pf_trace_size) + return -1; + + __asm__ __volatile__ ( + " lock; cmpxchg %3, %2 ;" + " jz 1f ;" + " movl $0, %1 ;" + " jmp 2f ;" + "1: movl $1, %1 ;" + "2: " + : "=m" (pf_trace_info->position), + "=g" (exchanged) + : "m" (pf_trace_info->position), + "r" (newval), + "a" (oldval) + : "cc"); + + if (exchanged) { + *pos = oldval; + return 0; + } + } + + /* unreachable */ +} + +/* message must be escaped already */ +void +pf_trace_message (const char *message, + unsigned long length) +{ + unsigned long pos, + i; + + if (pf_trace_buffer == NULL || + pf_trace_info->enabled == 0 || + length < 1) + return; + + if (pf_trace_position_add (length + 1, &pos)) + return; + + for (i = 1; i < length; i++) { + pf_trace_buffer [pos + i] = message [i]; + } + + pf_trace_buffer [pos + length] = 'E'; + pf_trace_buffer [pos] = message [0]; +} + +EXPORT_SYMBOL (pf_trace_message); + +void +pf_clear_trace_buffer (void) +{ + unsigned long i; + + if (pf_trace_buffer == NULL) + return; + + pf_trace_info->enabled = 0; + + for (i = 0; i < pf_trace_size; i++) + pf_trace_buffer [i] = 0; + + pf_trace_info->position = 0; +} + +static void +pf_set_page_count (unsigned long start, + unsigned long order) +{ + unsigned long count = 1 << order, + address = start, + i; + struct page *page; + + for (i = 0; i < count; i++) { + page = virt_to_page (address); + atomic_set (&page->_count, 1); + address += PAGE_SIZE; + } +} + +void __init +pf_init (void) +{ + printk ("Initializing Pf tracing\n"); + + pf_trace_buffer = (unsigned char*) + __get_free_pages (GFP_ATOMIC | __GFP_REPEAT, + CONFIG_PF_BUFFER_ORDER); + if (pf_trace_buffer == NULL) { + printk ("Pf trace buffer allocation failed\n"); + return; + } + + pf_set_page_count ((unsigned long) pf_trace_buffer, + CONFIG_PF_BUFFER_ORDER); + + pf_trace_info = (struct pf_trace_info*) + (pf_trace_buffer + (1 << CONFIG_PF_BUFFER_ORDER << PAGE_SHIFT) - + PAGE_SIZE); + + pf_trace_info->position = 0; + pf_trace_info->enabled = 0; + + /* There is one guard page at the end */ + pf_trace_size = (1 << CONFIG_PF_BUFFER_ORDER << PAGE_SHIFT) - + (PAGE_SIZE << 1); +} + diff -urN linux-2.6.19/arch/i386/kernel/pf.inc.S linux-2.6.19-mync/arch/i386/kernel/pf.inc.S --- linux-2.6.19/arch/i386/kernel/pf.inc.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/pf.inc.S 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,92 @@ +#ifdef CONFIG_PF + +.text + /* After PF_TRACE_BEGIN: + * 4 bytes is EIP pushed by `call' instruction + * 12 bytes are pushed on the stack right at the beginning + * the next 4 bytes on the stack is $vector */ +pf_irq_entry: + pushfl + pushl %eax + pushl %ebx + + movl 16 (%esp), %eax + andl $0xff, %eax + + /* Check if it is an exception with an error code on the stack */ + cmpl $8, %eax; je 1f + cmpl $10, %eax; je 1f + cmpl $11, %eax; je 1f + cmpl $12, %eax; je 1f + cmpl $13, %eax; je 1f + cmpl $14, %eax; je 1f + cmpl $17, %eax; je 1f + + /* Remember of 16 bytes pushed in WRAP_IRQ_GATE */ + movl /* 20 + 16 */ 36 (%esp), %ebx + jmp 2f +1: /* Remember of 16 bytes pushed in WRAP_IRQ_GATE */ + movl /* 24 + 16 */ 40 (%esp), %ebx +2: + pushl %ecx + pushl %edx + pushl %ebx /* eip */ + pushl %eax /* vector */ + call pf_trace_interrupt + addl $8, %esp + popl %edx + popl %ecx + + popl %ebx + popl %eax + popfl + ret + + /* After PF_TRACE_BEGIN: + * 4 bytes is EIP pushed by `call' instruction + * 8 bytes are pushed on the stack right at the beginning + * 20 more bytes are pushed in the beginning of RESTORE_WRAP_IRQ + * then come: + * EIP (offset 32) + * CS (offset 36) + * EFLAGS (offset 40) + * Event type: + * 1 - iret to CPL != 0 + * In this case we have access to current task_struct + * 2 - iret to CPL == 0 (FIGUREMEOUT VM_MASK?) + */ +pf_iret: + pushfl + pushl %eax + + movl 36 (%esp), %eax + testl $(VM_MASK | 3), %eax + jz 1f + + pushl %ecx + pushl %edx + call pf_trace_iret_to_user + popl %edx + popl %ecx + jmp 2f; + +1: pushl %ecx + pushl %edx + call pf_trace_iret_to_kernel + popl %edx + popl %ecx + +2: popl %eax + popfl + ret + +#define PF_IRQ_ENTRY call pf_irq_entry +#define PF_IRET call pf_iret + +#else + +#define PF_IRQ_ENTRY +#define PF_IRET + +#endif /* CONFIG_PF */ + diff -urN linux-2.6.19/arch/i386/kernel/process.c linux-2.6.19-mync/arch/i386/kernel/process.c --- linux-2.6.19/arch/i386/kernel/process.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/process.c 2007-01-28 15:47:32.000000000 +0300 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,7 @@ /* endless idle loop with no priority at all */ while (1) { + rti_activate_userspace (); while (!need_resched()) { void (*idle)(void); diff -urN linux-2.6.19/arch/i386/kernel/reboot.c linux-2.6.19-mync/arch/i386/kernel/reboot.c --- linux-2.6.19/arch/i386/kernel/reboot.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/reboot.c 2007-01-28 15:47:32.000000000 +0300 @@ -17,6 +17,7 @@ #include #include "mach_reboot.h" #include +#include /* * Power off function, if any @@ -281,6 +282,8 @@ void machine_shutdown(void) { + rti_stop (); + #ifdef CONFIG_SMP int reboot_cpu_id; diff -urN linux-2.6.19/arch/i386/kernel/rti.c linux-2.6.19-mync/arch/i386/kernel/rti.c --- linux-2.6.19/arch/i386/kernel/rti.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/rti.c 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include +#include + +struct rti_pending_irq { + unsigned long pending; + unsigned long next; +} __attribute__ ((packed)); + +extern void* wrap_irq_interrupt_entry_points [256]; + +volatile unsigned long rti_if [NR_CPUS]; +volatile unsigned long rti_first_pending_irq [NR_CPUS]; +volatile unsigned long rti_last_pending_irq [NR_CPUS]; +volatile struct rti_pending_irq rti_pending_irqs [NR_VECTORS] [NR_CPUS]; + +extern asmlinkage void rti_timer_interrupt (void); +extern void rti_set_privileged_intr_gate (unsigned int n, void *addr); + +volatile unsigned long rti_vector_irq [NR_VECTORS]; + +rti_userspace_activator_proc rti_userspace_activator = NULL; + +void rti_set_userspace_activator (rti_userspace_activator_proc proc) +{ + /* This is supposed to be atomic. */ + rti_userspace_activator = proc; +} + +EXPORT_SYMBOL (rti_set_userspace_activator); + +void rti_activate_userspace (void) +{ + if (rti_userspace_activator != NULL) + rti_userspace_activator (); +} + +#define RTI_NO_IRQ 666 +#define RTI_IF_ON 0x200 +#define RTI_IF_OFF 0 + +asmlinkage void rti_add_pending_irq (unsigned long irq) +{ + unsigned long flags; + int cpu; + + /* TODO illogical, the CPU has to be the same */ + direct_irq_save (flags); + cpu = raw_smp_processor_id (); + + if (irq != 49 && irq != 32) + sdbg_printf ("A%lu", irq); + else + sdbg_printf ("a"); + + rti_pending_irqs [irq] [cpu].pending = 1; + if (rti_pending_irqs [irq] [cpu].next == RTI_NO_IRQ && + rti_last_pending_irq [cpu] != irq) + { + if (rti_last_pending_irq [cpu] == RTI_NO_IRQ) { + rti_first_pending_irq [cpu] = irq; + rti_last_pending_irq [cpu] = irq; + } else { + unsigned long last_irq; + + last_irq = rti_last_pending_irq [cpu]; + rti_pending_irqs [last_irq] [cpu].next = irq; + rti_last_pending_irq [cpu] = irq; + } + } + + direct_irq_restore (flags); +} + +/* Must be called with interrupts disabled. */ +asmlinkage void rti_unset_pending_irq (unsigned long irq) +{ + int cpu = raw_smp_processor_id (); + + sdbg_printf ("U%lu", irq); + + rti_pending_irqs [irq] [cpu].pending = 0; +} + +/* Must be called with interrupts disabled. */ +static unsigned long rti_take_distinct_pending_irq (unsigned long irq) +{ + int cpu = raw_smp_processor_id (); + + if (rti_pending_irqs [irq] [cpu].pending != 1) + return RTI_NO_IRQ; + + rti_pending_irqs [irq] [cpu].pending = 0; + + sdbg_printf ("d"); + + return irq; +} + +/* Must be called with interrupts disabled. */ +static unsigned long rti_take_any_pending_irq (void) +{ + int cpu = raw_smp_processor_id (); + unsigned long irq, + next_irq; + + irq = rti_first_pending_irq [cpu]; + while (irq != RTI_NO_IRQ) { + next_irq = rti_pending_irqs [irq] [cpu].next; + rti_pending_irqs [irq] [cpu].next = RTI_NO_IRQ; + rti_first_pending_irq [cpu] = next_irq; + + if (next_irq == RTI_NO_IRQ) + rti_last_pending_irq [cpu] = RTI_NO_IRQ; + + if (rti_pending_irqs [irq] [cpu].pending == 1) { + rti_pending_irqs [irq] [cpu].pending = 0; + if (irq != 49 && irq != 32) + sdbg_printf ("P%lu", irq); + else + sdbg_printf ("p"); + return irq; + } + + irq = next_irq; + } + + return RTI_NO_IRQ; +} + +/* Must be called with interrupts disabled. */ +asmlinkage unsigned long rti_take_pending_irq_entry (void) +{ + unsigned long irq; + + irq = rti_take_distinct_pending_irq (INVALIDATE_TLB_VECTOR); + if (irq == RTI_NO_IRQ) + irq = rti_take_any_pending_irq (); + + if (irq != RTI_NO_IRQ) + return (unsigned long) wrap_irq_interrupt_entry_points [irq]; + + return 0; /* NULL */ +} + +#ifndef CONFIG_X86_IO_APIC +asmlinkage void mask_IO_APIC_irq (unsigned int irq) +{ + /* must not get here */ +} +#endif + +static void rti_set_smi (int on) +{ + unsigned char b0, + b1; + unsigned short smi_en; + struct pci_dev *dev = NULL; + struct pci_device_id id = + { PCI_DEVICE (PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH7_0) }; + unsigned long value; + + dev = pci_get_device (id.vendor, id.device, NULL); + + if (dev == NULL || dev->bus->number || dev->devfn != 0xf8) { + pci_dev_put (dev); + printk ("rti_set_smi: 945P not found\n"); + return; + } + + pci_read_config_byte (dev, 0x40, &b0); + pci_read_config_byte (dev, 0x41, &b1); + + smi_en = (((b1 << 1) | (b0 >> 7)) << 7) + 0x30; + + value = inl (smi_en); + if (on) + value |= 1; + else + value &= ~1; + + outl (value, smi_en); + + printk ("rti_set_smi: SMI %s globally in ICH7\n", + on ? "enabled" : "disabled"); +} + +void rti_init_timer (void) +{ + rti_set_privileged_intr_gate (LOCAL_TIMER_VECTOR, rti_timer_interrupt); + +/* apic_write_around (APIC_TDCR, 0xb); + apic_write_around (APIC_TMICT, 5000); +*/ +} + +extern asmlinkage void rti_switch_rt_on (void); +extern asmlinkage void rti_switch_rt_off (void); + +void rti_init (void) +{ + unsigned long flags; + unsigned i, j; + + local_irq_save (flags); + + for (i = 0; i < NR_CPUS; i++) { + rti_if [i] = 0x200; + + rti_first_pending_irq [i] = RTI_NO_IRQ; + rti_last_pending_irq [i] = RTI_NO_IRQ; + + for (j = 0; j < NR_VECTORS; j++) { + rti_pending_irqs [j] [i].pending = 0; + rti_pending_irqs [j] [i].next = RTI_NO_IRQ; + } + } + + rti_switch_rt_on (); + rti_init_timer (); + rti_set_smi (0); + local_irq_restore (flags); +} + +void rti_stop (void) +{ + unsigned long flags; + + local_irq_save (flags); + direct_irq_disable (); + rti_switch_rt_off (); + rti_set_smi (1); + local_irq_restore (flags); +} + +extern asmlinkage void rti_save_flags (void); +extern asmlinkage void rti_irq_restore (void); +extern void (*rti_timer_callback) (void); + +EXPORT_SYMBOL (rti_irq_enable); +EXPORT_SYMBOL (rti_irq_disable); +EXPORT_SYMBOL (rti_save_flags); +EXPORT_SYMBOL (rti_irq_restore); +EXPORT_SYMBOL (rti_safe_halt); + +EXPORT_SYMBOL (rti_timer_callback); + diff -urN linux-2.6.19/arch/i386/kernel/rti.inc.S linux-2.6.19-mync/arch/i386/kernel/rti.inc.S --- linux-2.6.19/arch/i386/kernel/rti.inc.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/rti.inc.S 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,679 @@ +#ifdef CONFIG_RTI +#include +#include +#include +#include +#include + +/* TODO Move this macro to a common header + * (it is defined in rti.c too) */ +#define RTI_NO_IRQ 666 + +.text + +/* Speaker sound generation (one pulse) */ +#define DEBUG_SPEAKER \ + pushfl; \ + pushl %eax; \ + inb $0x61, %al; \ + xorb $2, %al; \ + outb %al, $0x61; \ + popl %eax; \ + popfl; + + /* Hang up on the current CPU + * and make some noise from the speaker */ +#define DEBUG_BEEP \ + cli; \ + movl $0, %ebx; \ +5: cmpl $0, %ebx; \ + jne 6f; \ + inb $0x61, %al; \ + xorb $2, %al; \ + outb %al, $0x61; \ + movl $300000, %ebx; \ + jmp 5b; \ +6: decl %ebx; \ + jmp 5b + +#define rti_cli call rti_irq_disable +#define rti_sti call rti_irq_enable + +ENTRY (rti_debug_beep) + cli + DEBUG_BEEP + ret + +#define RTI_CPUS_ORDER 11 +/* Per-CPU shift for rti_lapic_mask */ +#define RTI_LAPIC_MASK_ORDER 10 + +/* This value must exactly match the one + * in the enum at asm/fixmap.h */ +#define RTI_FIX_APIC_BASE 2 +#define RTI_APIC_BASE (__FIXADDR_TOP - (RTI_FIX_APIC_BASE \ + << PAGE_SHIFT)) +#define RTI_APIC_REGISTER(x) (RTI_APIC_BASE + (x)) + +.data + +/* Virtual local APIC masks are separate for each interrupt. + * The purpose is to prevent extra interrupts right after issuing EOI + * and till conventional kernel code performs ack_APIC_irq thus + * emulating usual system behaivour */ +ENTRY (rti_lapic_mask) +.rept NR_CPUS +.rept 256 + .long 0 +.endr +.endr + +/* RTI hooks are active */ +ENTRY (rti_rt_on) + .long 0 + +ENTRY (rti_timer_callback) + .long 0 + +rti_save_flags_vptr: + .long rti_save_flags_nonrt +rti_irq_restore_vptr: + .long rti_irq_restore_nonrt +rti_irq_disable_vptr: + .long rti_irq_disable_nonrt +rti_irq_enable_vptr: + .long rti_irq_enable_nonrt +rti_safe_halt_vptr: + .long rti_safe_halt_nonrt + +rti_gate_vptr: + .long rti_gate_nonrt +rti_managed_gate_vptr: + .long rti_managed_gate_nonrt + +rti_iret_vptr: + .long rti_iret_nonrt + +.text + +#define RTI_GATE(arg) \ + pushl $arg; \ + call *%cs:rti_gate_vptr; \ + addl $4, %esp + +#define RTI_MANAGED_GATE(arg) \ + pushl $arg; \ + call *%cs:rti_managed_gate_vptr; \ + addl $4, %esp + +#define RTI_IRQ_GATE RTI_GATE (0) +#define RTI_IRQ_GATE_EC RTI_GATE (2) +#define RTI_TRAP_GATE RTI_GATE (1) +#define RTI_TRAP_GATE_EC RTI_GATE (3) + +#define RTI_MANAGED_IRQ_GATE RTI_MANAGED_GATE (0) +#define RTI_MANAGED_IRQ_NOACK RTI_MANAGED_GATE (1) +#define RTI_MANAGED_IRQ_EXT RTI_MANAGED_GATE (2) + +#define RTI_MANAGED_TRAP_GATE RTI_MANAGED_GATE (4) +#define RTI_MANAGED_TRAP_NOACK RTI_MANAGED_GATE (5) +#define RTI_MANAGED_TRAP_EXT RTI_MANAGED_GATE (6) + +#define RTI_IRET call rti_iret + +/* return value in EAX */ +rti_save_flags_nonrt: + pushfl + popl %eax + ret + +/* argument in EAX */ +rti_irq_restore_nonrt: + pushl %eax + popfl + ret + +rti_irq_disable_nonrt: + cli + ret + +rti_irq_enable_nonrt: + sti + ret + +rti_safe_halt_nonrt: + sti + hlt + ret + +rti_managed_gate_nonrt: +rti_gate_nonrt: +rti_iret_nonrt: + ret + +ENTRY (rti_timer_interrupt) + pushfl + pushl %eax + pushl %ds + pushl %es + + movl $(__USER_DS), %eax + movl %eax, %ds; + movl %eax, %es + + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + cmpl $0, %ebp + popl %ebp + je rti_timer_bsp +rti_timer_nonbsp: + pushl $0xef + PF_IRQ_ENTRY + RTI_MANAGED_IRQ_GATE + addl $4, %esp + + popl %es + popl %ds + popl %eax + popfl + + pushl $(0xef - 256) + SAVE_ALL_NOCFI + movl %esp, %eax + call smp_apic_timer_interrupt + jmp ret_from_intr + +rti_timer_bsp: + pushl $0xef + PF_IRQ_ENTRY + addl $4, %esp + + movl $0, RTI_APIC_REGISTER (APIC_EOI) + + popl %es + popl %ds + popl %eax + popfl + SAVE_ALL_NOCFI + cmpl $0, rti_timer_callback + je 1f + call *rti_timer_callback + +1: RESTORE_REGS_NOCFI + pushl $0xef + RESTORE_WRAP_PRIVILEGED_IRQ + addl $4, %esp + + cli +/* cmpl $0, rti_wbinvd_pending + je 2f + decl rti_wbinvd_pending + wbinvd +*/ +2: iret + +rti_irq_disable_rt: + cli + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + movl $0, rti_if (%ebp) + popl %ebp + popfl + + sti + ret + +rti_process_pending_irqs_nested: + cli + pushl %eax + pushl %ecx + pushl %edx + call rti_take_pending_irq_entry + popl %edx + popl %ecx + + cmpl $0, %eax + je 1f + + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + movl $0, rti_if (%ebp) + popl %ebp + popfl + + sti + pushfl + pushl %cs + call *%eax + popl %eax + + jmp rti_process_pending_irqs_nested + +1: popl %eax + ret + +rti_irq_enable_rt: + cli + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + movl $0, rti_if (%ebp) + popl %ebp + popfl + + call rti_process_pending_irqs_nested + + cli + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + movl $0x200, rti_if (%ebp) + popl %ebp + popfl + + sti + ret + +rti_safe_halt_rt: + cli + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + cmpl $RTI_NO_IRQ, rti_last_pending_irq (%ebp) + je rti_safe_halt_hlt + popl %ebp + popfl + + cli + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + movl $0, rti_if (%ebp) + popl %ebp + popfl + + call rti_process_pending_irqs_nested + + /* TODO CPU changed => process pending irqs again */ + cli + pushfl + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + movl $0x200, rti_if (%ebp) + popl %ebp + popfl + + sti + ret +rti_safe_halt_hlt: + movl $0x200, rti_if (%ebp) + popl %ebp + popfl + + sti + hlt + ret + +/* Return value in EAX */ +rti_save_flags_rt: + pushl %ebp + pushfl + cli + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + pushfl + popl %eax + andl $0xfffffdff, %eax + orl rti_if (%ebp), %eax + popfl + popl %ebp + ret + +/* Parameter in EAX */ +rti_irq_restore_rt: + pushfl + andl $0x200, %eax + cmpl $0, %eax + je 1f + popfl + call rti_irq_enable_rt + jmp 2f +1: popfl + call rti_irq_disable_rt +2: sti + ret + +/* TODO Naive on/off switching is unsafe, especially on SMP systems. */ + +ENTRY (rti_switch_rt_on) + pushfl + cli + + movl $1, rti_rt_on + + movl $rti_save_flags_rt , rti_save_flags_vptr + movl $rti_irq_restore_rt , rti_irq_restore_vptr + movl $rti_irq_disable_rt , rti_irq_disable_vptr + movl $rti_irq_enable_rt , rti_irq_enable_vptr + movl $rti_safe_halt_rt , rti_safe_halt_vptr + + movl $rti_gate_rt , rti_gate_vptr + movl $rti_managed_gate_rt , rti_managed_gate_vptr + movl $rti_iret_rt , rti_iret_vptr + + popfl + ret + +ENTRY (rti_switch_rt_off) + pushfl + cli + + movl $rti_save_flags_nonrt , rti_save_flags_vptr + movl $rti_irq_restore_nonrt , rti_irq_restore_vptr + movl $rti_irq_disable_nonrt , rti_irq_disable_vptr + movl $rti_irq_enable_nonrt , rti_irq_enable_vptr + movl $rti_safe_halt_nonrt , rti_safe_halt_vptr + + movl $rti_gate_nonrt , rti_gate_vptr + movl $rti_managed_gate_nonrt , rti_managed_gate_vptr + movl $rti_iret_nonrt , rti_iret_vptr + + movl $0, rti_rt_on + + popfl + ret + +ENTRY (rti_save_flags) + call *%cs:rti_save_flags_vptr + ret +ENTRY (rti_irq_restore) + call *%cs:rti_irq_restore_vptr + ret +ENTRY (rti_irq_disable) + call *%cs:rti_irq_disable_vptr + ret +ENTRY (rti_irq_enable) + call *%cs:rti_irq_enable_vptr + ret +ENTRY (rti_safe_halt) + call *%cs:rti_safe_halt_vptr + ret + +rti_iret: + call *%cs:rti_iret_vptr + ret + +rti_gate_rt: + pushl %ebp + pushl %ebx + cli + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + + /* Stack layout: + * +--------+ + * 44 | EFLAGS |\ + * 40 | CS | } interrupt gate + * 36 | EIP |/ + * 32 | EFLAGS |\ + * 28 | EAX | \ + * 24 | DS | } WRAP_IRQ_GATE + * 20 | ES | / + * 16 | vector |/ + * 12 | type | + * 8 | EIP | _vptr call + * 4 | EBP |\ + * 0 | EBX | } this function + * |--------| + * v v + * + * 'type' values: + * 0 - interrupt gate + * 2 - interrupt gate with an error code + * 1 - trap gate + * 3 - trap gate with an error code + * + * (type & 1) is 1 if it's a trap gate; + * (type & 2) is 1 if there is an error code on the stack. + */ + + testl $2, 12 (%esp) /* type */ + jz 1f + movl $4, %ebx + jmp 2f +1: xorl %ebx, %ebx +2: + movl 44 (%esp, %ebx), %eax /* EFLAGS */ + andl $0xfffffdff, %eax + orl rti_if (%ebp), %eax + movl %eax, 44 (%esp, %ebx) /* EFLAGS */ + + testl $1, 12 (%esp) /* type */ + jnz 1f + movl $0, rti_if (%ebp) +1: + sti + popl %ebx + popl %ebp + ret + +rti_managed_gate_rt: + cli + + /* Stack layout: + * +--------+ + * 36 | EFLAGS |\ + * 32 | CS | } interrupt gate + * 28 | EIP |/ + * 24 | EFLAGS |\ + * 20 | EAX | \ + * 16 | DS | } WRAP_IRQ_GATE + * 12 | ES | / + * 8 | vector |/ + * 4 | type | + * 0 | EIP | _vptr call + * |--------| + * v v + * + * 'type' values: + * 0 - interrupt gate + * 1 - interrupt gate with no ACK to Local APIC required + * 2 - interrupt gate for an external source + * 4 - trap gate + * 5 - trap gate with no ACK to Local APIC required + * 6 - trap gate for an external source + * + * (type & 3) is: 0 for a "usual" gate, + * 1 for a gate with no ACK to Local APIC required, + * 2 for a gate for an external source; + * (type & 4) is 1 if it's a trap gate. + */ + + movl 4 (%esp), %eax /* type */ + andl $3, %eax + cmpl $0, %eax + je rti_managed_gate_rt_usual + cmpl $1, %eax + je rti_managed_gate_rt_noack + +rti_managed_gate_rt_ext: + SDBG_SEND_CHAR (e, rti_managed_gate_rt_ext) + + /* Check for a bit in TMR: + * only level-triggered interrupts are those of interest */ + movl 8 (%esp), %eax /* vector */ + andl $0xff, %eax + pushl %ebx + + pushl %eax + shrl $5, %eax + shll $4, %eax + movl RTI_APIC_REGISTER (APIC_TMR) (%eax), %ebx + popl %eax + + pushl %eax + andl $0x1f, %eax + pushl %ecx + movl %eax, %ecx + shrl %cl, %ebx + popl %ecx + popl %eax + + andl $1, %ebx + cmpl $1, %ebx + popl %ebx + jne rti_managed_gate_rt_noack + + /* This is a level-triggered interrupt */ + /* Saving C-clobbered registers */ + pushl %ecx + pushl %edx + cmpl $1, rti_io_apic_enabled + jne 2f + + /* Acknowledge IO-APIC interrupt */ + shll $2, %eax + movl rti_vector_irq (%eax), %eax + pushl %eax + call mask_IO_APIC_irq + jmp 3f + +2: /* Acknowlefge 8259A PIC interrupt */ + subl $FIRST_EXTERNAL_VECTOR, %eax + pushl %eax + call disable_8259A_irq + +3: addl $4, %esp + popl %edx + popl %ecx + jmp rti_managed_gate_rt_noack + +rti_managed_gate_rt_usual: + SDBG_SEND_CHAR (u, rti_managed_gate_rt_usual) + movl $0, RTI_APIC_REGISTER (APIC_EOI) + +rti_managed_gate_rt_noack: + SDBG_SEND_CHAR (n, rti_managed_gate_rt_noack) + pushl %ebp + GET_THREAD_INFO (%ebp) + movl TI_cpu (%ebp), %ebp + shll $2, %ebp + + movl 40 (%esp), %eax /* EFLAGS, 36 + 4 */ + andl $0xfffffdff, %eax + orl rti_if (%ebp), %eax + movl %eax, 40 (%esp) /* EFLAGS, 36 + 4 */ + + cmpl $0, rti_if (%ebp) + jne 1f + movl 12 (%esp), %eax /* vector, 8 + 4 */ + + pushl %ecx + pushl %edx + pushl %eax + call rti_add_pending_irq + addl $4, %esp + popl %edx + popl %ecx + + popl %ebp + addl $12, %esp /* EIP, type, vector */ + popl %es + popl %ds + popl %eax + orl $0x200, 12 (%esp) /* Set IF on the stack to 1 (EFLAGS) */ + /* TODO No need to do pushfl after entering a gate! */ + andl $~0x200, (%esp) /* Avoiding nested interrupts */ + popfl + iret + +1: testl $4, 8 (%esp) /* type, 4 + 4 */ + jnz 2f + movl $0, rti_if (%ebp) +2: movl 12 (%esp), %eax /* vector, 8 + 4 */ + + pushl %ecx + pushl %edx + pushl %eax + call rti_unset_pending_irq + addl $4, %esp + popl %edx + popl %ecx + + sti + popl %ebp + ret + + /* 16 bytes are pushed in the beginning of RESTORE_WRAP_IRQ + * 8 more bytes for a _vptr call + * then come: + * vector (offset 24) + * EIP (offset 28) + * CS (offset 32) + * EFLAGS (offset 36) */ +rti_iret_rt: + cli + movl 36 (%esp), %eax # EFLAGS + andl $0x200, %eax + cmpl $0, %eax + je 1f + + /* TODO Interrupt emulation could be done without + * nesting interrupts. */ + call rti_irq_enable_rt + jmp 2f + +1: call rti_irq_disable_rt + +2: orl $0x200, 36 (%esp) # EFLAGS + ret + +#define RTI_ACTIVATE_USERSPACE \ + pushl %eax; \ + pushl %ecx; \ + pushl %edx; \ + call rti_activate_userspace; \ + popl %edx; \ + popl %ecx; \ + popl %eax; + +#else /* !CONFIG_RTI */ + +#define rti_cli cli +#define rti_sti sti + +#define RTI_IRQ_GATE +#define RTI_IRQ_GATE_EC +#define RTI_MANAGED_IRQ_GATE +#define RTI_MANAGED_IRQ_NOACK +#define RTI_MANAGED_IRQ_EXT +#define RTI_TRAP_GATE +#define RTI_TRAP_GATE_EC +#define RTI_MANAGED_TRAP_GATE +#define RTI_MANAGED_TRAP_NOACK +#define RTI_MANAGED_TRAP_EXT +#define RTI_IRET + +#define RTI_ACTIVATE_USERSPACE + +#endif /* CONFIG_RTI */ + diff -urN linux-2.6.19/arch/i386/kernel/sdebug.c linux-2.6.19-mync/arch/i386/kernel/sdebug.c --- linux-2.6.19/arch/i386/kernel/sdebug.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/sdebug.c 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,85 @@ +#include +#include + +#include + +#include +#include + +/* 0x3 means COM1, 0x2 for COM2*/ +#define PORT(a) 0x3 ## a + +/* Example of seial port setup on a receiving machine: + * setserial /dev/ttyS0 baud_base 38400 + */ + +union port_mode { + struct { + unsigned char + len : 2, /* word length */ + stop : 1, /* stop bits */ + parity : 2, /* parity */ + fix_parity : 1, /* parity fixation */ + set_break : 1, /* break */ + div_load : 1; /* divisor loading */ + }; + + unsigned char mode; /* the whole register */ +}; + +void sdbg_init(void) +{ + union port_mode mode; + unsigned short div = 4; + char ctl; + + /* frequency divisor setup */ + ctl = inb(PORT(fb)); + outb(ctl | 0x80, PORT(fb)); + outb((char)((div >> 8) & 0xff), PORT(f9)); + outb((char)(div & 0xff), PORT(f8)); + mode.len = 3; /* 8 data bits */ + mode.stop = 0; /* 1 stop bit */ + mode.parity = 0; /* no parity control */ + mode.fix_parity = 0; + mode.set_break = 0; + mode.div_load = 0; + outb(0, PORT(f9)); /* disable interrupts */ + outb(mode.mode, PORT(fb)); /* port mode setup*/ + /* FIFO initialization: + * use FIFO and report on 8 bytes */ + outb(0x81, PORT(fa)); +} + +static void sdbg_send_byte(char byte) +{ + while(!(inb(PORT(fd)) & 0x20)); + outb(byte, PORT(f8)); +} + +static void sdbg_send_data(char *buf, int len) +{ + int i; + + for(i = 0; i < len; i++) + sdbg_send_byte(buf[i]); +} + +void sdbg_printf(const char *fmt, ...) +{ + va_list args; + int i; + static char buf[1024]; + unsigned long flags; + + local_irq_save(flags); + va_start(args, fmt); + i = vscnprintf(buf, sizeof buf, fmt, args); + va_end(args); + sdbg_send_data(buf, i); + local_irq_restore(flags); +} + +EXPORT_SYMBOL(sdbg_init); +EXPORT_SYMBOL(sdbg_printf); + diff -urN linux-2.6.19/arch/i386/kernel/traps.c linux-2.6.19-mync/arch/i386/kernel/traps.c --- linux-2.6.19/arch/i386/kernel/traps.c 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/traps.c 2007-01-28 15:47:32.000000000 +0300 @@ -1181,6 +1181,7 @@ } #endif +#ifndef CONFIG_WRAP_IRQ /* * This needs to use 'idt_table' rather than 'idt', and * thus use the _nonmapped_ version of the IDT, as the @@ -1210,6 +1211,46 @@ _set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS); } +#define rti_set_privileged_intr_gate(n, addr) set_intr_gate (n, addr) + +#else +void* wrap_irq_interrupt_entry_points [256]; + +extern void (*wrap_irq_interrupt [256]) (void); +extern void (*wrap_irq_trap [256]) (void); + +void set_intr_gate (unsigned int n, void *addr) +{ + wrap_irq_interrupt_entry_points [n] = addr; + _set_gate(n, DESCTYPE_INT, wrap_irq_interrupt [n], __KERNEL_CS); +} + +void rti_set_privileged_intr_gate (unsigned int n, void *addr) +{ + _set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS); +} + +static inline void set_system_intr_gate (unsigned int n, void *addr) +{ + wrap_irq_interrupt_entry_points [n] = addr; + _set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, wrap_irq_interrupt [n], __KERNEL_CS); +} + +static void __init set_trap_gate (unsigned int n, void *addr) +{ + wrap_irq_interrupt_entry_points [n] = addr; + _set_gate(n, DESCTYPE_TRAP, wrap_irq_trap [n], __KERNEL_CS); +} + +static void __init set_system_gate (unsigned int n, void *addr) +{ + wrap_irq_interrupt_entry_points [n] = addr; + _set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, wrap_irq_trap [n], __KERNEL_CS); +} + +unsigned long rti_io_apic_enabled = 0; +#endif /* CONFIG_WRAP_IRQ */ + static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) { _set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3)); @@ -1232,7 +1273,9 @@ set_trap_gate(0,÷_error); set_intr_gate(1,&debug); +#ifndef CONFIG_RTI set_intr_gate(2,&nmi); +#endif set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ set_system_gate(4,&overflow); set_trap_gate(5,&bounds); diff -urN linux-2.6.19/arch/i386/kernel/wrap_irq.inc.S linux-2.6.19-mync/arch/i386/kernel/wrap_irq.inc.S --- linux-2.6.19/arch/i386/kernel/wrap_irq.inc.S 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/kernel/wrap_irq.inc.S 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,276 @@ +#define SAVE_ALL_NOCFI \ + cld; \ + pushl %es; \ + pushl %ds; \ + pushl %eax; \ + pushl %ebp; \ + pushl %edi; \ + pushl %esi; \ + pushl %edx; \ + pushl %ecx; \ + pushl %ebx; \ + movl $(__USER_DS), %edx;\ + movl %edx, %ds; \ + movl %edx, %es; + +#define RESTORE_INT_REGS_NOCFI \ + popl %ebx; \ + popl %ecx; \ + popl %edx; \ + popl %esi; \ + popl %edi; \ + popl %ebp; \ + popl %eax; + +#define RESTORE_REGS_NOCFI \ + RESTORE_INT_REGS_NOCFI \ +1: popl %ds; \ +2: popl %es; \ +.section .fixup,"ax"; \ +3: movl $0,(%esp); \ + jmp 1b; \ +4: movl $0,(%esp); \ + jmp 2b; \ +.previous; \ +.section __ex_table,"a"; \ + .align 4; \ + .long 1b,3b; \ + .long 2b,4b; \ +.previous + +#include "pf.inc.S" + +#if 0 +#define RTI_TRAP_GATE +#define RTI_TRAP_GATE_EC +#define RTI_IRQ_GATE +#define RTI_IRQ_GATE_EC +#define RTI_MANAGED_IRQ_GATE +#define RTI_MANAGED_IRQ_EXT +#define RTI_MANAGED_IRQ_NOACK +#define RTI_MANAGED_TRAP_NOACK +#endif + +#ifdef CONFIG_WRAP_IRQ + /* TODO Just test WRAP_IRQ with 16-bit code in the background + * and say it is fine */ +#define WRAP_IRQ_FORBIDDEN \ + cli; \ + pushl $wrap_irq_forbidden_fs; \ + call printk; \ + DEBUG_BEEP; \ +1: jmp 1b + + /* This block is better be finished without interrupts + * to save stack space */ + /* The interrupts are guaranteed to be disabled + * after RESTORE_WRAP_IRQ */ + /* Pushes 16 bytes on the stack, plus 4 bytes for + * an interrupt vector, totals to 20 bytes */ +#define RESTORE_WRAP_PRIVILEGED_IRQ \ + pushfl; \ + pushl %eax; \ + pushl %ds; \ + pushl %es; \ + \ + movl $(__USER_DS), %eax; \ + movl %eax, %ds; \ + movl %eax, %es; \ + \ + PF_IRET; \ + \ + popl %es; \ + popl %ds; \ + popl %eax; \ + popfl + +#define RESTORE_WRAP_IRQ \ + pushfl; \ + andl $~0x200, (%esp); \ + pushl %eax; \ + pushl %ds; \ + pushl %es; \ + \ + movl $(__USER_DS), %eax; \ + movl %eax, %ds; \ + movl %eax, %es; \ + \ + PF_IRET; \ + RTI_IRET; \ + \ + popl %es; \ + popl %ds; \ + popl %eax; \ + popfl +#else +#define WRAP_IRQ_FORBIDDEN +#define RESTORE_WRAP_IRQ +#endif /* CONFIG_WRAP_IRQ */ + +#include "rti.inc.S" + +#ifdef CONFIG_WRAP_IRQ +.data +wrap_irq_forbidden_fs: + .string "Forbidden irq wrapper's execution path\n" +.previous + + +/* EFLAGS and EAX may be used freely inside entrance handlers. */ +#define WRAP_IRQ_GATE_EARLY_ENTRANCE \ + pushfl; \ + pushl %eax; \ + pushl %ds; \ + pushl %es; \ + \ + movl $(__USER_DS), %eax; \ + movl %eax, %ds; \ + movl %eax, %es + +/* entrance_code starts with 20 additional bytes on the stack. */ +#define WRAP_IRQ_GATE(entrance_code) \ + ALIGN; \ +1: WRAP_IRQ_GATE_EARLY_ENTRANCE; \ + pushl $vector; \ + PF_IRQ_ENTRY; \ + entrance_code; \ + jmp wrap_irq_common_interrupt; \ +.data; \ + .long 1b; \ +.previous; \ +vector = vector + 1 + +.data +ENTRY (wrap_irq_interrupt) +.text +ALIGN +wrap_irq_interrupt_text: +vector = 0 +.rept 2 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 0-1 +.endr + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_NOACK) # 2 (NMI) +.rept 5 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 3-7 +.endr + WRAP_IRQ_GATE (RTI_IRQ_GATE_EC) # 8 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 9 +.rept 5 + WRAP_IRQ_GATE (RTI_IRQ_GATE_EC) # 10-14 +.endr + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 15 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 16 + WRAP_IRQ_GATE (RTI_IRQ_GATE_EC) # 17 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 18 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 19 +.rept 12 + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 20-31 +.endr +.rept 96 + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_EXT) # 32-127 +.endr + WRAP_IRQ_GATE (RTI_IRQ_GATE) # 128 (syscall) +.rept 110 + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_EXT) # 129-238 +.endr + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_GATE) # 239 (local APIC timer) +.rep 10 + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_GATE) # 240-249 +.endr +.rept 6 + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_GATE) # 250-254 +.endr + WRAP_IRQ_GATE (RTI_MANAGED_IRQ_NOACK) # Spurious vector + +.data +ENTRY (wrap_irq_trap) +.text +ALIGN +wrap_irq_trap_text: +vector = 0 +.rept 2 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 0-1 +.endr + WRAP_IRQ_GATE (RTI_MANAGED_TRAP_NOACK) # 2 (NMI) +.rept 5 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 3-7 +.endr + WRAP_IRQ_GATE (RTI_TRAP_GATE_EC) # 8 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 9 +.rept 5 + WRAP_IRQ_GATE (RTI_TRAP_GATE_EC) # 10-14 +.endr + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 15 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 16 + WRAP_IRQ_GATE (RTI_TRAP_GATE_EC) # 17 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 18 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 19 +.rept 12 + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 20-31 +.endr +.rept 96 +# TSYSCALL WRAP_IRQ_GATE (RTI_MANAGED_TRAP_EXT) # 32-127 + WRAP_IRQ_GATE (RTI_TRAP_GATE) +.endr + WRAP_IRQ_GATE (RTI_TRAP_GATE) # 128 (syscall) +.rept 110 +# TSYSCALL WRAP_IRQ_GATE (RTI_MANAGED_TRAP_EXT) # 129-238 + WRAP_IRQ_GATE (RTI_TRAP_GATE) +.endr +# TSYSCALL WRAP_IRQ_GATE (RTI_MANAGED_TRAP_GATE) # 239 (local APIC timer) + WRAP_IRQ_GATE (RTI_TRAP_GATE) +.rep 10 +# TSYSCALL WRAP_IRQ_GATE (RTI_MANAGED_TRAP_GATE) # 240-249 + WRAP_IRQ_GATE (RTI_TRAP_GATE) +.endr +.rept 6 +# TSYSCALL WRAP_IRQ_GATE (RTI_MANAGED_IRQ_GATE) # 250-254 + WRAP_IRQ_GATE (RTI_TRAP_GATE) +.endr + WRAP_IRQ_GATE (RTI_MANAGED_TRAP_NOACK) # Spurious vector + + ALIGN +wrap_irq_common_interrupt: + movl (%esp), %eax + shll $2, %eax + addl $wrap_irq_interrupt_entry_points, %eax + movl (%eax), %eax + + addl $4, %esp + popl %es + + testl $IF_MASK, 8 (%esp) + jz wrap_irq_if_cleared_entry + + # sti shadows the next instruction from being interrupted. + # We're saved. Let's pray for this. + +1: // xorl $IF_MASK, 8 (%esp) + andl $(~IF_MASK), 8 (%esp) + cli + popl %ds + pushl %eax + movl /*%cs:*/ 8 (%esp), %eax + pushl %eax + popfl + popl %eax + movl %eax, /*%cs:*/ 4 (%esp) + popl %eax + sti + ret + +wrap_irq_if_cleared_entry: +// TEST!! rti_cli +// Irrelevant (non-rt path) + cli + popl %ds + pushl %eax + movl /*%cs:*/ 8 (%esp), %eax + pushl %eax + popfl + popl %eax + movl %eax, /*%cs:*/ 4 (%esp) + popl %eax + ret +#endif /* CONFIG_WRAP_IRQ */ + diff -urN linux-2.6.19/arch/i386/Makefile linux-2.6.19-mync/arch/i386/Makefile --- linux-2.6.19/arch/i386/Makefile 2007-01-28 15:40:45.000000000 +0300 +++ linux-2.6.19-mync/arch/i386/Makefile 2007-01-28 15:47:51.000000000 +0300 @@ -29,7 +29,7 @@ LDFLAGS_vmlinux := CHECKFLAGS += -D__i386__ -CFLAGS += -pipe -msoft-float +CFLAGS += -pipe -fno-stack-protector #-msoft-float # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2) diff -urN linux-2.6.19/drivers/char/Makefile linux-2.6.19-mync/drivers/char/Makefile --- linux-2.6.19/drivers/char/Makefile 2007-01-28 15:40:51.000000000 +0300 +++ linux-2.6.19-mync/drivers/char/Makefile 2007-01-28 15:47:32.000000000 +0300 @@ -90,6 +90,7 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_TANBAC_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o +obj-$(CONFIG_PF) += pf.o obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ diff -urN linux-2.6.19/drivers/char/pf.c linux-2.6.19-mync/drivers/char/pf.c --- linux-2.6.19/drivers/char/pf.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/drivers/char/pf.c 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PF_IOC_MAGIC 0xef + +#define PF_IOC_START _IO (PF_IOC_MAGIC, 0) +#define PF_IOC_STOP _IO (PF_IOC_MAGIC, 1) +#define PF_IOC_RESET _IO (PF_IOC_MAGIC, 2) + +struct pf_dev { + struct cdev cdev; + dev_t dev; +}; + +static struct pf_dev pf_dev; +static int pf_major; +static int pf_minor; + +static struct class *pf_class; + +static int pf_open (struct inode *inode, + struct file *filp); +static int pf_release (struct inode *inode, + struct file *filp); +static ssize_t pf_read (struct file *filp, + char __user *buf, + size_t count, + loff_t *f_pos); +static int pf_mmap (struct file *filp, + struct vm_area_struct *vma); +static int pf_ioctl (struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg); + +struct file_operations pf_fops = { + .owner = THIS_MODULE, + .read = pf_read, + .mmap = pf_mmap, + .ioctl = pf_ioctl, + .open = pf_open, + .release = pf_release, +}; + +static struct page* pf_vma_nopage (struct vm_area_struct *vma, + unsigned long address, + int *type); + +static void +pf_vma_open (struct vm_area_struct *vma) +{ +} + +static void +pf_vma_close (struct vm_area_struct *vma) +{ +} + +struct vm_operations_struct pf_vm_ops = { + .open = pf_vma_open, + .close = pf_vma_close, + .nopage = pf_vma_nopage, +}; + +static ssize_t +pf_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + unsigned long offset = (unsigned long) *f_pos; + unsigned long realCount; + + if (offset > pf_trace_size) + return 0; + + if ((unsigned long) pf_trace_buffer + offset < + (unsigned long) pf_trace_buffer) + return -EINVAL; + + if ((unsigned long) pf_trace_buffer + offset + count < + (unsigned long) pf_trace_buffer + offset || + (unsigned long) pf_trace_buffer + offset + count > + (unsigned long) pf_trace_buffer + pf_trace_size) + realCount = pf_trace_size - offset; + else + realCount = count; + + if (copy_to_user (buf, + (void*) (pf_trace_buffer + offset), + realCount)) + return -EFAULT; + + *f_pos += realCount; + + return realCount; +} + +static struct page* +pf_vma_nopage (struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + unsigned long real_addr; + struct page *page; + + /* TODO Exclude the guard page at the end */ + + real_addr = address - vma->vm_start + + (vma->vm_pgoff << PAGE_SHIFT); + if (real_addr > (1 << CONFIG_PF_BUFFER_ORDER << PAGE_SHIFT)) + return NOPAGE_SIGBUS; + + real_addr += (unsigned long) pf_trace_buffer; + + page = virt_to_page (real_addr); + get_page (page); + + if (type != NULL) + *type = VM_FAULT_MINOR; + + return page; +} + +static int +pf_mmap (struct file *filp, struct vm_area_struct *vma) +{ + vma->vm_ops = &pf_vm_ops; + vma->vm_flags |= VM_RESERVED; + vma->vm_private_data = filp->private_data; + return 0; +} + +static int +pf_ioctl (struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case PF_IOC_START: + pf_trace_info->enabled = 1; + return 0; + case PF_IOC_STOP: + pf_trace_info->enabled = 0; + return 0; + case PF_IOC_RESET: + pf_clear_trace_buffer (); + return 0; + default: + return -ENOTTY; + }; +} + +static int +pf_open (struct inode *inode, struct file *filp) +{ + struct pf_dev *dev; + + dev = container_of (inode->i_cdev, struct pf_dev, cdev); + filp->private_data = dev; + + i_size_write (inode, pf_trace_size); + printk ("i_size: %lu\n", (unsigned long) i_size_read (inode)); + + return 0; +} + +static int +pf_release (struct inode *inode, struct file *filp) +{ + return 0; +} + +static void +pf_setup_cdev (struct pf_dev *dev, int index) +{ + int err; + int devno; + + devno = MKDEV (pf_major, pf_minor + index); + + cdev_init (&dev->cdev, &pf_fops); + dev->cdev.owner = THIS_MODULE; + err = cdev_add (&dev->cdev, devno, 1); + if (err) + printk (KERN_NOTICE "Error %d adding pf%d\n", err, index); +} + +static void +pf_cleanup_cdev (struct pf_dev *dev) +{ + cdev_del (&dev->cdev); +} + +static int +pf_init_devnumbers (struct pf_dev *dev) +{ + int res; + + if (pf_major) { + dev->dev = MKDEV (pf_major, pf_minor); + res = register_chrdev_region (dev->dev, 1, "pf"); + } else { + res = alloc_chrdev_region (&dev->dev, pf_minor, 1, "pf"); + pf_major = MAJOR (dev->dev); + } + + if (res < 0) { + printk (KERN_WARNING "Pf: can't get major %d\n", pf_major); + return res; + } + + class_device_create (pf_class, NULL, MKDEV (pf_major, pf_minor), NULL, + "pf%d", pf_minor); + + printk ("Pf: major %d, minor %d\n", pf_major, pf_minor); + + return 0; +} + +static void +pf_cleanup_devnumbers (struct pf_dev *dev) +{ + class_device_destroy (pf_class, dev->dev); + unregister_chrdev_region (dev->dev, 1); +} + +static int __init pf_dev_init (void) +{ + int res; + + if (pf_trace_buffer == NULL) { + printk ("Pf: NULL trace buffer!\n"); + return -EFAULT; + } + + pf_class = class_create (THIS_MODULE, "pf"); + if (IS_ERR (pf_class)) { + printk (KERN_ERR "Pf: error creating pf class\n"); + return -EFAULT; + } + + res = pf_init_devnumbers (&pf_dev); + if (res < 0) + return res; + + pf_setup_cdev (&pf_dev, 0); + + return 0; +} + +static void __exit pf_dev_exit (void) +{ + pf_cleanup_cdev (&pf_dev); + pf_cleanup_devnumbers (&pf_dev); + + class_device_destroy (pf_class, MKDEV (pf_major, pf_minor)); + class_destroy (pf_class); +} + +module_init (pf_dev_init) +module_exit (pf_dev_exit) + +MODULE_AUTHOR ("Dmitry M. Shatrov"); +MODULE_DESCRIPTION ("Pf interface module"); +MODULE_LICENSE ("GPL"); + diff -urN linux-2.6.19/include/asm-i386/apicdef.h linux-2.6.19-mync/include/asm-i386/apicdef.h --- linux-2.6.19/include/asm-i386/apicdef.h 2007-01-28 15:39:55.000000000 +0300 +++ linux-2.6.19-mync/include/asm-i386/apicdef.h 2007-01-28 15:47:32.000000000 +0300 @@ -109,6 +109,8 @@ #define APIC_TDR_DIV_64 0x9 #define APIC_TDR_DIV_128 0xA +#ifndef __ASSEMBLY__ + #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) #define MAX_IO_APICS 64 @@ -372,4 +374,5 @@ #undef u32 +#endif /* __ASSEMBLY__ */ #endif diff -urN linux-2.6.19/include/asm-i386/apic.h linux-2.6.19-mync/include/asm-i386/apic.h --- linux-2.6.19/include/asm-i386/apic.h 2007-01-28 15:41:06.000000000 +0300 +++ linux-2.6.19-mync/include/asm-i386/apic.h 2007-01-28 15:47:32.000000000 +0300 @@ -71,6 +71,10 @@ # define apic_write_around(x,y) apic_write_atomic((x),(y)) #endif +#ifdef CONIFG_RTI +extern unsigned long rti_rt_on; +#endif + static inline void ack_APIC_irq(void) { /* @@ -81,7 +85,12 @@ */ /* Docs say use 0 for future compatibility */ +#ifndef CONFIG_RTI + if (rti_rt_on == 0) + apic_write_around(APIC_EOI, 0); +#else apic_write_around(APIC_EOI, 0); +#endif } extern void (*wait_timer_tick)(void); diff -urN linux-2.6.19/include/asm-i386/irqflags.h linux-2.6.19-mync/include/asm-i386/irqflags.h --- linux-2.6.19/include/asm-i386/irqflags.h 2007-01-28 15:39:55.000000000 +0300 +++ linux-2.6.19-mync/include/asm-i386/irqflags.h 2007-01-28 15:47:32.000000000 +0300 @@ -12,6 +12,43 @@ #ifndef __ASSEMBLY__ +#ifndef CONFIG_RTI +#define direct_irq_disable() local_irq_disable() +#define direct_irq_enable() local_irq_enable() +#define direct_save_flags(x) local_save_flags(x) +#define direct_irq_save(x) local_irq_save(x) +#define direct_irq_restore(x) local_irq_restore(x) +#else +#define direct_save_flags(x) \ + do { \ + typecheck (unsigned long, x); \ + __asm__ __volatile__ ( \ + "pushfl; popl %0" \ + : "=g" (x) : : \ + "memory"); \ + } while (0) +#define direct_irq_restore(x) \ + do { \ + typecheck (unsigned long, x); \ + __asm__ __volatile__ ( \ + "pushl %0; popfl" \ + : : "g" (x) : \ + "cc"); \ + } while (0) +#define direct_irq_disable() __asm__ __volatile__ ("cli") +#define direct_irq_enable() __asm__ __volatile__ ("sti") +#define direct_irq_save(x) \ + __asm__ __volatile__ ( \ + "pushfl; popl %0; cli" \ + : "=g" (x) : : \ + "memory") + +extern void rti_irq_disable (void); +extern void rti_irq_enable (void); +extern void rti_safe_halt (void); +#endif + +#ifndef CONFIG_RTI static inline unsigned long __raw_local_save_flags(void) { unsigned long flags; @@ -24,38 +61,85 @@ return flags; } +#else +static inline unsigned long __raw_local_save_flags(void) +{ + unsigned long flags; + + __asm__ __volatile__ ( + "call rti_save_flags ;" + "movl %%eax, %0 ;" + : "=g" (flags) : + : "eax", "memory" + ); + + return flags; +} +#endif #define raw_local_save_flags(flags) \ do { (flags) = __raw_local_save_flags(); } while (0) +#ifndef CONFIG_RTI static inline void raw_local_irq_restore(unsigned long flags) { __asm__ __volatile__( "pushl %0 ; popfl" - : /* no output */ - :"g" (flags) + : : "g" (flags) :"memory", "cc" ); } +#else +static inline void raw_local_irq_restore(unsigned long flags) +{ + __asm__ __volatile__( + "movl %0, %%eax ;" + "call rti_irq_restore ;" + : : "g" (flags) + : "eax", "memory" + ); +} +#endif +#ifndef CONFIG_RTI static inline void raw_local_irq_disable(void) { __asm__ __volatile__("cli" : : : "memory"); } +#else +static inline void raw_local_irq_disable(void) +{ + rti_irq_disable (); +} +#endif +#ifndef CONFIG_RTI static inline void raw_local_irq_enable(void) { __asm__ __volatile__("sti" : : : "memory"); } +#else +static inline void raw_local_irq_enable(void) +{ + rti_irq_enable (); +} +#endif /* * Used in the idle loop; sti takes one instruction cycle * to complete: */ +#ifndef CONFIG_RTI static inline void raw_safe_halt(void) { __asm__ __volatile__("sti; hlt" : : : "memory"); } +#else +static inline void raw_safe_halt(void) +{ + rti_safe_halt (); +} +#endif /* * Used when interrupts are already enabled or to diff -urN linux-2.6.19/include/asm-i386/mach-default/do_timer.h linux-2.6.19-mync/include/asm-i386/mach-default/do_timer.h --- linux-2.6.19/include/asm-i386/mach-default/do_timer.h 2007-01-28 15:41:06.000000000 +0300 +++ linux-2.6.19-mync/include/asm-i386/mach-default/do_timer.h 2007-01-28 15:47:32.000000000 +0300 @@ -17,6 +17,9 @@ static inline void do_timer_interrupt_hook(void) { do_timer(1); +#ifdef CONFIG_RTI + smp_local_timer_interrupt (); +#else #ifndef CONFIG_SMP update_process_times(user_mode_vm(get_irq_regs())); #endif @@ -31,6 +34,7 @@ if (!using_apic_timer) smp_local_timer_interrupt(); #endif +#endif /* CONFIG_RTI */ } diff -urN linux-2.6.19/include/asm-i386/sdebug.h linux-2.6.19-mync/include/asm-i386/sdebug.h --- linux-2.6.19/include/asm-i386/sdebug.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/include/asm-i386/sdebug.h 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,40 @@ +#ifndef __ASM_I386_SDEBUG_H__ +#define __ASM_I386_SDEBUG_H__ + +#ifdef CONFIG_SDEBUG + +#define SDBG_SEND_CHAR(char, label) \ + pushl %eax; \ + pushl %edx; \ +label/**/_SDBG_SEND_CHAR: \ + movl $0x3fd, %edx; \ + inb %dx, %al; \ + andl $0x20, %eax; \ + jz label/**/_SDBG_SEND_CHAR; \ + movl $'char, %eax; \ + movl $0x3f8, %edx; \ + outb %al, %dx; \ + popl %edx; \ + popl %eax; + +#define SDBG_SEND_MEM(byte, label) \ + pushl %eax; \ + pushl %edx; \ +label/**/_SDBG_SEND_MEM: \ + movl $0x3fd, %edx; \ + inb %dx, %al; \ + andl $0x20, %eax; \ + jz label/**/_SDBG_SEND_MEM; \ + movb byte, %al; \ + movl $0x3f8, %edx; \ + outb %al, %dx; \ + popl %edx; \ + popl %eax; + +#else +#define SDBG_SEND_CHAR(char, label) +#define SDBG_SEND_MEM(char, label) +#endif + +#endif /* __ASM_I386_SDEBUG_H__ */ + diff -urN linux-2.6.19/include/asm-i386/spinlock.h linux-2.6.19-mync/include/asm-i386/spinlock.h --- linux-2.6.19/include/asm-i386/spinlock.h 2007-01-28 15:41:06.000000000 +0300 +++ linux-2.6.19-mync/include/asm-i386/spinlock.h 2007-01-28 15:47:32.000000000 +0300 @@ -7,8 +7,13 @@ #include #include +#ifndef CONFIG_RTI #define CLI_STRING "cli" #define STI_STRING "sti" +#else +#define CLI_STRING "call rti_irq_disable" +#define STI_STRING "call rti_irq_enable" +#endif /* * Your basic SMP spinlocks, allowing only a single CPU anywhere diff -urN linux-2.6.19/include/linux/mmzone.h linux-2.6.19-mync/include/linux/mmzone.h --- linux-2.6.19/include/linux/mmzone.h 2007-01-28 15:41:07.000000000 +0300 +++ linux-2.6.19-mync/include/linux/mmzone.h 2007-01-28 15:47:32.000000000 +0300 @@ -18,7 +18,7 @@ /* Free memory management - zoned buddy allocator. */ #ifndef CONFIG_FORCE_MAX_ZONEORDER -#define MAX_ORDER 11 +#define MAX_ORDER 15 #else #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER #endif diff -urN linux-2.6.19/include/linux/pf.h linux-2.6.19-mync/include/linux/pf.h --- linux-2.6.19/include/linux/pf.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/include/linux/pf.h 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,35 @@ +#ifndef __LINUX_PF_H__ +#define __LINUX_PF_H__ + +#define PF_MSGTYPE_INTERRUPT 7 +#define PF_MSGTYPE_IRET_TO_KERNEL 2 +#define PF_MSGTYPE_IRET_TO_USER 1 + +struct pf_trace_info { + unsigned long position; + unsigned long enabled; +} __attribute__ ((packed)); + +extern volatile struct pf_trace_info *pf_trace_info; + +extern volatile unsigned char *pf_trace_buffer; +extern unsigned long pf_trace_size; + +extern void pf_init (void); + +/* 'fromLen' is the size of 'from' buffer. + * 'to' buffer must be at least 2*len bytes long. + * Returns escaped message length. */ +extern +unsigned long pf_escape_message (unsigned char *to, + unsigned char *from, + unsigned long fromLen); + +/* This is the only symbol exported for kernel modules */ +extern void pf_trace_message (const char *message, + unsigned long length); + +extern void pf_clear_trace_buffer (void); + +#endif /* __LINUX_PF_H__ */ + diff -urN linux-2.6.19/include/linux/rti.h linux-2.6.19-mync/include/linux/rti.h --- linux-2.6.19/include/linux/rti.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/include/linux/rti.h 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,20 @@ +#ifndef __LINUX_RTI_H__ +#define __LINUX_RTI_H__ + +typedef void (*rti_userspace_activator_proc) (void); + +#ifdef CONFIG_RTI +extern void rti_set_userspace_activator (rti_userspace_activator_proc proc); +extern void rti_activate_userspace (void); +extern void rti_init (void); +extern void rti_stop (void); +#else +static inline void rti_set_userspace_activator ( + rti_userspace_activator_proc proc) {} +static inline void rti_activate_userspace (void) {} +static inline void rti_init (void) {} +static inline void rti_stop (void) {} +#endif + +#endif /* __LINUX_RTI_H__ */ + diff -urN linux-2.6.19/include/linux/sdebug.h linux-2.6.19-mync/include/linux/sdebug.h --- linux-2.6.19/include/linux/sdebug.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6.19-mync/include/linux/sdebug.h 2007-01-28 15:47:32.000000000 +0300 @@ -0,0 +1,15 @@ +#ifndef _ASM_SDEBUG_H +#define _ASM_SDEBUG_H + +#include + +#ifdef CONFIG_SDEBUG +extern void sdbg_init(void); +extern void sdbg_printf(const char *fmt, ...); +#else +static inline void sdbg_init(void) {} +static inline void sdbg_printf(const char *fmt, ...) {} +#endif + +#endif /* _ASM_SDEBUG_H */ + diff -urN linux-2.6.19/init/main.c linux-2.6.19-mync/init/main.c --- linux-2.6.19/init/main.c 2007-01-28 15:41:08.000000000 +0300 +++ linux-2.6.19-mync/init/main.c 2007-01-28 15:47:32.000000000 +0300 @@ -49,6 +49,9 @@ #include #include #include +#include +#include +#include #include #include @@ -502,6 +505,9 @@ page_address_init(); printk(KERN_NOTICE); printk(linux_banner); + + sdbg_init (); + setup_arch(&command_line); unwind_setup(); setup_per_cpu_areas(); @@ -604,6 +610,10 @@ check_bugs(); +#ifdef CONFIG_PF + pf_init (); +#endif + acpi_early_init(); /* before LAPIC and SMP init */ /* Do the rest non-__init'ed, we're now alive */ @@ -765,6 +775,9 @@ system_state = SYSTEM_RUNNING; numa_default_policy(); + printk ("Initializing RTI\n"); + rti_init (); + if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.\n");