diff -uNrp linux-2.4.31/adeos/generic.c linux-2.4.31-r18/adeos/generic.c --- linux-2.4.31/adeos/generic.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/adeos/generic.c 2005-06-02 23:24:31.000000000 +0200 @@ -0,0 +1,631 @@ +/* + * linux/adeos/generic.c + * + * Copyright (C) 2002 Philippe Gerum. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Architecture-independent ADEOS services. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Adeos nanokernel"); +MODULE_AUTHOR("Philippe Gerum"); +MODULE_LICENSE("GPL"); + +/* adeos_register_domain() -- Add a new domain to the system. All + client domains must call this routine to register themselves to + ADEOS before using its services. */ + +int adeos_register_domain (adomain_t *adp, adattr_t *attr) + +{ + struct list_head *pos; + unsigned long flags; + int n; + + if (adp_current != adp_root) + { + printk(KERN_WARNING "Adeos: Only the root domain may register a new domain.\n"); + return -EPERM; + } + + flags = adeos_critical_enter(NULL); + + list_for_each(pos,&__adeos_pipeline) { + adomain_t *_adp = list_entry(pos,adomain_t,p_link); + if (_adp->domid == attr->domid) + break; + } + + adeos_critical_exit(flags); + + if (pos != &__adeos_pipeline) + /* A domain with the given id already exists -- fail. */ + return -EBUSY; + + for (n = 0; n < ADEOS_NR_CPUS; n++) + adp->cpudata[n].status = 0; + + /* A special case for domains who won't process events (i.e. no + entry). We have to mark them as suspended so that + adeos_suspend_domain() won't consider them, unless they + _actually_ receive events, which would lead to a panic + situation since they have no stack context... :o> */ + + for (n = 0; n < ADEOS_NR_CPUS; n++) + { + set_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[n].status); + + if (attr->entry == NULL) + adp->estackbase[n] = NULL; + } + + adp->name = attr->name; + adp->priority = attr->priority; + adp->domid = attr->domid; + adp->dswitch = attr->dswitch; + adp->flags = 0; + adp->ptd_setfun = attr->ptdset; + adp->ptd_getfun = attr->ptdget; + adp->ptd_keymap = 0; + adp->ptd_keycount = 0; + adp->ptd_keymax = attr->nptdkeys; + + for (n = 0; n < ADEOS_NR_EVENTS; n++) + /* Event handlers must be cleared before the i-pipe stage is + inserted since an exception may occur on behalf of the new + emerging domain. */ + adp->events[n].handler = NULL; + + if (attr->entry != NULL) + __adeos_init_domain(adp,attr); + + /* Insert the domain in the interrupt pipeline last, so it won't + be resumed for processing interrupts until it has a valid stack + context. */ + + __adeos_init_stage(adp); + + INIT_LIST_HEAD(&adp->p_link); + + flags = adeos_critical_enter(NULL); + + list_for_each(pos,&__adeos_pipeline) { + adomain_t *_adp = list_entry(pos,adomain_t,p_link); + if (adp->priority > _adp->priority) + break; + } + + list_add_tail(&adp->p_link,pos); + + adeos_critical_exit(flags); + + printk(KERN_WARNING "Adeos: Domain %s registered.\n",adp->name); + + /* Finally, allow the new domain to perform its initialization + chores on behalf of its own stack context. */ + + if (attr->entry != NULL) + { + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + __adeos_switch_to(adp_root,adp,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status) && + adp_root->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + + adeos_unlock_cpu(flags); + } + + return 0; +} + +/* adeos_unregister_domain() -- Remove a domain from the system. All + client domains must call this routine to unregister themselves from + the ADEOS layer. */ + +int adeos_unregister_domain (adomain_t *adp) + +{ + unsigned long flags; + unsigned event; + + if (adp_current != adp_root) + { + printk(KERN_WARNING "Adeos: Only the root domain may unregister a domain.\n"); + return -EPERM; + } + + if (adp == adp_root) + { + printk(KERN_WARNING "Adeos: Cannot unregister the root domain.\n"); + return -EPERM; + } + + for (event = 0; event < ADEOS_NR_EVENTS; event++) + /* Need this to update the monitor count. */ + adeos_catch_event_from(adp,event,NULL); + +#ifdef CONFIG_SMP + { + unsigned irq; + int _cpuid; + + /* In the SMP case, wait for the logged events to drain on other + processors before eventually removing the domain from the + pipeline. */ + + adeos_unstall_pipeline_from(adp); + + flags = adeos_critical_enter(NULL); + + for (irq = 0; irq < IPIPE_NR_IRQS; irq++) + { + clear_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control); + clear_bit(IPIPE_STICKY_FLAG,&adp->irqs[irq].control); + set_bit(IPIPE_PASS_FLAG,&adp->irqs[irq].control); + } + + adeos_critical_exit(flags); + + for (_cpuid = 0; _cpuid < smp_num_cpus; _cpuid++) + { + for (irq = 0; irq < IPIPE_NR_IRQS; irq++) + while (adp->cpudata[_cpuid].irq_hits[irq] > 0) + cpu_relax(); + + while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status)) + cpu_relax(); + + while (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[_cpuid].status)) + cpu_relax(); + } + } +#endif /* CONFIG_SMP */ + + /* Simply remove the domain from the pipeline and we are almost + done. */ + + flags = adeos_critical_enter(NULL); + list_del_init(&adp->p_link); + adeos_critical_exit(flags); + + __adeos_cleanup_domain(adp); + + printk(KERN_WARNING "Adeos: Domain %s unregistered.\n",adp->name); + + return 0; +} + +int __adeos_schedule_irq (unsigned irq, struct list_head *head) + +{ + struct list_head *ln; + unsigned long flags; + adeos_declare_cpuid; + + if (irq >= IPIPE_NR_IRQS || + (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map))) + return -EINVAL; + + adeos_lock_cpu(flags); + + ln = head; + + while (ln != &__adeos_pipeline) + { + adomain_t *adp = list_entry(ln,adomain_t,p_link); + + if (test_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control)) + { + adp->cpudata[cpuid].irq_hits[irq]++; + __adeos_set_irq_bit(adp,cpuid,irq); + adeos_unlock_cpu(flags); + return 1; + } + + ln = adp->p_link.next; + } + + adeos_unlock_cpu(flags); + + return 0; +} + +/* adeos_propagate_irq() -- Force a given IRQ propagation on behalf of + a running interrupt handler to the next domain down the pipeline. + Returns non-zero if a domain has received the interrupt + notification, zero otherwise. + This call is useful for handling shared interrupts among domains. + e.g. pipeline = [domain-A]---[domain-B]... + Both domains share IRQ #X. + - domain-A handles IRQ #X but does not pass it down (i.e. Terminate + or Dynamic interrupt control mode) + - domain-B handles IRQ #X (i.e. Terminate or Accept interrupt + control modes). + When IRQ #X is raised, domain-A's handler determines whether it + should process the interrupt by identifying its source. If not, + adeos_propagate_irq() is called so that the next domain down the + pipeline which handles IRQ #X is given a chance to process it. This + process can be repeated until the end of the pipeline is + reached. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +int fastcall adeos_propagate_irq (unsigned irq) { +#else /* LINUX_VERSION_CODE < 2.4.27 */ +int adeos_propagate_irq (unsigned irq) { +#endif + + return __adeos_schedule_irq(irq,adp_current->p_link.next); +} + +/* adeos_schedule_irq() -- Almost the same as adeos_propagate_irq(), + but attempts to pend the interrupt for the current domain first. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +int fastcall adeos_schedule_irq (unsigned irq) { +#else /* LINUX_VERSION_CODE < 2.4.27 */ +int adeos_schedule_irq (unsigned irq) { +#endif + return __adeos_schedule_irq(irq,&adp_current->p_link); +} + +unsigned long adeos_set_irq_affinity (unsigned irq, unsigned long cpumask) + +{ +#ifdef CONFIG_SMP + if (irq >= IPIPE_NR_XIRQS) + /* Allow changing affinity of external IRQs only. */ + return 0; + + if (smp_num_cpus > 1) + /* Allow changing affinity of external IRQs only. */ + return __adeos_set_irq_affinity(irq,cpumask); +#endif /* CONFIG_SMP */ + + return 0; +} + +/* adeos_free_irq() -- Return a previously allocated virtual/soft + pipelined interrupt to the pool of allocatable interrupts. */ + +int adeos_free_irq (unsigned irq) + +{ + if (irq >= IPIPE_NR_IRQS) + return -EINVAL; + + clear_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map); + + return 0; +} + +/* adeos_catch_event_from() -- Interpose an event handler starting + from a given domain. */ + +int adeos_catch_event_from (adomain_t *adp, unsigned event, void (*handler)(adevinfo_t *)) + +{ + if (event >= ADEOS_NR_EVENTS) + return -EINVAL; + + if (!xchg(&adp->events[event].handler,handler)) + { + if (handler) + __adeos_event_monitors[event]++; + } + else if (!handler) + __adeos_event_monitors[event]--; + + return 0; +} + +void adeos_init_attr (adattr_t *attr) + +{ + attr->name = "Anonymous"; + attr->domid = 1; + attr->entry = NULL; + attr->estacksz = 0; /* Let ADEOS choose a reasonable stack size */ + attr->priority = ADEOS_ROOT_PRI; + attr->dswitch = NULL; + attr->nptdkeys = 0; + attr->ptdset = NULL; + attr->ptdget = NULL; +} + +int adeos_alloc_ptdkey (void) + +{ + unsigned long flags; + int key = -1; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (adp_current->ptd_keycount < adp_current->ptd_keymax) + { + key = ffz(adp_current->ptd_keymap); + set_bit(key,&adp_current->ptd_keymap); + adp_current->ptd_keycount++; + } + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return key; +} + +int adeos_free_ptdkey (int key) + +{ + unsigned long flags; + + if (key < 0 || key >= adp_current->ptd_keymax) + return -EINVAL; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (test_and_clear_bit(key,&adp_current->ptd_keymap)) + adp_current->ptd_keycount--; + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return 0; +} + +int adeos_set_ptd (int key, void *value) + +{ + if (key < 0 || key >= adp_current->ptd_keymax) + return -EINVAL; + + if (!adp_current->ptd_setfun) + { + printk(KERN_WARNING "Adeos: No ptdset hook for %s\n",adp_current->name); + return -EINVAL; + } + + adp_current->ptd_setfun(key,value); + + return 0; +} + +void *adeos_get_ptd (int key) + +{ + if (key < 0 || key >= adp_current->ptd_keymax) + return NULL; + + if (!adp_current->ptd_getfun) + { + printk(KERN_WARNING "Adeos: No ptdget hook for %s\n",adp_current->name); + return NULL; + } + + return adp_current->ptd_getfun(key); +} + +int adeos_init_mutex (admutex_t *mutex) + +{ + admutex_t initm = ADEOS_MUTEX_UNLOCKED; + *mutex = initm; + return 0; +} + +int adeos_destroy_mutex (admutex_t *mutex) + +{ + if (!adeos_spin_trylock(&mutex->lock) && + adp_current != adp_root && + mutex->owner != adp_current) + return -EBUSY; + + return 0; +} + +static inline void __adeos_sleepon_mutex (admutex_t *mutex, adomain_t *sleeper, int cpuid) + +{ + adomain_t *owner = mutex->owner; + + /* Make the current domain (== sleeper) wait for the mutex to be + released. Adeos' pipelined scheme guarantees that the new + sleeper _is_ more prioritary than any aslept domain since we + have stalled each sleeper's stage. Must be called with local hw + interrupts off. */ + + sleeper->m_link = mutex->sleepq; + mutex->sleepq = sleeper; + __adeos_switch_to(adp_cpu_current[cpuid],owner,cpuid); + mutex->owner = sleeper; + adeos_spin_unlock(&mutex->lock); +} +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +unsigned long fastcall adeos_lock_mutex (admutex_t *mutex) +#else /* LINUX_VERSION_CODE < 2.4.27 */ +unsigned long adeos_lock_mutex (admutex_t *mutex) +#endif +{ + unsigned long flags, hwflags; + adeos_declare_cpuid; + adomain_t *adp; + + if (unlikely(!adp_pipelined)) + { + adeos_hw_local_irq_save(hwflags); + flags = !adeos_hw_test_iflag(hwflags); + adeos_spin_lock(&mutex->lock); + return flags; + } + + adeos_lock_cpu(hwflags); + + adp = adp_cpu_current[cpuid]; + + flags = test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + /* Two cases to handle here on SMP systems, only one for UP: + 1) in case of a conflicting access from a prioritary domain + running on the same cpu, make this domain sleep on the mutex, + and resume the current owner so it can release the lock asap. + 2) in case of a conflicting access from any domain on a + different cpu than the current owner's, simply enter a spinning + loop. Note that testing mutex->owncpu is safe since it is only + changed by the current owner, and set to -1 when the mutex is + unlocked. */ + +#ifdef CONFIG_SMP + while (!adeos_spin_trylock(&mutex->lock)) + { + if (mutex->owncpu == cpuid) + { + __adeos_sleepon_mutex(mutex,adp,cpuid); + adeos_load_cpuid(); + } + } + + mutex->owncpu = cpuid; +#else /* !CONFIG_SMP */ + while (mutex->owner != NULL && mutex->owner != adp) + __adeos_sleepon_mutex(mutex,adp,cpuid); +#endif /* CONFIG_SMP */ + + mutex->owner = adp; + + adeos_unlock_cpu(hwflags); + + return flags; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +void fastcall adeos_unlock_mutex (admutex_t *mutex, unsigned long flags) +#else /* LINUX_VERSION_CODE < 2.4.27 */ +void adeos_unlock_mutex (admutex_t *mutex, unsigned long flags) +#endif +{ + unsigned long hwflags; + adeos_declare_cpuid; + adomain_t *adp; + + if (unlikely(!adp_pipelined)) + { + adeos_spin_unlock(&mutex->lock); + + if (flags) + adeos_hw_cli(); + else + adeos_hw_sti(); + + return; + } + +#ifdef CONFIG_SMP + mutex->owncpu = -1; +#endif /* CONFIG_SMP */ + + if (!flags) + adeos_hw_sti(); /* Absolutely needed. */ + + adeos_lock_cpu(hwflags); + + if (unlikely(mutex->sleepq != NULL)) + { + adomain_t *sleeper = mutex->sleepq; + /* Wake up the first most prioritary sleeper. */ + mutex->sleepq = sleeper->m_link; + __adeos_switch_to(adp_cpu_current[cpuid],sleeper,cpuid); + adeos_load_cpuid(); + } + else + { + mutex->owner = NULL; + adeos_spin_unlock(&mutex->lock); + } + + adp = adp_cpu_current[cpuid]; + + if (flags) + set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + else + { + clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (adp->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + adeos_unlock_cpu(hwflags); +} + +void __adeos_takeover (void) + +{ + __adeos_enable_pipeline(); + printk(KERN_WARNING "Adeos: Pipelining started.\n"); +} + +#ifdef MODULE + +static int __init adeos_init_module (void) + +{ + __adeos_takeover(); + return 0; +} + +static void __exit adeos_exit_module (void) + +{ + __adeos_disable_pipeline(); + printk(KERN_WARNING "Adeos: Pipelining stopped.\n"); +} + +module_init(adeos_init_module); +module_exit(adeos_exit_module); + +#endif /* MODULE */ + +EXPORT_SYMBOL(adeos_register_domain); +EXPORT_SYMBOL(adeos_unregister_domain); +EXPORT_SYMBOL(adeos_virtualize_irq_from); +EXPORT_SYMBOL(adeos_control_irq); +EXPORT_SYMBOL(adeos_propagate_irq); +EXPORT_SYMBOL(adeos_schedule_irq); +EXPORT_SYMBOL(adeos_free_irq); +EXPORT_SYMBOL(adeos_send_ipi); +EXPORT_SYMBOL(adeos_catch_event_from); +EXPORT_SYMBOL(adeos_init_attr); +EXPORT_SYMBOL(adeos_get_sysinfo); +EXPORT_SYMBOL(adeos_tune_timer); +EXPORT_SYMBOL(adeos_alloc_ptdkey); +EXPORT_SYMBOL(adeos_free_ptdkey); +EXPORT_SYMBOL(adeos_set_ptd); +EXPORT_SYMBOL(adeos_get_ptd); +EXPORT_SYMBOL(adeos_set_irq_affinity); +EXPORT_SYMBOL(adeos_init_mutex); +EXPORT_SYMBOL(adeos_destroy_mutex); +EXPORT_SYMBOL(adeos_lock_mutex); +EXPORT_SYMBOL(adeos_unlock_mutex); diff -uNrp linux-2.4.31/adeos/Makefile linux-2.4.31-r18/adeos/Makefile --- linux-2.4.31/adeos/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/adeos/Makefile 2004-06-07 22:50:41.000000000 +0200 @@ -0,0 +1,32 @@ +# +# Makefile for the Adeos layer. +# + +O_TARGET := built-in.o + +list-multi := adeos.o +export-objs := generic.o +adeos-objs := generic.o + +ifdef CONFIG_X86 +adeos-objs += x86.o +endif + +ifdef CONFIG_ARM +ifdef CONFIG_UCLINUX +adeos-objs += armnommu.o +else +adeos-objs += armv.o +endif +endif + +ifdef CONFIG_PPC +adeos-objs += ppc.o +endif + +obj-$(CONFIG_ADEOS) += adeos.o + +include $(TOPDIR)/Rules.make + +adeos.o: $(adeos-objs) + $(LD) -r -o $@ $(adeos-objs) diff -uNrp linux-2.4.31/adeos/x86.c linux-2.4.31-r18/adeos/x86.c --- linux-2.4.31/adeos/x86.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/adeos/x86.c 2005-06-06 23:11:24.000000000 +0200 @@ -0,0 +1,1004 @@ +/* + * linux/adeos/x86.c + * + * Copyright (C) 2002 Philippe Gerum. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Architecture-dependent ADEOS support for x86. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#include +#ifdef CONFIG_X86_IO_APIC +#include +#endif /* CONFIG_X86_IO_APIC */ +#include +#endif /* CONFIG_X86_LOCAL_APIC */ + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ + +extern struct desc_struct idt_table[]; + +extern spinlock_t __adeos_pipelock; + +static void (*__adeos_std_vector_table[256])(void); + +static struct hw_interrupt_type __adeos_std_irq_dtype[NR_IRQS]; + +/* Lifted from arch/i386/kernel/traps.c */ +#define __adeos_set_gate(gate_addr,type,dpl,addr) \ +do { \ + int __d0, __d1; \ + __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ + "movw %4,%%dx\n\t" \ + "movl %%eax,%0\n\t" \ + "movl %%edx,%1" \ + :"=m" (*((long *) (gate_addr))), \ + "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ + :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ + "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \ +} while (0) + +#define __adeos_get_gate_addr(v) \ + ((void *)((idt_table[v].b & 0xffff0000)|(idt_table[v].a & 0xffff))) + +#define __adeos_set_irq_gate(vector,addr) \ +__adeos_set_gate(idt_table+vector,14,0,addr) + +#define __adeos_set_trap_gate(vector,addr) \ +__adeos_set_gate(idt_table+vector,15,0,addr) + +#define __adeos_set_sys_gate(vector,addr) \ +__adeos_set_gate(idt_table+vector,15,3,addr) + +#define BUILD_IRQ_BODY() \ +__asm__( \ + "\n" __ALIGN_STR"\n" \ + SYMBOL_NAME_STR(__adeos_irq_common) ":\n\t" \ + "pushl %es\n\t" \ + "pushl %ds\n\t" \ + "pushl %eax\n\t" \ + "pushl %ebp\n\t" \ + "pushl %edi\n\t" \ + "pushl %esi\n\t" \ + "pushl %edx\n\t" \ + "pushl %ecx\n\t" \ + "pushl %ebx\n\t" \ + "movl $" STR(__KERNEL_DS) ",%edx\n\t" \ + "movl %edx,%ds\n\t" \ + "movl %edx,%es\n\t" \ + "call " SYMBOL_NAME_STR(__adeos_handle_irq) "\n\t" \ + "testl %eax,%eax\n\t" \ + "jnz 1f\n\t" \ + "popl %ebx\n\t" \ + "popl %ecx\n\t" \ + "popl %edx\n\t" \ + "popl %esi\n\t" \ + "popl %edi\n\t" \ + "popl %ebp\n\t" \ + "popl %eax\n\t" \ + "popl %ds\n\t" \ + "popl %es\n\t" \ + "addl $4,%esp\n\t" \ + "iret\n\t" \ + "1: cld\n\t" \ + __adeos_bump_count_noarg /* Depends on CONFIG_PREEMPT. */ \ + "jmp " SYMBOL_NAME_STR(ret_from_intr) "\n"); + + +#define BUILD_IRQ_PROTO(irq) __adeos_irq_##irq(void) +#define BUILD_1_IRQ(irq) \ +asmlinkage void BUILD_IRQ_PROTO(irq); \ +__asm__( \ + "\n" __ALIGN_STR"\n" \ + SYMBOL_NAME_STR(__adeos_irq_) #irq ":\n\t" \ + "pushl $"#irq"-256 \n\t" \ + "jmp " SYMBOL_NAME_STR(__adeos_irq_common) "\n"); + +#define BUILD_IRQ_N(x,y) \ +BUILD_1_IRQ(x##y) + +#define BUILD_16_IRQS(x) \ +BUILD_IRQ_N(x,0) BUILD_IRQ_N(x,1) BUILD_IRQ_N(x,2) BUILD_IRQ_N(x,3) \ +BUILD_IRQ_N(x,4) BUILD_IRQ_N(x,5) BUILD_IRQ_N(x,6) BUILD_IRQ_N(x,7) \ +BUILD_IRQ_N(x,8) BUILD_IRQ_N(x,9) BUILD_IRQ_N(x,a) BUILD_IRQ_N(x,b) \ +BUILD_IRQ_N(x,c) BUILD_IRQ_N(x,d) BUILD_IRQ_N(x,e) BUILD_IRQ_N(x,f) + +BUILD_IRQ_BODY(); + +BUILD_16_IRQS(0x0) +#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_X86_IO_APIC) +BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) BUILD_16_IRQS(0x4) +BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) BUILD_16_IRQS(0x8) +BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) BUILD_16_IRQS(0xc) +BUILD_16_IRQS(0xd) +#endif /* CONFIG_X86_LOCAL_APIC || CONFIG_X86_IO_APIC */ + +#define LIST_1_IRQ(irq) &__adeos_irq_ ## irq + +#define LIST_IRQ_N(x,y) \ +LIST_1_IRQ(x##y) + +#define LIST_16_IRQS(x) \ +LIST_IRQ_N(x,0), LIST_IRQ_N(x,1), LIST_IRQ_N(x,2), LIST_IRQ_N(x,3), \ +LIST_IRQ_N(x,4), LIST_IRQ_N(x,5), LIST_IRQ_N(x,6), LIST_IRQ_N(x,7), \ +LIST_IRQ_N(x,8), LIST_IRQ_N(x,9), LIST_IRQ_N(x,a), LIST_IRQ_N(x,b), \ +LIST_IRQ_N(x,c), LIST_IRQ_N(x,d), LIST_IRQ_N(x,e), LIST_IRQ_N(x,f) + +static void (*__adeos_irq_trampolines[])(void) = { + LIST_16_IRQS(0x0), +#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_X86_IO_APIC) + LIST_16_IRQS(0x1), LIST_16_IRQS(0x2), LIST_16_IRQS(0x3), LIST_16_IRQS(0x4), + LIST_16_IRQS(0x5), LIST_16_IRQS(0x6), LIST_16_IRQS(0x7), LIST_16_IRQS(0x8), + LIST_16_IRQS(0x9), LIST_16_IRQS(0xa), LIST_16_IRQS(0xb), LIST_16_IRQS(0xc), + LIST_16_IRQS(0xd) +#endif /* CONFIG_X86_LOCAL_APIC || CONFIG_X86_IO_APIC */ +}; + +#define BUILD_TRAP_PROTO(trapnr) __adeos_trap_##trapnr(void) + +#define BUILD_TRAP_ERRCODE(trapnr) \ +asmlinkage void BUILD_TRAP_PROTO(trapnr); \ +__asm__ ( \ + "\n" __ALIGN_STR"\n\t" \ + SYMBOL_NAME_STR(__adeos_trap_) #trapnr ":\n\t" \ + "cld\n\t" \ + "pushl %es\n\t" \ + "pushl %ds\n\t" \ + "pushl %eax\n\t" \ + "pushl %ebp\n\t" \ + "pushl %edi\n\t" \ + "pushl %esi\n\t" \ + "pushl %edx\n\t" \ + "pushl %ecx\n\t" \ + "pushl %ebx\n\t" \ + "movl $" STR(__KERNEL_DS) ",%edx\n\t" \ + "mov %dx,%ds\n\t" \ + "mov %dx,%es\n\t" \ + "movl ("__stringify(__adeos_event_monitors + 4 * trapnr)"),%eax\n\t" \ + "testl %eax,%eax\n\t" \ + "jz 1f\n\t" \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ + "pushl $"#trapnr"\n\t" \ + "call " __stringify(__adeos_handle_event) "\n\t" \ + "addl $8,%esp\n\t" \ + "testl %eax,%eax\n\t" \ +"1: popl %ebx\n\t" \ + "popl %ecx\n\t" \ + "popl %edx\n\t" \ + "popl %esi\n\t" \ + "popl %edi\n\t" \ + "popl %ebp\n\t" \ + "jz 2f\n\t" \ + "popl %eax\n\t" \ + "popl %ds\n\t" \ + "popl %es\n\t" \ + "addl $4,%esp\n\t" \ + "iret\n" \ +"2: movl ("SYMBOL_NAME_STR(__adeos_std_vector_table + 4 * trapnr)"),%eax\n\t" \ + "movl 8(%esp),%es\n\t" \ + "movl %eax,8(%esp)\n\t" \ + "popl %eax\n\t" \ + "popl %ds\n\t" \ + "ret\n"); + +#define BUILD_TRAP_NOERRCODE(trapnr) \ +asmlinkage void BUILD_TRAP_PROTO(trapnr); \ +__asm__ ( \ + "\n" __ALIGN_STR"\n\t" \ + SYMBOL_NAME_STR(__adeos_trap_) #trapnr ":\n\t" \ + "cld\n\t" \ + "pushl $0\n\t" \ + "pushl %es\n\t" \ + "pushl %ds\n\t" \ + "pushl %eax\n\t" \ + "pushl %ebp\n\t" \ + "pushl %edi\n\t" \ + "pushl %esi\n\t" \ + "pushl %edx\n\t" \ + "pushl %ecx\n\t" \ + "pushl %ebx\n\t" \ + "movl $" STR(__KERNEL_DS) ",%edx\n\t" \ + "mov %dx,%ds\n\t" \ + "mov %dx,%es\n\t" \ + "movl (" __stringify(__adeos_event_monitors + 4 * trapnr)"),%eax\n\t" \ + "testl %eax,%eax\n\t" \ + "jz 1f\n\t" \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ + "pushl $"#trapnr"\n\t" \ + "call " __stringify(__adeos_handle_event) "\n\t" \ + "addl $8,%esp\n\t" \ + "testl %eax,%eax\n\t" \ +"1: popl %ebx\n\t" \ + "popl %ecx\n\t" \ + "popl %edx\n\t" \ + "popl %esi\n\t" \ + "popl %edi\n\t" \ + "popl %ebp\n\t" \ + "jz 2f\n\t" \ + "popl %eax\n\t" \ + "popl %ds\n\t" \ + "popl %es\n\t" \ + "addl $4,%esp\n\t" \ + "iret\n" \ +"2: movl ("SYMBOL_NAME_STR(__adeos_std_vector_table + 4 * trapnr)"),%eax\n\t" \ + "movl %eax,12(%esp)\n\t" \ + "popl %eax\n\t" \ + "popl %ds\n\t" \ + "popl %es\n\t" \ + "ret\n"); + +BUILD_TRAP_NOERRCODE(0x0) BUILD_TRAP_NOERRCODE(0x1) BUILD_TRAP_NOERRCODE(0x2) +BUILD_TRAP_NOERRCODE(0x3) BUILD_TRAP_NOERRCODE(0x4) BUILD_TRAP_NOERRCODE(0x5) +BUILD_TRAP_NOERRCODE(0x6) BUILD_TRAP_NOERRCODE(0x7) BUILD_TRAP_ERRCODE(0x8) +BUILD_TRAP_NOERRCODE(0x9) BUILD_TRAP_ERRCODE(0xa) BUILD_TRAP_ERRCODE(0xb) +BUILD_TRAP_ERRCODE(0xc) BUILD_TRAP_ERRCODE(0xd) BUILD_TRAP_ERRCODE(0xe) +BUILD_TRAP_NOERRCODE(0xf) BUILD_TRAP_NOERRCODE(0x10) BUILD_TRAP_ERRCODE(0x11) +BUILD_TRAP_NOERRCODE(0x12) BUILD_TRAP_NOERRCODE(0x13) BUILD_TRAP_ERRCODE(0x14) +BUILD_TRAP_ERRCODE(0x15) BUILD_TRAP_ERRCODE(0x16) BUILD_TRAP_ERRCODE(0x17) +BUILD_TRAP_ERRCODE(0x18) BUILD_TRAP_ERRCODE(0x19) BUILD_TRAP_ERRCODE(0x1a) +BUILD_TRAP_ERRCODE(0x1b) BUILD_TRAP_ERRCODE(0x1c) BUILD_TRAP_ERRCODE(0x1d) +BUILD_TRAP_ERRCODE(0x1e) BUILD_TRAP_ERRCODE(0x1f) + +#define LIST_TRAP(trapnr) &__adeos_trap_ ## trapnr + +static void (*__adeos_trap_trampolines[])(void) = { + LIST_TRAP(0x0), LIST_TRAP(0x1), LIST_TRAP(0x2), LIST_TRAP(0x3), + LIST_TRAP(0x4), LIST_TRAP(0x5), LIST_TRAP(0x6), LIST_TRAP(0x7), + LIST_TRAP(0x8), LIST_TRAP(0x9), LIST_TRAP(0xa), LIST_TRAP(0xb), + LIST_TRAP(0xc), LIST_TRAP(0xd), LIST_TRAP(0xe), LIST_TRAP(0xf), + LIST_TRAP(0x10), LIST_TRAP(0x11), LIST_TRAP(0x12), LIST_TRAP(0x13), + LIST_TRAP(0x14), LIST_TRAP(0x15), LIST_TRAP(0x16), LIST_TRAP(0x17), + LIST_TRAP(0x18), LIST_TRAP(0x19), LIST_TRAP(0x1a), LIST_TRAP(0x1b), + LIST_TRAP(0x1c), LIST_TRAP(0x1d), LIST_TRAP(0x1e), LIST_TRAP(0x1f) +}; + +static int __adeos_ack_common_irq (unsigned irq) + +{ + irq_desc_t *desc = irq_desc + irq; +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + desc->handler->ack(irq); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + + return 1; +} + +static unsigned __adeos_override_irq_startup (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + unsigned s; + + adeos_lock_cpu(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_unlock_irq(adp_cpu_current[cpuid],irq); + s = __adeos_std_irq_dtype[irq].startup(irq); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_unlock_cpu(hwflags); + + return s; +} + +static void __adeos_override_irq_shutdown (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_lock_cpu(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_std_irq_dtype[irq].shutdown(irq); + __adeos_clear_irq(adp_cpu_current[cpuid],irq); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_unlock_cpu(hwflags); +} + +static void __adeos_override_irq_enable (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_lock_cpu(hwflags); + adflags = adeos_test_and_stall_pipeline(); + +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + + __adeos_unlock_irq(adp_cpu_current[cpuid],irq); + __adeos_std_irq_dtype[irq].enable(irq); + +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_unlock_cpu(hwflags); +} + +static void __adeos_override_irq_disable (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_lock_cpu(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_std_irq_dtype[irq].disable(irq); + __adeos_lock_irq(adp_cpu_current[cpuid],cpuid,irq); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_unlock_cpu(hwflags); +} + +static void __adeos_override_irq_end (unsigned irq) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_lock_cpu(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + +#ifdef CONFIG_X86_IO_APIC + if (!IO_APIC_IRQ(irq) || !(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) +#else /* !CONFIG_X86_IO_APIC */ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) +#endif /* CONFIG_X86_IO_APIC */ + __adeos_unlock_irq(adp_cpu_current[cpuid],irq); + + __adeos_std_irq_dtype[irq].end(irq); + +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_unlock_cpu(hwflags); +} + +static void __adeos_override_irq_affinity (unsigned irq, unsigned long mask) + +{ + unsigned long adflags, hwflags; + adeos_declare_cpuid; + + adeos_lock_cpu(hwflags); + adflags = adeos_test_and_stall_pipeline(); +#ifdef CONFIG_PREEMPT + preempt_disable(); +#endif /* CONFIG_PREEMPT */ + __adeos_std_irq_dtype[irq].set_affinity(irq,mask); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ + adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid); + adeos_unlock_cpu(hwflags); +} + +/* __adeos_enable_pipeline() -- Take over the interrupt control from + the root domain (i.e. Linux). After this routine has returned, all + interrupts go through the pipeline. */ + +void __adeos_enable_pipeline (void) + +{ + unsigned vector, irq; + unsigned long flags; + + /* Collect the original vector table. */ + + for (vector = 0; vector < 256; vector++) + __adeos_std_vector_table[vector] = __adeos_get_gate_addr(vector); + +#ifdef CONFIG_SMP + + /* This vector must be set up prior to call + adeos_critical_enter(). */ + + __adeos_set_irq_gate(ADEOS_CRITICAL_VECTOR, + __adeos_irq_trampolines[ADEOS_CRITICAL_IPI]); + +#endif /* CONFIG_SMP */ + + flags = adeos_critical_enter(NULL); + + /* First, grab the ISA and IO-APIC interrupts. */ + + for (irq = 0; irq < NR_IRQS && irq + FIRST_EXTERNAL_VECTOR < FIRST_SYSTEM_VECTOR; irq++) + { +#ifdef CONFIG_X86_IO_APIC + if (IO_APIC_IRQ(irq)) + { + vector = IO_APIC_VECTOR(irq); + + if (vector == 0) + continue; + } + else +#endif /* CONFIG_X86_IO_APIC */ + { + vector = irq + FIRST_EXTERNAL_VECTOR; + + if (vector == SYSCALL_VECTOR) + continue; + } + + /* Fails for ADEOS_CRITICAL_IPI but that's ok. */ + + adeos_virtualize_irq(irq, + (void (*)(unsigned))__adeos_std_vector_table[vector], + &__adeos_ack_common_irq, + IPIPE_CALLASM_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK); + + __adeos_set_irq_gate(vector,__adeos_irq_trampolines[irq]); + } + + /* Interpose on the IRQ control routines so we can make them + atomic using hw masking and prevent the interrupt log from + being untimely flushed. Since we don't want to be too smart + about what's going on into irq.c and we want to change only + some of the controller members, let's be dumb and interpose the + rough way. */ + + for (irq = 0; irq < NR_IRQS; irq++) + __adeos_std_irq_dtype[irq] = *irq_desc[irq].handler; + + /* The original controller structs are often shared, so we first + save them all before changing any of them. Notice that we don't + redirect the ack handler since the relevant XT-PIC/IO-APIC + management code is already Adeos-aware. */ + + for (irq = 0; irq < NR_IRQS; irq++) + { + irq_desc[irq].handler->startup = &__adeos_override_irq_startup; + irq_desc[irq].handler->shutdown = &__adeos_override_irq_shutdown; + irq_desc[irq].handler->enable = &__adeos_override_irq_enable; + irq_desc[irq].handler->disable = &__adeos_override_irq_disable; + irq_desc[irq].handler->end = &__adeos_override_irq_end; + + if (irq_desc[irq].handler->set_affinity != NULL) + irq_desc[irq].handler->set_affinity = &__adeos_override_irq_affinity; + } + +#ifdef CONFIG_X86_LOCAL_APIC + + /* Map the APIC system vectors including the unused ones so that + client domains can virtualize the corresponding IRQs. */ + + for (vector = FIRST_SYSTEM_VECTOR; vector < CALL_FUNCTION_VECTOR; vector++) + { + adeos_virtualize_irq(vector - FIRST_EXTERNAL_VECTOR, + (void (*)(unsigned))__adeos_std_vector_table[vector], + &__adeos_ack_system_irq, + IPIPE_CALLASM_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK); + + __adeos_set_irq_gate(vector, + __adeos_irq_trampolines[vector - FIRST_EXTERNAL_VECTOR]); + } + + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR0, + __adeos_irq_trampolines[ADEOS_SERVICE_IPI0]); + + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR1, + __adeos_irq_trampolines[ADEOS_SERVICE_IPI1]); + + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR2, + __adeos_irq_trampolines[ADEOS_SERVICE_IPI2]); + + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR3, + __adeos_irq_trampolines[ADEOS_SERVICE_IPI3]); + + __adeos_tick_irq = using_apic_timer ? LOCAL_TIMER_VECTOR - FIRST_EXTERNAL_VECTOR : 0; + +#else /* !CONFIG_X86_LOCAL_APIC */ + + __adeos_tick_irq = 0; + +#endif /* CONFIG_X86_LOCAL_APIC */ + +#ifdef CONFIG_SMP + + /* All interrupts must be pipelined, but the spurious one since we + don't even want to acknowledge it. */ + + for (vector = CALL_FUNCTION_VECTOR; vector < SPURIOUS_APIC_VECTOR; vector++) + { + adeos_virtualize_irq(vector - FIRST_EXTERNAL_VECTOR, + (void (*)(unsigned))__adeos_std_vector_table[vector], + &__adeos_ack_system_irq, + IPIPE_CALLASM_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK); + + __adeos_set_irq_gate(vector, + __adeos_irq_trampolines[vector - FIRST_EXTERNAL_VECTOR]); + } + +#endif /* CONFIG_SMP */ + + /* Redirect traps and exceptions (except NMI). */ + + __adeos_set_trap_gate(0,__adeos_trap_trampolines[0]); + __adeos_set_trap_gate(1,__adeos_trap_trampolines[1]); + __adeos_set_sys_gate(3,__adeos_trap_trampolines[3]); + __adeos_set_sys_gate(4,__adeos_trap_trampolines[4]); + __adeos_set_sys_gate(5,__adeos_trap_trampolines[5]); + __adeos_set_trap_gate(6,__adeos_trap_trampolines[6]); + __adeos_set_trap_gate(7,__adeos_trap_trampolines[7]); + __adeos_set_trap_gate(8,__adeos_trap_trampolines[8]); + __adeos_set_trap_gate(9,__adeos_trap_trampolines[9]); + __adeos_set_trap_gate(10,__adeos_trap_trampolines[10]); + __adeos_set_trap_gate(11,__adeos_trap_trampolines[11]); + __adeos_set_trap_gate(12,__adeos_trap_trampolines[12]); + __adeos_set_trap_gate(13,__adeos_trap_trampolines[13]); + __adeos_set_irq_gate(14,__adeos_trap_trampolines[14]); + __adeos_set_trap_gate(15,__adeos_trap_trampolines[15]); + __adeos_set_trap_gate(16,__adeos_trap_trampolines[16]); + __adeos_set_trap_gate(17,__adeos_trap_trampolines[17]); + __adeos_set_trap_gate(18,__adeos_trap_trampolines[18]); + __adeos_set_trap_gate(19,__adeos_trap_trampolines[19]); + + adp_pipelined = 1; + + adeos_critical_exit(flags); +} + +/* __adeos_disable_pipeline() -- Disengage the pipeline. */ + +void __adeos_disable_pipeline (void) + +{ + unsigned vector, irq; + unsigned long flags; + + flags = adeos_critical_enter(NULL); + + /* Restore interrupt controllers. */ + + for (irq = 0; irq < NR_IRQS; irq++) + *irq_desc[irq].handler = __adeos_std_irq_dtype[irq]; + + /* Restore original IDT settings. */ + + for (irq = 0; irq < NR_IRQS && irq + FIRST_EXTERNAL_VECTOR < FIRST_SYSTEM_VECTOR; irq++) + { +#ifdef CONFIG_X86_IO_APIC + if (IO_APIC_IRQ(irq)) + { + vector = IO_APIC_VECTOR(irq); + + if (vector == 0) + continue; + } + else +#endif /* CONFIG_X86_IO_APIC */ + { + vector = irq + FIRST_EXTERNAL_VECTOR; + + if (vector == SYSCALL_VECTOR) + continue; + } + + __adeos_set_irq_gate(vector,__adeos_std_vector_table[vector]); + } + +#ifdef CONFIG_X86_LOCAL_APIC + + for (vector = FIRST_SYSTEM_VECTOR; vector < CALL_FUNCTION_VECTOR; vector++) + __adeos_set_irq_gate(vector,__adeos_std_vector_table[vector]); + + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR0,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR0]); + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR1,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR1]); + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR2,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR2]); + __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR3,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR3]); + +#endif /* CONFIG_X86_LOCAL_APIC */ + +#ifdef CONFIG_SMP + + for (vector = CALL_FUNCTION_VECTOR; vector < SPURIOUS_APIC_VECTOR; vector++) + __adeos_set_irq_gate(vector,__adeos_std_vector_table[vector]); + + __adeos_set_irq_gate(ADEOS_CRITICAL_VECTOR,__adeos_std_vector_table[ADEOS_CRITICAL_VECTOR]); + +#endif /* CONFIG_SMP */ + + __adeos_set_trap_gate(0,__adeos_std_vector_table[0]); + __adeos_set_trap_gate(1,__adeos_std_vector_table[1]); + __adeos_set_sys_gate(3,__adeos_std_vector_table[3]); + __adeos_set_sys_gate(4,__adeos_std_vector_table[4]); + __adeos_set_sys_gate(5,__adeos_std_vector_table[5]); + __adeos_set_trap_gate(6,__adeos_std_vector_table[6]); + __adeos_set_trap_gate(7,__adeos_std_vector_table[7]); + __adeos_set_trap_gate(8,__adeos_std_vector_table[8]); + __adeos_set_trap_gate(9,__adeos_std_vector_table[9]); + __adeos_set_trap_gate(10,__adeos_std_vector_table[10]); + __adeos_set_trap_gate(11,__adeos_std_vector_table[11]); + __adeos_set_trap_gate(12,__adeos_std_vector_table[12]); + __adeos_set_trap_gate(13,__adeos_std_vector_table[13]); + __adeos_set_irq_gate(14,__adeos_std_vector_table[14]); + __adeos_set_trap_gate(15,__adeos_std_vector_table[15]); + __adeos_set_trap_gate(16,__adeos_std_vector_table[16]); + __adeos_set_trap_gate(17,__adeos_std_vector_table[17]); + __adeos_set_trap_gate(18,__adeos_std_vector_table[18]); + __adeos_set_trap_gate(19,__adeos_std_vector_table[19]); + + adp_pipelined = 0; + + adeos_critical_exit(flags); +} + +/* adeos_virtualize_irq_from() -- Attach a handler (and optionally a + hw acknowledge routine) to an interrupt for the given domain. */ + +int adeos_virtualize_irq_from (adomain_t *adp, + unsigned irq, + void (*handler)(unsigned irq), + int (*acknowledge)(unsigned irq), + unsigned modemask) +{ + unsigned long flags; + int err; + + if (irq >= IPIPE_NR_IRQS) + return -EINVAL; + + if (adp->irqs[irq].control & IPIPE_SYSTEM_MASK) + return -EPERM; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (handler != NULL) + { + /* A bit of hack here: if we are re-virtualizing an IRQ just + to change the acknowledge routine by passing the special + ADEOS_SAME_HANDLER value, then allow to recycle the current + handler for the IRQ. This allows Linux device drivers + managing shared IRQ lines to call adeos_virtualize_irq() in + addition to request_irq() just for the purpose of + interposing their own shared acknowledge routine. */ + + if (handler == ADEOS_SAME_HANDLER) + { + handler = adp->irqs[irq].handler; + + if (handler == NULL) + { + err = -EINVAL; + goto unlock_and_exit; + } + } + else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 && + adp->irqs[irq].handler != NULL) + { + err = -EBUSY; + goto unlock_and_exit; + } + + if ((modemask & (IPIPE_SHARED_MASK|IPIPE_PASS_MASK)) == IPIPE_SHARED_MASK) + { + err = -EINVAL; + goto unlock_and_exit; + } + + if ((modemask & IPIPE_STICKY_MASK) != 0) + modemask |= IPIPE_HANDLE_MASK; + } + else + modemask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SHARED_MASK); + + if (acknowledge == NULL) + { + if ((modemask & IPIPE_SHARED_MASK) == 0) + /* Acknowledge handler unspecified -- this is ok in + non-shared management mode, but we will force the use + of the Linux-defined handler instead. */ + acknowledge = adp_root->irqs[irq].acknowledge; + else + { + /* A valid acknowledge handler to be called in shared mode + is required when declaring a shared IRQ. */ + err = -EINVAL; + goto unlock_and_exit; + } + } + + adp->irqs[irq].handler = handler; + adp->irqs[irq].acknowledge = acknowledge; + adp->irqs[irq].control = modemask; + + if (irq < NR_IRQS && + handler != NULL && + !adeos_virtual_irq_p(irq) && + (modemask & IPIPE_ENABLE_MASK) != 0) + { + if (adp != adp_current) + { + /* IRQ enable/disable state is domain-sensitive, so we may + not change it for another domain. What is allowed + however is forcing some domain to handle an interrupt + source, by passing the proper 'adp' descriptor which + thus may be different from adp_current. */ + err = -EPERM; + goto unlock_and_exit; + } + + irq_desc[irq].handler->enable(irq); + } + + err = 0; + +unlock_and_exit: + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return err; +} + +/* adeos_control_irq() -- Change an interrupt mode. This affects the + way a given interrupt is handled by ADEOS for the current + domain. setmask is a bitmask telling whether: + - the interrupt should be passed to the domain (IPIPE_HANDLE_MASK), + and/or + - the interrupt should be passed down to the lower priority domain(s) + in the pipeline (IPIPE_PASS_MASK). + This leads to four possibilities: + - PASS only => Ignore the interrupt + - HANDLE only => Terminate the interrupt (process but don't pass down) + - PASS + HANDLE => Accept the interrupt (process and pass down) + - => Discard the interrupt + - DYNAMIC is currently an alias of HANDLE since it marks an interrupt + which is processed by the current domain but not implicitely passed + down to the pipeline, letting the domain's handler choose on a case- + by-case basis whether the interrupt propagation should be forced + using adeos_propagate_irq(). + clrmask clears the corresponding bits from the control field before + setmask is applied. +*/ + +int adeos_control_irq (unsigned irq, + unsigned clrmask, + unsigned setmask) +{ + unsigned long flags; + irq_desc_t *desc; + + if (irq >= IPIPE_NR_IRQS) + return -EINVAL; + + if (adp_current->irqs[irq].control & IPIPE_SYSTEM_MASK) + return -EPERM; + + if (((setmask|clrmask) & IPIPE_SHARED_MASK) != 0) + return -EINVAL; + + desc = irq_desc + irq; + + if (adp_current->irqs[irq].handler == NULL) + setmask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK); + + if ((setmask & IPIPE_STICKY_MASK) != 0) + setmask |= IPIPE_HANDLE_MASK; + + if ((clrmask & (IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK)) != 0) /* If one goes, both go. */ + clrmask |= (IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK); + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + adp_current->irqs[irq].control &= ~clrmask; + adp_current->irqs[irq].control |= setmask; + + if ((setmask & IPIPE_ENABLE_MASK) != 0) + desc->handler->enable(irq); + else if ((clrmask & IPIPE_ENABLE_MASK) != 0) + desc->handler->disable(irq); + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return 0; +} + +asmlinkage static void __adeos_domain_trampoline (void (*entry)(int), int iflag) +/* asmlinkage is there just in case -mregparm is used... */ +{ + unsigned long flags; + adeos_declare_cpuid; + + adeos_get_cpu(flags); + clear_bit(IPIPE_SLEEP_FLAG,&adp_current->cpudata[cpuid].status); + adeos_put_cpu(flags); + entry(iflag); +} + +void __adeos_init_domain (adomain_t *adp, adattr_t *attr) + +{ + int estacksz = attr->estacksz > 0 ? attr->estacksz : 8192, _cpuid; + adeos_declare_cpuid; + + /* Here we don't care if a CPU migration occurs since we do not + use the cpuid for accessing per-CPU data, but we don't want + more than one CPU to be passed iflag == 1. */ + + adeos_load_cpuid(); + + for (_cpuid = 0; _cpuid < smp_num_cpus; _cpuid++) + { + int **psp = &adp->esp[_cpuid]; + + adp->estackbase[_cpuid] = (int *)kmalloc(estacksz,GFP_KERNEL); + + if (adp->estackbase[_cpuid] == NULL) + panic("Adeos: No memory for domain stack on CPU #%d",_cpuid); + + adp->esp[_cpuid] = adp->estackbase[_cpuid]; + **psp = 0; + *psp = (int *)(((unsigned long)*psp + estacksz - 0x10) & ~0xf); + *--(*psp) = (_cpuid == cpuid); /* iflag */ + *--(*psp) = (int)attr->entry; + *--(*psp) = 0; + *--(*psp) = (int)&__adeos_domain_trampoline; + } +} + +void __adeos_cleanup_domain (adomain_t *adp) + +{ + int _cpuid; + + adeos_unstall_pipeline_from(adp); + + for (_cpuid = 0; _cpuid < smp_num_cpus; _cpuid++) + { +#ifdef CONFIG_SMP + while (adp->cpudata[_cpuid].irq_pending_hi != 0) + cpu_relax(); + + while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status)) + cpu_relax(); +#endif /* CONFIG_SMP */ + + if (adp->estackbase[_cpuid] != NULL) + kfree(adp->estackbase[_cpuid]); + } +} + +int adeos_get_sysinfo (adsysinfo_t *info) + +{ + info->ncpus = smp_num_cpus; + info->cpufreq = adeos_cpu_freq(); + info->archdep.tmirq = __adeos_tick_irq; + + return 0; +} + +int adeos_tune_timer (unsigned long ns, int flags) + +{ + unsigned hz, latch; + unsigned long x; + + if (flags & ADEOS_RESET_TIMER) + latch = LATCH; + else + { + hz = 1000000000 / ns; + + if (hz < HZ) + return -EINVAL; + + latch = (CLOCK_TICK_RATE + hz/2) / hz; + } + + x = adeos_critical_enter(NULL); /* Sync with all CPUs */ + + /* Shamelessly lifted from init_IRQ() in i8259.c */ + outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(latch & 0xff,0x40); /* LSB */ + outb(latch >> 8,0x40); /* MSB */ + + adeos_critical_exit(x); + + return 0; +} + +/* adeos_send_ipi() -- Send a specified service IPI to a set of + processors. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +int fastcall adeos_send_ipi (unsigned ipi, cpumask_t cpumask) +#else /* LINUX_VERSION_CODE < 2.4.27 */ +int adeos_send_ipi (unsigned ipi, cpumask_t cpumask) +#endif +{ +#ifdef CONFIG_SMP + unsigned long flags; + adeos_declare_cpuid; + int self; + + switch (ipi) + { + case ADEOS_SERVICE_IPI0: + case ADEOS_SERVICE_IPI1: + case ADEOS_SERVICE_IPI2: + case ADEOS_SERVICE_IPI3: + + break; + + default: + + return -EINVAL; + } + + adeos_lock_cpu(flags); + + self = test_and_clear_bit(cpuid,&cpumask); + + if (cpumask) + __adeos_send_IPI_mask(cpumask,ipi + FIRST_EXTERNAL_VECTOR); + + if (self) + adeos_trigger_irq(ipi); + + adeos_unlock_cpu(flags); +#endif /* CONFIG_SMP */ + + return 0; +} diff -uNrp linux-2.4.31/arch/i386/config.in linux-2.4.31-r18/arch/i386/config.in --- linux-2.4.31/arch/i386/config.in 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/config.in 2005-06-20 23:51:43.000000000 +0200 @@ -267,6 +267,11 @@ mainmenu_option next_comment comment 'General setup' bool 'Networking support' CONFIG_NET +tristate 'Adeos support' CONFIG_ADEOS +if [ "$CONFIG_ADEOS" != "n" ]; then + define_bool CONFIG_ADEOS_CORE y + bool 'Adeos pipeline profiling' CONFIG_ADEOS_PROFILING +fi # Visual Workstation support is utterly broken. # If you want to see it working mail an VW540 to hch@infradead.org 8) diff -uNrp linux-2.4.31/arch/i386/kernel/adeos.c linux-2.4.31-r18/arch/i386/kernel/adeos.c --- linux-2.4.31/arch/i386/kernel/adeos.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/adeos.c 2005-06-02 23:14:17.000000000 +0200 @@ -0,0 +1,685 @@ +/* + * linux/arch/i386/kernel/adeos.c + * + * Copyright (C) 2002 Philippe Gerum. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Architecture-dependent ADEOS core support for x86. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#include +#ifdef CONFIG_X86_IO_APIC +#include +#endif /* CONFIG_X86_IO_APIC */ +#include +#endif /* CONFIG_X86_LOCAL_APIC */ + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ + +struct pt_regs __adeos_tick_regs; + +int __adeos_tick_irq; + +/* A global flag telling whether Adeos pipelining is engaged. */ +int adp_pipelined; + +#ifdef CONFIG_X86_LOCAL_APIC +/* Ugly hack allowing 1) to run portions of early kernel init code + which make use of smp_processor_id(), 2) to run SMP kernels on UP + boxen without APIC. See asm-i386/adeos.h */ +int __adeos_apic_mapped; +#endif /* CONFIG_X86_LOCAL_APIC */ + +#ifdef CONFIG_SMP + +static volatile unsigned long __adeos_cpu_sync_map; + +static volatile unsigned long __adeos_cpu_lock_map; + +static spinlock_t __adeos_cpu_barrier = SPIN_LOCK_UNLOCKED; + +static atomic_t __adeos_critical_count = ATOMIC_INIT(0); + +static void (*__adeos_cpu_sync)(void); + +#endif /* CONFIG_SMP */ + +#define __adeos_call_asm_irq_handler(adp,irq) \ + __asm__ __volatile__ ("pushfl\n\t" \ + "push %%cs\n\t" \ + "call *%1\n" \ + : /* no output */ \ + : "a" (irq), "m" ((adp)->irqs[irq].handler)) + +#define __adeos_call_c_irq_handler(adp,irq) \ + __asm__ __volatile__ ("pushl %%ebp\n\t" \ + "pushl %%edi\n\t" \ + "pushl %%esi\n\t" \ + "pushl %%edx\n\t" \ + "pushl %%ecx\n\t" \ + "pushl %%ebx\n\t" \ + "pushl %%eax\n\t" \ + "call *%1\n\t" \ + "addl $4,%%esp\n\t" \ + "popl %%ebx\n\t" \ + "popl %%ecx\n\t" \ + "popl %%edx\n\t" \ + "popl %%esi\n\t" \ + "popl %%edi\n\t" \ + "popl %%ebp\n" \ + : /* no output */ \ + : "a" (irq), "m" ((adp)->irqs[irq].handler)) + +#ifdef CONFIG_PREEMPT +/* With kernel preemption enabled, ret_from_intr might identify a need + for rescheduling raised by the C handler, so we should call it + after we have bumped the preemption count. Native (i.e. ASM) + handlers are expected to do the same. */ +#define __adeos_call_c_root_irq_handler(adp,irq) \ + __asm__ __volatile__ ("pushfl\n\t" \ + "pushl %%cs\n\t" \ + "pushl $1f\n\t" \ + "pushl $-1\n\t" /* Negative (fake) orig_eax. */ \ + "pushl %%es\n\t" \ + "pushl %%ds\n\t" \ + "pushl %%eax\n\t" \ + "pushl %%ebp\n\t" \ + "pushl %%edi\n\t" \ + "pushl %%esi\n\t" \ + "pushl %%edx\n\t" \ + "pushl %%ecx\n\t" \ + "pushl %%ebx\n\t" \ + __adeos_bump_count \ + "pushl %%eax\n\t" \ + "call *%1\n\t" \ + "addl $4,%%esp\n\t" \ + "jmp "__stringify(ret_from_intr)"\n\t" \ + "1:\n" \ + : /* no output */ \ + : "a" (irq), "m" ((adp)->irqs[irq].handler)) +#else /* !CONFIG_PREEMPT */ +#define __adeos_call_c_root_irq_handler(adp,irq) __adeos_call_c_irq_handler(adp,irq) +#endif /* CONFIG_PREEMPT */ + +static __inline__ unsigned long flnz (unsigned long word) { + __asm__("bsrl %1, %0" + : "=r" (word) + : "r" (word)); + return word; +} + +void __adeos_check_machine (void) + +{ +#ifdef CONFIG_SMP + if (!cpu_has_apic) + /* Ok, unlike vanilla Linux, Adeos in SMP mode is not going to + work without an APIC. So bail out now. */ + panic("Adeos: APIC not detected -- cannot run in SMP mode."); +#endif /* CONFIG_SMP */ +} + +int __adeos_ack_system_irq (unsigned irq) { +#ifdef CONFIG_X86_LOCAL_APIC + ack_APIC_irq(); /* Takes no spin lock, right? */ +#endif /* CONFIG_X86_LOCAL_APIC */ + return 1; +} + +#ifdef CONFIG_SMP + +static void __adeos_do_critical_sync (unsigned irq) + +{ + adeos_declare_cpuid; + unsigned long flags; + + adeos_lock_cpu(flags); + + set_bit(cpuid,&__adeos_cpu_sync_map); + + /* Now we are in sync with the lock requestor running on another + CPU. Enter a spinning wait until he releases the global + lock. */ + adeos_spin_lock(&__adeos_cpu_barrier); + + /* Got it. Now get out. */ + + if (__adeos_cpu_sync) + /* Call the sync routine if any. */ + __adeos_cpu_sync(); + + adeos_spin_unlock(&__adeos_cpu_barrier); + + clear_bit(cpuid,&__adeos_cpu_sync_map); + + adeos_unlock_cpu(flags); +} + +int __adeos_hw_cpuid (void) + +{ + if (!__adeos_apic_mapped) + return 0; + + { + unsigned long flags; + int cpuid; + +#ifdef CONFIG_MULTIQUAD + extern volatile int logical_apicid_2_cpu[]; + adeos_hw_local_irq_save(flags); + cpuid = logical_apicid_2_cpu[adeos_smp_apic_id()]; + adeos_hw_local_irq_restore(flags); +#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */ + extern volatile int physical_apicid_2_cpu[]; + adeos_hw_local_irq_save(flags); + cpuid = physical_apicid_2_cpu[adeos_smp_apic_id()]; + adeos_hw_local_irq_restore(flags); +#endif /* CONFIG_MULTIQUAD */ + + return cpuid; + } +} + +#endif /* CONFIG_SMP */ + +/* adeos_critical_enter() -- Grab the superlock excluding all CPUs + but the current one from a critical section. This lock is used when + we must enforce a global critical section for a single CPU in a + possibly SMP system whichever context the CPUs are running + (i.e. interrupt handler or regular thread). */ + +unsigned long adeos_critical_enter (void (*syncfn)(void)) + +{ + unsigned long flags; + + adeos_hw_local_irq_save(flags); + +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) /* We might be running a SMP-kernel on a UP box... */ + { + adeos_declare_cpuid; + + adeos_load_cpuid(); + + if (!test_and_set_bit(cpuid,&__adeos_cpu_lock_map)) + { + while (test_and_set_bit(BITS_PER_LONG - 1,&__adeos_cpu_lock_map)) + { + /* Refer to the explanations found in + linux/arch/asm-i386/irq.c about + SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND for more about + this strange loop. */ + int n = 0; + do { cpu_relax(); } while (++n < cpuid); + } + + adeos_spin_lock(&__adeos_cpu_barrier); + + __adeos_cpu_sync = syncfn; + + /* Send the sync IPI to all processors but the current one. */ + __adeos_send_IPI_allbutself(ADEOS_CRITICAL_VECTOR); + + while (__adeos_cpu_sync_map != (cpu_online_map & ~__adeos_cpu_lock_map)) + cpu_relax(); + } + + atomic_inc(&__adeos_critical_count); + } +#endif /* CONFIG_SMP */ + + return flags; +} + +/* adeos_critical_exit() -- Release the superlock. */ + +void adeos_critical_exit (unsigned long flags) + +{ +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) /* We might be running a SMP-kernel on a UP box... */ + { + adeos_declare_cpuid; + + adeos_load_cpuid(); + + if (atomic_dec_and_test(&__adeos_critical_count)) + { + adeos_spin_unlock(&__adeos_cpu_barrier); + + while (__adeos_cpu_sync_map != 0) + cpu_relax(); + + clear_bit(cpuid,&__adeos_cpu_lock_map); + clear_bit(BITS_PER_LONG - 1,&__adeos_cpu_lock_map); + } + } +#endif /* CONFIG_SMP */ + + adeos_hw_local_irq_restore(flags); +} + +void __adeos_init_stage (adomain_t *adp) + +{ + int cpuid, n; + + for (cpuid = 0; cpuid < ADEOS_NR_CPUS; cpuid++) + { + adp->cpudata[cpuid].irq_pending_hi = 0; + + for (n = 0; n < IPIPE_IRQ_IWORDS; n++) + adp->cpudata[cpuid].irq_pending_lo[n] = 0; + + for (n = 0; n < IPIPE_NR_IRQS; n++) + adp->cpudata[cpuid].irq_hits[n] = 0; + } + + for (n = 0; n < IPIPE_NR_IRQS; n++) + { + adp->irqs[n].acknowledge = NULL; + adp->irqs[n].handler = NULL; + adp->irqs[n].control = IPIPE_PASS_MASK; /* Pass but don't handle */ + } + +#ifdef CONFIG_SMP + adp->irqs[ADEOS_CRITICAL_IPI].acknowledge = &__adeos_ack_system_irq; + adp->irqs[ADEOS_CRITICAL_IPI].handler = &__adeos_do_critical_sync; + /* Immediately handle in the current domain but *never* pass */ + adp->irqs[ADEOS_CRITICAL_IPI].control = IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK; +#endif /* CONFIG_SMP */ +} + +/* __adeos_sync_stage() -- Flush the pending IRQs for the current + domain (and processor). This routine flushes the interrupt log + (see "Optimistic interrupt protection" from D. Stodolsky et al. for + more on the deferred interrupt scheme). Every interrupt that + occurred while the pipeline was stalled gets played. WARNING: + callers on SMP boxen should always check for CPU migration on + return of this routine. One can control the kind of interrupts + which are going to be sync'ed using the syncmask + parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT + plays virtual interrupts only. This routine must be called with hw + IRQs off. */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +void fastcall __adeos_sync_stage (unsigned long syncmask) +#else /* LINUX_VERSION_CODE < 2.4.27 */ +void __adeos_sync_stage (unsigned long syncmask) +#endif +{ + unsigned long mask, submask; + struct adcpudata *cpudata; + adeos_declare_cpuid; + int level, rank; + adomain_t *adp; + unsigned irq; + + adeos_load_cpuid(); + adp = adp_cpu_current[cpuid]; + cpudata = &adp->cpudata[cpuid]; + + /* The policy here is to keep the dispatching code interrupt-free + by stalling the current stage. If the upper domain handler + (which we call) wants to re-enable interrupts while in a safe + portion of the code (e.g. SA_INTERRUPT flag unset for Linux's + sigaction()), it will have to unstall (then stall again before + returning to us!) the stage when it sees fit. */ + + while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0) + { + /* Give a slight priority advantage to high-numbered IRQs + like the virtual ones. */ + level = flnz(mask); + __clear_bit(level,&cpudata->irq_pending_hi); + + while ((submask = cpudata->irq_pending_lo[level]) != 0) + { + rank = flnz(submask); + irq = (level << IPIPE_IRQ_ISHIFT) + rank; + + if (test_bit(IPIPE_LOCK_FLAG,&adp->irqs[irq].control)) + { + __clear_bit(rank,&cpudata->irq_pending_lo[level]); + continue; + } + + if (--cpudata->irq_hits[irq] == 0) + __clear_bit(rank,&cpudata->irq_pending_lo[level]); + + /* Allow the sync routine to be reentered on behalf of + the IRQ handler and any execution context switched + in by the IRQ handler. The latter also means that + returning from the switched out context is always + safe even if the sync routine has been reentered in + the meantime. */ + + __set_bit(IPIPE_STALL_FLAG,&cpudata->status); + +#ifdef CONFIG_ADEOS_PROFILING + __adeos_profile_data[cpuid].irqs[irq].n_synced++; + adeos_hw_tsc(__adeos_profile_data[cpuid].irqs[irq].t_synced); +#endif /* CONFIG_ADEOS_PROFILING */ + + if (adp == adp_root) + { + /* Make sure to re-enable hw interrupts to reduce + preemption latency by more prioritary domains + when calling Linux handlers. */ + + adeos_hw_sti(); + + if (test_bit(IPIPE_CALLASM_FLAG,&adp->irqs[irq].control)) + __adeos_call_asm_irq_handler(adp,irq); + else + __adeos_call_c_root_irq_handler(adp,irq); + } + else + __adeos_call_c_irq_handler(adp,irq); + + adeos_hw_cli(); + +#ifdef CONFIG_SMP + adeos_load_cpuid(); + cpudata = &adp->cpudata[cpuid]; +#endif /* CONFIG_SMP */ + + __clear_bit(IPIPE_STALL_FLAG,&cpudata->status); + } + } +} + +static inline void __adeos_walk_pipeline (struct list_head *pos, int cpuid) + +{ + adomain_t *this_domain = adp_cpu_current[cpuid]; + + while (pos != &__adeos_pipeline) + { + adomain_t *next_domain = list_entry(pos,adomain_t,p_link); + + if (test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) + break; /* Stalled stage -- do not go further. */ + + if (next_domain->cpudata[cpuid].irq_pending_hi != 0) + { + /* Since the critical IPI might be dispatched by the + following actions, the current domain might not be + linked to the pipeline anymore after its handler + returns on SMP boxes, even if the domain remains valid + (see adeos_unregister_domain()), so don't make any + dangerous assumptions here. */ + + if (next_domain == this_domain) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + else + { + __adeos_switch_to(this_domain,next_domain,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status) && + this_domain->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + break; + } + else if (next_domain == this_domain) + break; + + pos = next_domain->p_link.next; + } +} + +/* __adeos_handle_irq() -- ADEOS's generic IRQ handler. An optimistic + interrupt protection log is maintained here for each + domain. Interrupts are off on entry. */ + +int __adeos_handle_irq (struct pt_regs regs) + +{ + int m_ack = regs.orig_eax >= 0, s_ack; + unsigned irq = regs.orig_eax & 0xff; + struct list_head *head, *pos; + adeos_declare_cpuid; + + adeos_load_cpuid(); + +#ifdef CONFIG_ADEOS_PROFILING + __adeos_profile_data[cpuid].irqs[irq].n_handled++; + adeos_hw_tsc(__adeos_profile_data[cpuid].irqs[irq].t_handled); +#endif /* CONFIG_ADEOS_PROFILING */ + + s_ack = m_ack; + + if (unlikely(test_bit(IPIPE_STICKY_FLAG,&adp_cpu_current[cpuid]->irqs[irq].control))) + head = &adp_cpu_current[cpuid]->p_link; + else + head = __adeos_pipeline.next; + + /* Ack the interrupt. */ + + pos = head; + + while (pos != &__adeos_pipeline) + { + adomain_t *_adp = list_entry(pos,adomain_t,p_link); + + /* For each domain handling the incoming IRQ, mark it as + pending in its log. */ + + if (test_bit(IPIPE_HANDLE_FLAG,&_adp->irqs[irq].control)) + { + /* Domains that handle this IRQ are polled for + acknowledging it by decreasing priority order. The + interrupt must be made pending _first_ in the domain's + status flags before the PIC is unlocked. */ + + _adp->cpudata[cpuid].irq_hits[irq]++; + __adeos_set_irq_bit(_adp,cpuid,irq); + + /* Always get the first master acknowledge available. Once + we've got it, allow slave acknowledge handlers to run + (until one of them stops us). */ + + if (!m_ack) + m_ack = _adp->irqs[irq].acknowledge(irq); + else if (test_bit(IPIPE_SHARED_FLAG,&_adp->irqs[irq].control) && !s_ack) + s_ack = _adp->irqs[irq].acknowledge(irq); + } + + /* If the domain does not want the IRQ to be passed down the + interrupt pipe, exit the loop now. */ + + if (!test_bit(IPIPE_PASS_FLAG,&_adp->irqs[irq].control)) + break; + + pos = _adp->p_link.next; + } + + if (likely(irq == __adeos_tick_irq)) + { + __adeos_tick_regs.eflags = regs.eflags; + __adeos_tick_regs.eip = regs.eip; + __adeos_tick_regs.xcs = regs.xcs; + } + + /* Now walk the pipeline, yielding control to the highest priority + domain that has pending interrupt(s) or immediately to the + current domain if the interrupt has been marked as + 'sticky'. This search does not go beyond the current domain in + the pipeline. To understand this code properly, one must keep + in mind that domains having a higher priority than the current + one are sleeping on the adeos_suspend_domain() service. In + addition, domains having a lower priority have been preempted + by an interrupt dispatched to a more prioritary domain. Once + the first and most prioritary stage has been selected here, the + subsequent stages will be activated in turn when each visited + domain calls adeos_suspend_domain() to wake up its neighbour + down the pipeline. */ + + __adeos_walk_pipeline(head,cpuid); + + adeos_load_cpuid(); + + return (adp_cpu_current[cpuid] == adp_root && + !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status)); +} + +/* adeos_trigger_irq() -- Push the interrupt to the pipeline entry + just like if it has been actually received from a hw source. This + both works for real and virtual interrupts. This also means that + the current domain might be immediately preempted by a more + prioritary domain who happens to handle this interrupt. */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +int fastcall adeos_trigger_irq (unsigned irq) +#else /* LINUX_VERSION_CODE <= 2.4.27 */ +int adeos_trigger_irq (unsigned irq) +#endif +{ + struct pt_regs regs; + unsigned long flags; + + if (irq >= IPIPE_NR_IRQS || + (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map))) + return -EINVAL; + + adeos_hw_local_irq_save(flags); + + regs.orig_eax = irq; /* Won't be acked */ + regs.xcs = __KERNEL_CS; + regs.eflags = flags; + + __adeos_handle_irq(regs); + + adeos_hw_local_irq_restore(flags); + + return 1; +} + +static inline void __fixup_if (struct pt_regs *regs) + +{ + adeos_declare_cpuid; + unsigned long flags; + + adeos_get_cpu(flags); + + if (adp_cpu_current[cpuid] == adp_root) + { + /* Have the saved hw state look like the domain stall bit, so that + __adeos_unstall_iret_root() restores the proper pipeline state + for the root stage upon exit. */ + + if (test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status)) + regs->eflags &= ~0x200; + else + regs->eflags |= 0x200; + } + + adeos_put_cpu(flags); +} + +asmlinkage void __adeos_if_fixup_root (struct pt_regs regs) + +{ + if (likely(adp_pipelined)) + __fixup_if(®s); +} + +asmlinkage int __adeos_enter_syscall (struct pt_regs regs) + +{ + if (unlikely(__adeos_event_monitors[ADEOS_SYSCALL_PROLOGUE] > 0)) + { + int s = __adeos_handle_event(ADEOS_SYSCALL_PROLOGUE,®s); + /* We might enter here over a non-root domain and exit over + the root one as a result of the issued syscall (i.e. by + recycling the register set of the current context across + the migration), so we need to fixup the interrupt flag upon + return too, so that __adeos_unstall_iret_root() resets the + correct stall bit on exit. */ + __fixup_if(®s); + return s; + } + + return 0; +} + +asmlinkage int __adeos_exit_syscall (void) + +{ + if (unlikely(__adeos_event_monitors[ADEOS_SYSCALL_EPILOGUE] > 0)) + return __adeos_handle_event(ADEOS_SYSCALL_EPILOGUE,NULL); + + return 0; +} + +asmlinkage void __adeos_unstall_iret_root (struct pt_regs regs) + +{ + adeos_declare_cpuid; + + if (!adp_pipelined) + return; + + /* Emulate a software IRET. */ + + adeos_hw_cli(); + + adeos_load_cpuid(); + + /* Restore the software state as it used to be on kernel entry. */ + + if (!(regs.eflags & 0x200)) + { + __set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + regs.eflags |= 0x200; + } + else + { + __clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + + /* Only sync virtual IRQs here, so that we don't recurse + indefinitely in case of an external interrupt flood. */ + + if ((adp_root->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0) + __adeos_sync_stage(IPIPE_IRQMASK_VIRT); + } +} diff -uNrp linux-2.4.31/arch/i386/kernel/apic.c linux-2.4.31-r18/arch/i386/kernel/apic.c --- linux-2.4.31/arch/i386/kernel/apic.c 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/apic.c 2005-06-20 23:53:14.000000000 +0200 @@ -1096,7 +1096,7 @@ inline void smp_local_timer_interrupt(st * Currently this isn't too much of an issue (performance wise), * we can take more than 100K local irqs per second on a 100 MHz P5. */ -} + } /* * Local APIC timer interrupt. This is the most natural way for doing @@ -1121,6 +1121,11 @@ void smp_apic_timer_interrupt(struct pt_ * NOTE! We'd better ACK the irq immediately, * because timer handling can be slow. */ +#ifdef CONFIG_ADEOS_CORE + if (adp_pipelined) + regs = &__adeos_tick_regs; + else +#endif /* CONFIG_ADEOS_CORE */ ack_APIC_irq(); /* * update_process_times() expects us to have done irq_enter(). @@ -1168,6 +1173,9 @@ asmlinkage void smp_error_interrupt(void v = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); +#ifdef CONFIG_ADEOS_CORE + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ ack_APIC_irq(); atomic_inc(&irq_err_count); diff -uNrp linux-2.4.31/arch/i386/kernel/entry.S linux-2.4.31-r18/arch/i386/kernel/entry.S --- linux-2.4.31/arch/i386/kernel/entry.S 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/kernel/entry.S 2005-06-20 23:52:47.000000000 +0200 @@ -84,6 +84,11 @@ processor = 52 ENOSYS = 38 +#ifdef CONFIG_ADEOS_CORE +#define cli call __adeos_stall_root +#define sti call __adeos_unstall_root +#endif /* CONFIG_ADEOS_CORE */ + #define SAVE_ALL \ cld; \ pushl %es; \ @@ -138,6 +143,12 @@ ENTRY(lcall7) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_if_fixup_root) + call SYMBOL_NAME(__adeos_enter_syscall) + testl %eax,%eax + jne restore_all +#endif /* CONFIG_ADEOS_CORE */ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. @@ -155,13 +166,26 @@ ENTRY(lcall7) pushl $0x7 call *%edx addl $4, %esp +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_exit_syscall) + testl %eax,%eax + popl %eax + jne restore_all +#else /* !CONFIG_ADEOS_CORE */ popl %eax +#endif /* CONFIG_ADEOS_CORE */ jmp ret_from_sys_call ENTRY(lcall27) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_if_fixup_root) + call SYMBOL_NAME(__adeos_enter_syscall) + testl %eax,%eax + jne restore_all +#endif /* CONFIG_ADEOS_CORE */ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. @@ -179,11 +203,21 @@ ENTRY(lcall27) pushl $0x27 call *%edx addl $4, %esp +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_exit_syscall) + testl %eax,%eax popl %eax + jne restore_all +#else /* !CONFIG_ADEOS_CORE */ + popl %eax +#endif /* CONFIG_ADEOS_CORE */ jmp ret_from_sys_call ENTRY(ret_from_fork) +#ifdef CONFIG_ADEOS_CORE + sti +#endif /* CONFIG_ADEOS_CORE */ pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp @@ -202,6 +236,13 @@ ENTRY(ret_from_fork) ENTRY(system_call) pushl %eax # save orig_eax SAVE_ALL +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_if_fixup_root) + call SYMBOL_NAME(__adeos_enter_syscall) + testl %eax,%eax + jne restore_all + movl ORIG_EAX(%esp),%eax +#endif /* CONFIG_ADEOS_CORE */ GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys @@ -209,18 +250,26 @@ ENTRY(system_call) jae badsys call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_exit_syscall) + testl %eax,%eax + jne restore_all +#endif /* CONFIG_ADEOS_CORE */ ENTRY(ret_from_sys_call) - cli # need_resched and signals atomic test + cli cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_return +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_unstall_iret_root) +#endif /* CONFIG_ADEOS_CORE */ restore_all: RESTORE_ALL ALIGN signal_return: - sti # we can get here from an interrupt handler + sti testl $(VM_MASK),EFLAGS(%esp) movl %esp,%eax jne v86_signal_return @@ -288,6 +337,9 @@ error_code: movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_if_fixup_root) +#endif /* CONFIG_ADEOS_CORE */ movl %esp,%edx pushl %esi # push the error code pushl %edx # push the pt_regs pointer @@ -312,6 +364,9 @@ ENTRY(simd_coprocessor_error) ENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL +#ifdef CONFIG_ADEOS_CORE + call SYMBOL_NAME(__adeos_if_fixup_root) +#endif /* CONFIG_ADEOS_CORE */ GET_CURRENT(%ebx) movl %cr0,%eax testl $0x4,%eax # EM (math emulation bit) diff -uNrp linux-2.4.31/arch/i386/kernel/i386_ksyms.c linux-2.4.31-r18/arch/i386/kernel/i386_ksyms.c --- linux-2.4.31/arch/i386/kernel/i386_ksyms.c 2004-04-14 15:05:25.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/kernel/i386_ksyms.c 2005-06-20 23:53:06.000000000 +0200 @@ -33,6 +33,57 @@ extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; +#ifdef CONFIG_ADEOS_CORE +EXPORT_SYMBOL(adp_pipelined); +EXPORT_SYMBOL(adeos_critical_enter); +EXPORT_SYMBOL(adeos_critical_exit); +EXPORT_SYMBOL(adeos_trigger_irq); +EXPORT_SYMBOL(__adeos_sync_stage); +EXPORT_SYMBOL(__adeos_handle_irq); +EXPORT_SYMBOL(__adeos_ack_system_irq); +EXPORT_SYMBOL(__adeos_tick_regs); +EXPORT_SYMBOL(__adeos_tick_irq); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(__adeos_send_IPI_mask); +EXPORT_SYMBOL(__adeos_send_IPI_allbutself); +EXPORT_SYMBOL(__adeos_set_irq_affinity); +#endif /* CONFIG_SMP */ +#ifdef CONFIG_ADEOS_MODULE +#ifdef CONFIG_X86_LOCAL_APIC +extern int using_apic_timer; +EXPORT_SYMBOL_NOVERS(using_apic_timer); +#endif /* CONFIG_X86_LOCAL_APIC */ +#endif /* CONFIG_ADEOS_MODULE */ +/* The following are per-platform convenience exports which are needed + by some Adeos domains loaded as kernel modules. */ +extern irq_desc_t irq_desc[]; +EXPORT_SYMBOL_NOVERS(irq_desc); +extern struct desc_struct idt_table[]; +EXPORT_SYMBOL_NOVERS(idt_table); +extern void ret_from_intr(void); +EXPORT_SYMBOL_NOVERS(ret_from_intr); +#ifdef CONFIG_VT +extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); +EXPORT_SYMBOL_NOVERS(kd_mksound); +#endif /* CONFIG_VT */ +#ifdef CONFIG_SMP +EXPORT_SYMBOL_NOVERS(cpu_tlbstate); +EXPORT_SYMBOL_NOVERS(__adeos_hw_cpuid); +#endif /* CONFIG_SMP */ +#if defined(CONFIG_ADEOS_MODULE) && defined(CONFIG_X86_IO_APIC) +EXPORT_SYMBOL_NOVERS(io_apic_irqs); +EXPORT_SYMBOL_NOVERS(irq_vector); +#endif /* CONFIG_ADEOS_MODULE && CONFIG_X86_IO_APIC */ +EXPORT_SYMBOL_NOVERS(set_ldt_desc); +EXPORT_SYMBOL_NOVERS(default_ldt); +EXPORT_SYMBOL_NOVERS(__switch_to); +EXPORT_SYMBOL_NOVERS(cpu_khz); +extern void show_stack(unsigned long *esp); +EXPORT_SYMBOL_NOVERS(show_stack); +extern void show_registers(struct pt_regs *regs); +EXPORT_SYMBOL_NOVERS(show_registers); +#endif /* CONFIG_ADEOS_CORE */ + #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern void machine_real_restart(unsigned char *, int); EXPORT_SYMBOL(machine_real_restart); diff -uNrp linux-2.4.31/arch/i386/kernel/i8259.c linux-2.4.31-r18/arch/i386/kernel/i8259.c --- linux-2.4.31/arch/i386/kernel/i8259.c 2004-08-08 01:26:04.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/kernel/i8259.c 2005-06-20 23:52:09.000000000 +0200 @@ -266,6 +266,36 @@ static inline int i8259A_irq_real(unsign */ void mask_and_ack_8259A(unsigned int irq) { +#ifdef CONFIG_ADEOS_CORE + unsigned int irqmask = 1 << irq; + + spin_lock(&i8259A_lock); + + if (cached_irq_mask & irqmask) + goto spurious_8259A_irq; + + if (irq == 0) { + /* Fast timer ack -- don't mask + (unless supposedly spurious) */ + outb(0x20,0x20); + spin_unlock(&i8259A_lock); + return; + } + + cached_irq_mask |= irqmask; + +handle_real_irq: + if (irq & 8) { + outb(cached_A1,0xA1); + outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ + outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + } else { + outb(cached_21,0x21); + outb(0x60+irq,0x20); /* 'Specific EOI' to master */ + } + spin_unlock(&i8259A_lock); + return; +#else /* !CONFIG_ADEOS_CORE */ unsigned int irqmask = 1 << irq; unsigned long flags; @@ -302,6 +332,7 @@ handle_real_irq: } spin_unlock_irqrestore(&i8259A_lock, flags); return; +#endif /* CONFIG_ADEOS_CORE */ spurious_8259A_irq: /* diff -uNrp linux-2.4.31/arch/i386/kernel/io_apic.c linux-2.4.31-r18/arch/i386/kernel/io_apic.c --- linux-2.4.31/arch/i386/kernel/io_apic.c 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/io_apic.c 2005-06-20 23:52:57.000000000 +0200 @@ -1250,6 +1250,25 @@ static unsigned int startup_edge_ioapic_ * interrupt for real. This prevents IRQ storms from unhandled * devices. */ + +#ifdef CONFIG_ADEOS_CORE + +static void ack_edge_ioapic_irq (unsigned irq) + +{ + if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) + { + unsigned long flags; + adeos_spin_lock_irqsave(&ioapic_lock,flags); + __mask_IO_APIC_irq(irq); + adeos_spin_unlock_irqrestore(&ioapic_lock,flags); + } + + ack_APIC_irq(); +} + +#else /* !CONFIG_ADEOS_CORE */ + static void ack_edge_ioapic_irq(unsigned int irq) { if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) @@ -1258,6 +1277,8 @@ static void ack_edge_ioapic_irq(unsigned ack_APIC_irq(); } +#endif /* CONFIG_ADEOS_CORE */ + static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ } @@ -1286,6 +1307,65 @@ static unsigned int startup_level_ioapic #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq +#ifdef CONFIG_ADEOS_CORE + +/* The standard Linux implementation for acknowledging IO-APIC + interrupts has been changed in order to guarantee that low priority + IRQs won't be delayed waiting for a high priority interrupt handler + to call end_level_ioapic_irq(). Therefore we immediately ack in + mask_and_ack_level_ioapic_irq(), still handling the 82093AA bugous + edge case. */ + +static unsigned long bugous_edge_triggers; + +static void end_level_ioapic_irq (unsigned irq) + +{ + if (test_and_clear_bit(irq,&bugous_edge_triggers)) + { +#ifdef APIC_MISMATCH_DEBUG + atomic_inc(&irq_mis_count); +#endif + spin_lock(&ioapic_lock); + __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 irq) + +{ + unsigned long v; + int i; + + i = IO_APIC_VECTOR(irq); + v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); + + if (!(v & (1 << (i & 0x1f)))) + { + set_bit(irq,&bugous_edge_triggers); + 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(); +} + +#else /* !CONFIG_ADEOS_CORE */ + static void end_level_ioapic_irq (unsigned int irq) { unsigned long v; @@ -1347,6 +1427,8 @@ static void end_level_ioapic_irq (unsign static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } +#endif /* CONFIG_ADEOS_CORE */ + #ifndef CONFIG_SMP void fastcall send_IPI_self(int vector) diff -uNrp linux-2.4.31/arch/i386/kernel/irq.c linux-2.4.31-r18/arch/i386/kernel/irq.c --- linux-2.4.31/arch/i386/kernel/irq.c 2003-11-28 19:26:19.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/irq.c 2005-06-20 23:52:18.000000000 +0200 @@ -595,6 +595,9 @@ asmlinkage unsigned int do_IRQ(struct pt kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); +#ifdef CONFIG_ADEOS_CORE + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ desc->handler->ack(irq); /* REPLAY is when Linux resends an IRQ that was dropped earlier @@ -636,6 +639,11 @@ asmlinkage unsigned int do_IRQ(struct pt */ for (;;) { spin_unlock(&desc->lock); +#ifdef CONFIG_ADEOS_CORE + if (likely(adp_pipelined && __adeos_tick_irq == irq)) + handle_IRQ_event(irq,&__adeos_tick_regs,action); + else +#endif /* CONFIG_ADEOS_CORE */ handle_IRQ_event(irq, ®s, action); spin_lock(&desc->lock); @@ -1125,6 +1133,29 @@ static int irq_affinity_write_proc (stru return full_count; } +#ifdef CONFIG_ADEOS_CORE + +unsigned long __adeos_set_irq_affinity (unsigned irq, unsigned long cpumask) + +{ + unsigned long oldmask = irq_affinity[irq]; + + if (cpumask == 0) + return oldmask; /* Return mask value -- no change. */ + + cpumask &= cpu_online_map; + + if (cpumask == 0 || irq_desc[irq].handler->set_affinity == NULL) + return 0; /* Error -- bad mask value or non-routable IRQ. */ + + irq_affinity[irq] = cpumask; + irq_desc[irq].handler->set_affinity(irq,cpumask); + + return oldmask; +} + +#endif /* CONFIG_ADEOS_CORE */ + #endif static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, @@ -1212,4 +1243,3 @@ void init_irq_proc (void) for (i = 0; i < NR_IRQS; i++) register_irq_proc(i); } - diff -uNrp linux-2.4.31/arch/i386/kernel/Makefile linux-2.4.31-r18/arch/i386/kernel/Makefile --- linux-2.4.31/arch/i386/kernel/Makefile 2005-04-04 03:42:19.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/kernel/Makefile 2005-06-20 23:51:59.000000000 +0200 @@ -14,7 +14,7 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o setup.o +export-objs := adeos.o mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o setup.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ @@ -30,6 +30,7 @@ obj-y += pci-pc.o pci-irq.o endif endif +obj-$(CONFIG_ADEOS_CORE) += adeos.o obj-$(CONFIG_MCA) += mca.o obj-$(CONFIG_MTRR) += mtrr.o obj-$(CONFIG_X86_MSR) += msr.o diff -uNrp linux-2.4.31/arch/i386/kernel/nmi.c linux-2.4.31-r18/arch/i386/kernel/nmi.c --- linux-2.4.31/arch/i386/kernel/nmi.c 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/kernel/nmi.c 2005-06-20 23:52:26.000000000 +0200 @@ -363,6 +363,9 @@ void nmi_watchdog_tick (struct pt_regs * bust_spinlocks(1); printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip); show_registers(regs); +#ifdef CONFIG_ADEOS_CORE + __adeos_dump_state(); +#endif /* CONFIG_ADEOS_CORE */ printk("console shuts up ...\n"); console_silent(); spin_unlock(&nmi_print_lock); diff -uNrp linux-2.4.31/arch/i386/kernel/process.c linux-2.4.31-r18/arch/i386/kernel/process.c --- linux-2.4.31/arch/i386/kernel/process.c 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/process.c 2005-06-20 23:53:54.000000000 +0200 @@ -134,6 +134,9 @@ void cpu_idle (void) void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; +#ifdef CONFIG_ADEOS_CORE + adeos_suspend_domain(); +#endif /* CONFIG_ADEOS_CORE */ while (!current->need_resched) idle(); schedule(); diff -uNrp linux-2.4.31/arch/i386/kernel/smpboot.c linux-2.4.31-r18/arch/i386/kernel/smpboot.c --- linux-2.4.31/arch/i386/kernel/smpboot.c 2004-04-14 15:05:25.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/kernel/smpboot.c 2005-06-20 23:53:23.000000000 +0200 @@ -1012,6 +1012,9 @@ void __init smp_boot_cpus(void) else boot_cpu_logical_apicid = logical_smp_processor_id(); map_cpu_to_boot_apicid(0, boot_cpu_apicid); +#ifdef CONFIG_ADEOS_CORE + __adeos_apic_mapped = 1; +#endif /* CONFIG_ADEOS_CORE */ global_irq_holder = 0; current->processor = 0; diff -uNrp linux-2.4.31/arch/i386/kernel/smp.c linux-2.4.31-r18/arch/i386/kernel/smp.c --- linux-2.4.31/arch/i386/kernel/smp.c 2004-11-17 12:54:21.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/smp.c 2005-06-20 23:52:36.000000000 +0200 @@ -134,6 +134,11 @@ static inline void __send_IPI_shortcut(u */ unsigned int cfg; +#ifdef CONFIG_ADEOS_CORE + unsigned long flags; + adeos_hw_local_irq_save(flags); +#endif /* !CONFIG_ADEOS_CORE */ + /* * Wait for idle. */ @@ -148,6 +153,10 @@ static inline void __send_IPI_shortcut(u * Send the IPI. The write to APIC_ICR fires this off. */ apic_write_around(APIC_ICR, cfg); + +#ifdef CONFIG_ADEOS_CORE + adeos_hw_local_irq_restore(flags); +#endif /* !CONFIG_ADEOS_CORE */ } void fastcall send_IPI_self(int vector) @@ -160,9 +169,12 @@ static inline void send_IPI_mask_bitmask unsigned long cfg; unsigned long flags; +#ifdef CONFIG_ADEOS_CORE + adeos_hw_local_irq_save(flags); +#else /* !CONFIG_ADEOS_CORE */ __save_flags(flags); __cli(); - +#endif /* CONFIG_ADEOS_CORE */ /* * Wait for idle. @@ -185,7 +197,11 @@ static inline void send_IPI_mask_bitmask */ apic_write_around(APIC_ICR, cfg); +#ifdef CONFIG_ADEOS_CORE + adeos_hw_local_irq_restore(flags); +#else /* !CONFIG_ADEOS_CORE */ __restore_flags(flags); +#endif /* CONFIG_ADEOS_CORE */ } static inline void send_IPI_mask_sequence(int mask, int vector) @@ -199,8 +215,12 @@ static inline void send_IPI_mask_sequenc * should be modified to do 1 message per cluster ID - mbligh */ +#ifdef CONFIG_ADEOS_CORE + adeos_hw_local_irq_save(flags); +#else /* !CONFIG_ADEOS_CORE */ __save_flags(flags); __cli(); +#endif /* CONFIG_ADEOS_CORE */ for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) { query_mask = 1 << query_cpu; @@ -231,7 +251,11 @@ static inline void send_IPI_mask_sequenc apic_write_around(APIC_ICR, cfg); } } +#ifdef CONFIG_ADEOS_CORE + adeos_hw_local_irq_restore(flags); +#else /* !CONFIG_ADEOS_CORE */ __restore_flags(flags); +#endif /* CONFIG_ADEOS_CORE */ } static inline void send_IPI_mask(int mask, int vector) @@ -382,7 +406,11 @@ asmlinkage void smp_invalidate_interrupt } else leave_mm(cpu); } +#ifdef CONFIG_ADEOS_CORE + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ ack_APIC_irq(); + clear_bit(cpu, &flush_cpumask); } @@ -603,6 +631,9 @@ void smp_send_stop(void) */ asmlinkage void smp_reschedule_interrupt(void) { +#ifdef CONFIG_ADEOS_CORE + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ ack_APIC_irq(); } @@ -612,6 +643,9 @@ asmlinkage void smp_call_function_interr void *info = call_data->info; int wait = call_data->wait; +#ifdef CONFIG_ADEOS_CORE + if (!adp_pipelined) +#endif /* CONFIG_ADEOS_CORE */ ack_APIC_irq(); /* * Notify initiating CPU that I've grabbed the data and am @@ -629,3 +663,14 @@ asmlinkage void smp_call_function_interr } } +#ifdef CONFIG_ADEOS_CORE + +void __adeos_send_IPI_mask (cpumask_t cpumask, int vector) { + send_IPI_mask(cpumask,vector); +} + +void __adeos_send_IPI_allbutself (int vector) { + send_IPI_allbutself(vector); +} + +#endif /* CONFIG_ADEOS_CORE */ diff -uNrp linux-2.4.31/arch/i386/kernel/time.c linux-2.4.31-r18/arch/i386/kernel/time.c --- linux-2.4.31/arch/i386/kernel/time.c 2004-02-18 14:36:30.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/time.c 2005-06-21 22:57:05.000000000 +0200 @@ -211,13 +211,22 @@ static unsigned long do_slow_gettimeoffs int i; +#ifdef CONFIG_ADEOS_CORE + unsigned long flags; + adeos_spin_lock_irqsave(&i8259A_lock, flags); +#else /* !CONFIG_ADEOS_CORE */ spin_lock(&i8259A_lock); +#endif /* CONFIG_ADEOS_CORE */ /* * This is tricky when I/O APICs are used; * see do_timer_interrupt(). */ i = inb(0x20); +#ifdef CONFIG_ADEOS_CORE + adeos_spin_unlock_irqrestore(&i8259A_lock, flags); +#else /* !CONFIG_ADEOS_CORE */ spin_unlock(&i8259A_lock); +#endif /* CONFIG_ADEOS_CORE */ /* assumption about timer being IRQ0 */ if (i & 0x01) { @@ -577,11 +586,20 @@ static inline void do_timer_interrupt(in * This will also deassert NMI lines for the watchdog if run * on an 82489DX-based system. */ +#ifdef CONFIG_ADEOS_CORE + unsigned long flags; + adeos_spin_lock_irqsave(&i8259A_lock, flags); +#else /* !CONFIG_ADEOS_CORE */ spin_lock(&i8259A_lock); +#endif /* CONFIG_ADEOS_CORE */ outb(0x0c, 0x20); /* Ack the IRQ; AEOI will end it automatically. */ inb(0x20); +#ifdef CONFIG_ADEOS_CORE + adeos_spin_unlock_irqrestore(&i8259A_lock, flags); +#else /* !CONFIG_ADEOS_CORE */ spin_unlock(&i8259A_lock); +#endif /* CONFIG_ADEOS_CORE */ } #endif @@ -644,8 +662,10 @@ static int use_tsc; */ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { +#ifndef CONFIG_ADEOS_CORE int count; - +#endif /* !CONFIG_ADEOS_CORE */ + /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other @@ -674,6 +694,7 @@ static void timer_interrupt(int irq, voi rdtscl(last_tsc_low); +#ifndef CONFIG_ADEOS_CORE spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -705,6 +726,7 @@ static void timer_interrupt(int irq, voi count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; +#endif /* !CONFIG_ADEOS_CORE */ } do_timer_interrupt(irq, NULL, regs); diff -uNrp linux-2.4.31/arch/i386/kernel/traps.c linux-2.4.31-r18/arch/i386/kernel/traps.c --- linux-2.4.31/arch/i386/kernel/traps.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/kernel/traps.c 2005-06-20 23:53:32.000000000 +0200 @@ -754,6 +754,10 @@ asmlinkage void do_spurious_interrupt_bu */ asmlinkage void math_state_restore(struct pt_regs regs) { +#ifdef CONFIG_ADEOS_CORE + unsigned long flags; + adeos_hw_local_irq_save(flags); +#endif /* CONFIG_ADEOS_CORE */ __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */ if (current->used_math) { @@ -762,6 +766,9 @@ asmlinkage void math_state_restore(struc init_fpu(); } current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */ +#ifdef CONFIG_ADEOS_CORE + adeos_hw_local_irq_restore(flags); +#endif /* CONFIG_ADEOS_CORE */ } #ifndef CONFIG_MATH_EMULATION diff -uNrp linux-2.4.31/arch/i386/mm/fault.c linux-2.4.31-r18/arch/i386/mm/fault.c --- linux-2.4.31/arch/i386/mm/fault.c 2004-08-08 01:26:04.000000000 +0200 +++ linux-2.4.31-r18/arch/i386/mm/fault.c 2005-06-20 23:51:29.000000000 +0200 @@ -153,7 +153,11 @@ asmlinkage void do_page_fault(struct pt_ /* It's safe to allow irq's after cr2 has been saved */ if (regs->eflags & X86_EFLAGS_IF) - local_irq_enable(); +#ifdef CONFIG_ADEOS_CORE + adeos_hw_sti(); +#else /* !CONFIG_ADEOS_CORE */ + local_irq_enable(); +#endif /* CONFIG_ADEOS_CORE */ tsk = current; diff -uNrp linux-2.4.31/arch/i386/mm/ioremap.c linux-2.4.31-r18/arch/i386/mm/ioremap.c --- linux-2.4.31/arch/i386/mm/ioremap.c 2003-11-28 19:26:19.000000000 +0100 +++ linux-2.4.31-r18/arch/i386/mm/ioremap.c 2005-06-20 23:51:13.000000000 +0200 @@ -81,6 +81,9 @@ static int remap_area_pages(unsigned lon if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) break; +#ifdef CONFIG_ADEOS_CORE + set_pgdir(address, *dir); +#endif /* CONFIG_ADEOS_CORE */ error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; diff -uNrp linux-2.4.31/Documentation/adeos.txt linux-2.4.31-r18/Documentation/adeos.txt --- linux-2.4.31/Documentation/adeos.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/Documentation/adeos.txt 2004-03-21 18:34:47.000000000 +0100 @@ -0,0 +1,172 @@ + +The Adeos nanokernel is based on research and publications made in the +early '90s on the subject of nanokernels. Our basic method was to +reverse the approach described in most of the papers on the subject. +Instead of first building the nanokernel and then building the client +OSes, we started from a live and known-to-be-functional OS, Linux, and +inserted a nanokernel beneath it. Starting from Adeos, other client +OSes can now be put side-by-side with the Linux kernel. + +To this end, Adeos enables multiple domains to exist simultaneously on +the same hardware. None of these domains see each other, but all of +them see Adeos. A domain is most probably a complete OS, but there is +no assumption being made regarding the sophistication of what's in +a domain. + +To share the hardware among the different OSes, Adeos implements an +interrupt pipeline (ipipe). Every OS domain has an entry in the ipipe. +Each interrupt that comes in the ipipe is passed on to every domain +in the ipipe. Instead of disabling/enabling interrupts, each domain +in the pipeline only needs to stall/unstall his pipeline stage. If +an ipipe stage is stalled, then the interrupts do not progress in the +ipipe until that stage has been unstalled. Each stage of the ipipe +can, of course, decide to do a number of things with an interrupt. +Among other things, it can decide that it's the last recipient of the +interrupt. In that case, the ipipe does not propagate the interrupt +to the rest of the domains in the ipipe. + +No hosted domain is allowed to use the real hardware cli/sti. But this +is OK, since the stall/unstall calls achieve the same functionality. + +Our approach is based on the following papers (links to these +papers are provided at the bottom of this message): +[1] D. Probert, J. Bruno, and M. Karzaorman. "Space: a new approach to +operating system abstraction." In: International Workshop on Object +Orientation in Operating Systems, pages 133-137, October 1991. +[2] D. Probert, J. Bruno. "Building fundamentally extensible application- +specific operating systems in Space", March 1995. +[3] D. Cheriton, K. Duda. "A caching model of operating system kernel +functionality". In: Proc. Symp. on Operating Systems Design and +Implementation, pages 179-194, Monterey CA (USA), 1994. +[4] D. Engler, M. Kaashoek, and J. O'Toole Jr. "Exokernel: an operating +system architecture for application-specific resource management", +December 1995. + +If you don't want to go fetch the complete papers, here's a summary. +The first 2 discuss the Space nanokernel, the 3rd discussed the cache +nanokernel, and the last discusses exokernel. + +The complete Adeos approach has been thoroughly documented in a whitepaper +published more than a year ago entitled "Adaptive Domain Environment +for Operating Systems" and available here: http://www.opersys.com/adeos +The current implementation is slightly different. Mainly, we do not +implement the functionality to move Linux out of ring 0. Although of +interest, this approach is not very portable. + +Instead, our patch taps right into Linux's main source of control +over the hardware, the interrupt dispatching code, and inserts an +interrupt pipeline which can then serve all the nanokernel's clients, +including Linux. + +This is not a novelty in itself. Other OSes have been modified in such +a way for a wide range of purposes. One of the most interesting +examples is described by Stodolsky, Chen, and Bershad in a paper +entitled "Fast Interrupt Priority Management in Operating System +Kernels" published in 1993 as part of the Usenix Microkernels and +Other Kernel Architectures Symposium. In that case, cli/sti were +replaced by virtual cli/sti which did not modify the real interrupt +mask in any way. Instead, interrupts were defered and delivered to +the OS upon a call to the virtualized sti. + +Mainly, this resulted in increased performance for the OS. Although +we haven't done any measurements on Linux's interrupt handling +performance with Adeos, our nanokernel includes by definition the +code implementing the technique described in the abovementioned +Stodolsky paper, which we use to redirect the hardware interrupt flow +to the pipeline. + +i386 and armnommu are currently supported. Most of the +architecture-dependent code is easily portable to other architectures. + +Aside of adding the Adeos module (driver/adeos), we also modified some +files to tap into Linux interrupt and system event dispatching (all +the modifications are encapsulated in #ifdef CONFIG_ADEOS_*/#endif). + +We modified the idle task so it gives control back to Adeos in order for +the ipipe to continue propagation. + +We modified init/main.c to initialize Adeos very early in the startup. + +Of course, we also added the appropriate makefile modifications and +config options so that you can choose to enable/disable Adeos as +part of the kernel build configuration. + +Adeos' public API is fully documented here: +http://home.gna.org/adeos/doc/api/index.html. + +In Linux's case, adeos_register_domain() is called very early during +system startup. + +To add your domain to the ipipe, you need to: +1) Register your domain with Adeos using adeos_register_domain() +2) Call adeos_virtualize_irq() for all the IRQs you wish to be +notified about in the ipipe. + +That's it. Provided you gave Adeos appropriate handlers in step +#2, your interrupts will be delivered via the ipipe. + +During runtime, you may change your position in the ipipe using +adeos_renice_domain(). You may also stall/unstall the pipeline +and change the ipipe's handling of the interrupts according to your +needs. + +Over x86, Adeos supports SMP, and local/IO-APIC on UP. + +Here are some of the possible uses for Adeos (this list is far +from complete): +1) Much like User-Mode Linux, it should now be possible to have 2 +Linux kernels living side-by-side on the same hardware. In contrast +to UML, this would not be 2 kernels one ontop of the other, but +really side-by-side. Since Linux can be told at boot time to use +only one portion of the available RAM, on a 128MB machine this +would mean that the first could be made to use the 0-64MB space and +the second would use the 64-128MB space. We realize that many +modifications are required. Among other things, one of the 2 kernels +will not need to conduct hardware initialization. Nevertheless, this +possibility should be studied closer. + +2) It follows from #1 that adding other kernels beside Linux should +be feasible. BSD is a prime candidate, but it would also be nice to +see what virtualizers such as VMWare and Plex86 could do with Adeos. +Proprietary operating systems could potentially also be accomodated. + +3) All the previous work that has been done on nanokernels should now +be easily ported to Linux. Mainly, we would be very interested to +hear about extensions to Adeos. Primarily, we have no mechanisms +currently enabling multiple domains to share information. The papers +mentioned earlier provide such mechanisms, but we'd like to see +actual practical examples. + +4) Kernel debuggers' main problem (tapping into the kernel's +interrupts) is solved and it should then be possible to provide +patchless kernel debuggers. They would then become loadable kernel +modules. + +5) Drivers who require absolute priority and dislike other kernel +portions who use cli/sti can now create a domain of their own +and place themselves before Linux in the ipipe. This provides a +mechanism for the implementation of systems that can provide guaranteed +realtime response. + +Philippe Gerum +Karim Yaghmour + +---------------------------------------------------------------------- +Links to papers: +1- +http://citeseer.nj.nec.com/probert91space.html +ftp://ftp.cs.ucsb.edu/pub/papers/space/iwooos91.ps.gz (not working) +http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-iwooos91.ps.gz + +2- +http://www.cs.ucsb.edu/research/trcs/abstracts/1995-06.shtml +http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-trcs95-06.ps.gz + +3- +http://citeseer.nj.nec.com/kenneth94caching.html +http://guir.cs.berkeley.edu/projects/osprelims/papers/cachmodel-OSkernel.ps.gz + +4- +http://citeseer.nj.nec.com/engler95exokernel.html +ftp://ftp.cag.lcs.mit.edu/multiscale/exokernel.ps.Z +---------------------------------------------------------------------- diff -uNrp linux-2.4.31/include/asm-i386/adeos.h linux-2.4.31-r18/include/asm-i386/adeos.h --- linux-2.4.31/include/asm-i386/adeos.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/include/asm-i386/adeos.h 2005-06-02 23:17:45.000000000 +0200 @@ -0,0 +1,461 @@ +/* + * include/asm-i386/adeos.h + * + * Copyright (C) 2002 Philippe Gerum. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __I386_ADEOS_H +#define __I386_ADEOS_H + +struct task_struct; + +#include +#include +#include +#include +#include +#include +#include + +#define ADEOS_ARCH_STRING "r18c1/x86" +#define ADEOS_MAJOR_NUMBER 18 +#define ADEOS_MINOR_NUMBER 1 + +extern int adp_pipelined; + +typedef unsigned long cpumask_t; + +#ifdef CONFIG_SMP + +#include +#include + +extern int smp_num_cpus; + +#define ADEOS_NR_CPUS NR_CPUS +#define ADEOS_CRITICAL_VECTOR 0xf9 /* Used by adeos_critical_enter/exit() */ +#define ADEOS_CRITICAL_IPI (ADEOS_CRITICAL_VECTOR - FIRST_EXTERNAL_VECTOR) + +static __inline int adeos_smp_apic_id(void) { + return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)); +} + +/* Cannot include asm/smpboot.h safely, so we define here the little + we need to know about CPU/apicid mappings. */ + +int __adeos_hw_cpuid(void); + +#define adeos_processor_id() __adeos_hw_cpuid() + +#define adeos_declare_cpuid int cpuid +#define adeos_load_cpuid() do { \ + (cpuid) = adeos_processor_id(); \ + } while(0) +#define adeos_lock_cpu(flags) do { \ + adeos_hw_local_irq_save(flags); \ + (cpuid) = adeos_processor_id(); \ + } while(0) +#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags) +#define adeos_get_cpu(flags) adeos_lock_cpu(flags) +#define adeos_put_cpu(flags) adeos_unlock_cpu(flags) +#define adp_current (adp_cpu_current[adeos_processor_id()]) + +void __adeos_send_IPI_mask(cpumask_t cpumask, + int vector); + +void __adeos_send_IPI_allbutself(int vector); + +unsigned long __adeos_set_irq_affinity (unsigned irq, + unsigned long cpumask); +#else /* !CONFIG_SMP */ + +#define ADEOS_NR_CPUS 1 +#define adeos_processor_id() 0 +/* Array references using this index should be optimized out. */ +#define adeos_declare_cpuid const int cpuid = 0 +#define adeos_load_cpuid() /* nop */ +#define adeos_lock_cpu(flags) adeos_hw_local_irq_save(flags) +#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags) +#define adeos_get_cpu(flags) do { flags = flags; } while(0) +#define adeos_put_cpu(flags) /* nop */ +#define adp_current (adp_cpu_current[0]) + +#endif /* CONFIG_SMP */ + + /* IDT fault vectors */ +#define ADEOS_NR_FAULTS 32 +/* Pseudo-vectors used for kernel events */ +#define ADEOS_FIRST_KEVENT ADEOS_NR_FAULTS +#define ADEOS_SYSCALL_PROLOGUE (ADEOS_FIRST_KEVENT) +#define ADEOS_SYSCALL_EPILOGUE (ADEOS_FIRST_KEVENT + 1) +#define ADEOS_SCHEDULE_HEAD (ADEOS_FIRST_KEVENT + 2) +#define ADEOS_SCHEDULE_TAIL (ADEOS_FIRST_KEVENT + 3) +#define ADEOS_ENTER_PROCESS (ADEOS_FIRST_KEVENT + 4) +#define ADEOS_EXIT_PROCESS (ADEOS_FIRST_KEVENT + 5) +#define ADEOS_SIGNAL_PROCESS (ADEOS_FIRST_KEVENT + 6) +#define ADEOS_KICK_PROCESS (ADEOS_FIRST_KEVENT + 7) +#define ADEOS_RENICE_PROCESS (ADEOS_FIRST_KEVENT + 8) +#define ADEOS_USER_EVENT (ADEOS_FIRST_KEVENT + 9) +#define ADEOS_LAST_KEVENT (ADEOS_USER_EVENT) + +#define ADEOS_NR_EVENTS (ADEOS_LAST_KEVENT + 1) + +typedef struct adevinfo { + + unsigned domid; + unsigned event; + void *evdata; + + volatile int propagate; /* Private */ + +} adevinfo_t; + +typedef struct adsysinfo { + + int ncpus; /* Number of CPUs on board */ + + unsigned long long cpufreq; /* CPU frequency (in Hz) */ + + /* Arch-dependent block */ + + struct { + unsigned tmirq; /* Timer tick IRQ */ + } archdep; + +} adsysinfo_t; + +#ifdef CONFIG_X86_LOCAL_APIC +/* We must cover the whole IRQ space (224 external vectors for x86) to + map the local timer interrupt (#207). */ +#define IPIPE_NR_XIRQS 224 +/* If the APIC is enabled, then we expose four service vectors in the + APIC space which are freely available to domains. */ +#define ADEOS_SERVICE_VECTOR0 0xf5 +#define ADEOS_SERVICE_IPI0 (ADEOS_SERVICE_VECTOR0 - FIRST_EXTERNAL_VECTOR) +#define ADEOS_SERVICE_VECTOR1 0xf6 +#define ADEOS_SERVICE_IPI1 (ADEOS_SERVICE_VECTOR1 - FIRST_EXTERNAL_VECTOR) +#define ADEOS_SERVICE_VECTOR2 0xf7 +#define ADEOS_SERVICE_IPI2 (ADEOS_SERVICE_VECTOR2 - FIRST_EXTERNAL_VECTOR) +#define ADEOS_SERVICE_VECTOR3 0xf8 +#define ADEOS_SERVICE_IPI3 (ADEOS_SERVICE_VECTOR3 - FIRST_EXTERNAL_VECTOR) +#else /* !CONFIG_X86_LOCAL_APIC */ +#define IPIPE_NR_XIRQS NR_IRQS +#endif /* CONFIG_X86_LOCAL_APIC */ +/* Number of virtual IRQs */ +#define IPIPE_NR_VIRQS BITS_PER_LONG +/* First virtual IRQ # */ +#define IPIPE_VIRQ_BASE (((IPIPE_NR_XIRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) * BITS_PER_LONG) +/* Total number of IRQ slots */ +#define IPIPE_NR_IRQS (IPIPE_VIRQ_BASE + IPIPE_NR_VIRQS) +/* Number of indirect words needed to map the whole IRQ space. */ +#define IPIPE_IRQ_IWORDS ((IPIPE_NR_IRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) +#define IPIPE_IRQ_IMASK (BITS_PER_LONG - 1) +#define IPIPE_IRQ_ISHIFT 5 /* 2^5 for 32bits arch. */ + +#define IPIPE_IRQMASK_ANY (~0L) +#define IPIPE_IRQMASK_VIRT (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG)) + +typedef struct adomain { + + /* -- Section: offset-based references are made on these fields + from inline assembly code. Please don't move or reorder. */ + void (*dswitch)(void); /* Domain switch hook */ + int *esp[ADEOS_NR_CPUS]; /* Domain stack pointers */ + /* -- End of section. */ + + int *estackbase[ADEOS_NR_CPUS]; + + unsigned long flags; + + unsigned domid; + + const char *name; + + int priority; + + struct adcpudata { + volatile unsigned long status; + volatile unsigned long irq_pending_hi; + volatile unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS]; + volatile unsigned irq_hits[IPIPE_NR_IRQS]; + adevinfo_t event_info; + } cpudata[ADEOS_NR_CPUS]; + + struct { + int (*acknowledge)(unsigned irq); + void (*handler)(unsigned irq); + unsigned long control; + } irqs[IPIPE_NR_IRQS]; + + struct { + void (*handler)(adevinfo_t *evinfo); + } events[ADEOS_NR_EVENTS]; + + int ptd_keymax; + int ptd_keycount; + unsigned long ptd_keymap; + void (*ptd_setfun)(int, void *); + void *(*ptd_getfun)(int); + + struct adomain *m_link; /* Link in mutex sleep queue */ + + struct list_head p_link; /* Link in pipeline */ + +} adomain_t; + +typedef struct admutex { + + spinlock_t lock; + + adomain_t *sleepq, /* Pending domains queue */ + *owner; /* Domain owning the mutex */ +#ifdef CONFIG_SMP + volatile int owncpu; +#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED, NULL, NULL, -1 } +#else /* !CONFIG_SMP */ +#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED, NULL, NULL } +#endif /* CONFIG_SMP */ + +} admutex_t; + +#define __clear_bit(nr,addr) clear_bit(nr,addr) +#define __test_bit(nr,addr) test_bit(nr,addr) + +/* The following macros must be used hw interrupts off. */ + +#define __adeos_set_irq_bit(adp,cpuid,irq) \ +do { \ + if (!test_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) { \ + __set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ + __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \ + } \ +} while(0) + +#define __adeos_clear_pend(adp,cpuid,irq) \ +do { \ + __clear_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ + if ((adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \ + __clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \ +} while(0) + +#define __adeos_lock_irq(adp,cpuid,irq) \ +do { \ + if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \ + __adeos_clear_pend(adp,cpuid,irq); \ +} while(0) + +#define __adeos_unlock_irq(adp,irq) \ +do { \ + int __cpuid, __nr_cpus = smp_num_cpus; \ + if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \ + for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) \ + if ((adp)->cpudata[__cpuid].irq_hits[irq] > 0) { \ + set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \ + set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[__cpuid].irq_pending_hi); \ + } \ +} while(0) + +#define __adeos_clear_irq(adp,irq) \ +do { \ + int __cpuid, __nr_cpus = smp_num_cpus; \ + clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control); \ + for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) { \ + (adp)->cpudata[__cpuid].irq_hits[irq] = 0; \ + __adeos_clear_pend(adp,__cpuid,irq); \ + } \ +} while(0) + +#define adeos_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \ + (irq) < IPIPE_NR_IRQS) + +#define adeos_hw_save_flags_and_sti(x) __asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory") +#define adeos_hw_cli() __asm__ __volatile__("cli": : :"memory") +#define adeos_hw_sti() __asm__ __volatile__("sti": : :"memory") +#define adeos_hw_local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") +#define adeos_hw_local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") +#define adeos_hw_local_irq_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) +#define adeos_hw_test_iflag(x) ((x) & (1<<9)) +#define adeos_hw_irqs_disabled() \ +({ \ + unsigned long flags; \ + adeos_hw_local_irq_flags(flags); \ + !adeos_hw_test_iflag(flags); \ +}) + +#define adeos_hw_tsc(t) __asm__ __volatile__("rdtsc" : "=A" (t)) +#define adeos_cpu_freq() ({ unsigned long long __freq = cpu_has_tsc?(1000LL * cpu_khz):CLOCK_TICK_RATE; __freq; }) + +#ifdef CONFIG_PREEMPT +#define adeos_spin_lock(x) _raw_spin_lock(x) +#define adeos_spin_unlock(x) _raw_spin_unlock(x) +#define adeos_spin_trylock(x) _raw_spin_trylock(x) +/* Ok, the following is stupid, but I want to keep all direct use of + preempt_count's offset here. */ +#define __adeos_bump_count "movl %%esp, %%ebx\n\t" \ + "andl $-8192, %%ebx\n\t" \ + "incl 4(%%ebx)\n\t" +#define __adeos_bump_count_noarg "movl %esp, %ebx\n\t" \ + "andl $-8192, %ebx\n\t" \ + "incl 4(%ebx)\n\t" +#else /* !CONFIG_PREEMPT */ +#define adeos_spin_lock(x) spin_lock(x) +#define adeos_spin_unlock(x) spin_unlock(x) +#define adeos_spin_trylock(x) spin_trylock(x) +#define __adeos_bump_count +#define __adeos_bump_count_noarg +#endif /* CONFIG_PREEMPT */ + +#define adeos_spin_lock_irqsave(x,flags) do { adeos_hw_local_irq_save(flags); adeos_spin_lock(x); } while (0) +#define adeos_spin_unlock_irqrestore(x,flags) do { adeos_spin_unlock(x); adeos_hw_local_irq_restore(flags); } while (0) +#define adeos_spin_lock_disable(x) do { adeos_hw_cli(); adeos_spin_lock(x); } while (0) +#define adeos_spin_unlock_enable(x) do { adeos_spin_unlock(x); adeos_hw_sti(); } while (0) + +/* Private interface -- Internal use only */ + +struct adattr; + +void __adeos_init(void); + +void __adeos_init_domain(adomain_t *adp, + struct adattr *attr); + +void __adeos_cleanup_domain(adomain_t *adp); + +#ifdef CONFIG_SMP + +/* + * __adeos_switch_to() -- Switch domain contexts. The current domain + * ("out") is switched out while the domain pointed by "in" is + * switched in. The current cpu identifier which is always known from + * callers is also passed to save a few cycles. This code works out + * the following tasks: - build a resume frame for the suspended + * domain, - save it's stack pointer, - load the incoming domain's + * stack pointer, - update the global domain descriptor pointer, - + * then finally activate the resume frame of the incoming domain. + * + * SMP version also provides for safe CPU migration (i.e. the domain + * may be switched back in on behalf of a different CPU than the one + * which switched it out). + * + * NOTE: dswitch() takes no argument, so there is no specific handling + * of CONFIG_REGPARM needed. This routine must be called with hw + * interrupts off. + */ + +static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid) + +{ + __asm__ __volatile__( \ + "pushl %%ebp\n\t" \ + "pushl %%ecx\n\t" \ + "pushl %%ebx\n\t" \ + "pushl %%edi\n\t" \ + "pushl %%esi\n\t" \ + "movl %%eax, %%ecx\n\t" \ + "leal adp_cpu_current(,%%eax,4),%%eax\n\t" \ + "xchg (%%eax), %%edx\n\t" \ + "pushl %%edx\n\t" \ + "pushl $1f\n\t" \ + "sall $2,%%ecx\n\t" \ + "addl $4,%%ecx\n\t" \ + "movl %%esp, (%%ecx,%%edx)\n\t" \ + "movl (%%eax), %%eax\n\t" \ + "movl (%%ecx,%%eax), %%esp\n\t" \ + "ret\n\t" \ + /* Call domain switch hook (if any) */ +"1: popl %%eax\n\t" \ + "movl (%%eax), %%eax\n\t" \ + "testl %%eax,%%eax\n\t" \ + "je 2f\n\t" \ + "call *%%eax\n\t" \ + /* Domain resume point */ +"2: popl %%esi\n\t" \ + "popl %%edi\n\t" \ + "popl %%ebx\n\t" \ + "popl %%ecx\n\t" \ + "popl %%ebp\n\t" \ + : /* no output */ \ + : "a" (cpuid), "d" (in) \ + : "memory", "cc"); + + barrier(); +} + +#else /* !CONFIG_SMP */ + +static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid) + +{ + __asm__ __volatile__( \ + "pushl %%ebp\n\t" \ + "pushl %%edx\n\t" \ + "pushl %%ecx\n\t" \ + "pushl %%ebx\n\t" \ + "pushl %%edi\n\t" \ + "pushl %%esi\n\t" \ + "movl "SYMBOL_NAME_STR(adp_cpu_current)", %%edx\n\t" \ + "pushl %%edx\n\t" \ + "pushl $1f\n\t" \ + "movl %%esp, 4(%%edx)\n\t" \ + "movl 4(%%eax), %%esp\n\t" \ + "movl %%eax, "SYMBOL_NAME_STR(adp_cpu_current)"\n\t" \ + "ret\n\t" \ + /* Call domain switch hook (if any) */ +"1: popl %%eax\n\t" \ + "movl (%%eax),%%eax\n\t" \ + "testl %%eax,%%eax\n\t" \ + "je 2f\n\t" \ + "call *%%eax\n\t" \ + /* Domain resume point */ +"2: popl %%esi\n\t" \ + "popl %%edi\n\t" \ + "popl %%ebx\n\t" \ + "popl %%ecx\n\t" \ + "popl %%edx\n\t" \ + "popl %%ebp\n\t" \ + : /* no output */ \ + : "a" (in)); +} + +#endif /* CONFIG_SMP */ + +void __adeos_check_machine(void); + +void __adeos_enable_pipeline(void); + +void __adeos_disable_pipeline(void); + +void __adeos_init_stage(adomain_t *adp); + +void FASTCALL(__adeos_sync_stage(unsigned long syncmask)); + +int __adeos_ack_system_irq(unsigned irq); + +int __adeos_handle_irq(struct pt_regs regs); + +extern struct pt_regs __adeos_tick_regs; + +extern int __adeos_tick_irq; + +#ifdef CONFIG_X86_LOCAL_APIC +extern int __adeos_apic_mapped; +#endif /* CONFIG_X86_LOCAL_APIC */ + +#include + +#endif /* !__I386_ADEOS_H */ diff -uNrp linux-2.4.31/include/asm-i386/hw_irq.h linux-2.4.31-r18/include/asm-i386/hw_irq.h --- linux-2.4.31/include/asm-i386/hw_irq.h 2003-08-25 13:44:43.000000000 +0200 +++ linux-2.4.31-r18/include/asm-i386/hw_irq.h 2005-06-20 23:57:28.000000000 +0200 @@ -56,7 +56,12 @@ * levels. (0x80 is the syscall vector) */ #define FIRST_DEVICE_VECTOR 0x31 +#ifdef CONFIG_ADEOS_CORE +/* Reserve 16 more vectors for domains. */ +#define FIRST_SYSTEM_VECTOR 0xdf +#else /* !CONFIG_ADEOS_CORE */ #define FIRST_SYSTEM_VECTOR 0xef +#endif /* CONFIG_ADEOS_CORE */ extern int irq_vector[NR_IRQS]; #define IO_APIC_VECTOR(irq) irq_vector[irq] diff -uNrp linux-2.4.31/include/asm-i386/pgalloc.h linux-2.4.31-r18/include/asm-i386/pgalloc.h --- linux-2.4.31/include/asm-i386/pgalloc.h 2003-08-25 13:44:43.000000000 +0200 +++ linux-2.4.31-r18/include/asm-i386/pgalloc.h 2005-06-20 23:57:09.000000000 +0200 @@ -139,6 +139,42 @@ static __inline__ void pte_free_slow(pte free_page((unsigned long)pte); } +#ifdef CONFIG_ADEOS_CORE + +/* Non-root Adeos domains cannot might not cope with on-demand + mappings for I/O or vmalloc'ed memory, so fall back to a brute + force instantaneous kernel global mapping of these areas. */ + +static inline void set_pgdir(unsigned long address, pgd_t entry) { + + struct task_struct *p; + pgd_t *pgd; + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); +#ifdef CONFIG_SMP + { + int cpu; + /* To pgd_alloc/pgd_free, one holds the page table lock and so + does our callee, so we can modify pgd caches of other CPUs + as well. -jj +rpm*/ + for (cpu = 0; cpu < NR_CPUS; cpu++) + for (pgd = (pgd_t *)cpu_data[cpu].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; + } +#else /* !CONFIG_SMP */ + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#endif /* CONFIG_SMP */ +} + +#endif /* CONFIG_ADEOS_CORE */ + #define pte_free(pte) pte_free_fast(pte) #define pgd_free(pgd) free_pgd_slow(pgd) #define pgd_alloc(mm) get_pgd_fast() diff -uNrp linux-2.4.31/include/asm-i386/smp.h linux-2.4.31-r18/include/asm-i386/smp.h --- linux-2.4.31/include/asm-i386/smp.h 2004-11-17 12:54:22.000000000 +0100 +++ linux-2.4.31-r18/include/asm-i386/smp.h 2005-06-20 23:57:18.000000000 +0200 @@ -81,7 +81,11 @@ extern void smp_store_cpu_info(int id); * so this is correct in the x86 case. */ +#ifdef CONFIG_ADEOS_CORE +#define smp_processor_id() adeos_processor_id() +#else /* !CONFIG_ADEOS_CORE */ #define smp_processor_id() (current->processor) +#endif /* CONFIG_ADEOS_CORE */ static __inline int hard_smp_processor_id(void) { diff -uNrp linux-2.4.31/include/asm-i386/system.h linux-2.4.31-r18/include/asm-i386/system.h --- linux-2.4.31/include/asm-i386/system.h 2004-04-14 15:05:40.000000000 +0200 +++ linux-2.4.31-r18/include/asm-i386/system.h 2005-06-20 23:57:36.000000000 +0200 @@ -12,6 +12,34 @@ 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)); +#ifdef CONFIG_ADEOS_CORE +#define prepare_to_switch(prev,next) \ +do { \ + struct { struct task_struct *prev, *next; } arg = { (prev), (next) }; \ + __adeos_schedule_head(&arg); \ + adeos_hw_cli(); \ +} while(0) +#define switch_to(prev,next,last) do { \ + asm volatile("pushl %%esi\n\t" \ + "pushl %%edi\n\t" \ + "pushl %%ebp\n\t" \ + "movl %%esp,%0\n\t" /* save ESP */ \ + "movl %3,%%esp\n\t" /* restore ESP */ \ + "movl $1f,%1\n\t" /* save EIP */ \ + "pushl %4\n\t" /* restore EIP */ \ + "jmp __switch_to\n" \ + "1:\t" \ + "popl %%ebp\n\t" \ + "popl %%edi\n\t" \ + "popl %%esi\n\t" \ + "sti\n\t" \ + :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \ + "=b" (last) \ + :"m" (next->thread.esp),"m" (next->thread.eip), \ + "a" (prev), "d" (next), \ + "b" (prev)); \ +} while (0) +#else /* !CONFIG_ADEOS_CORE */ #define prepare_to_switch() do { } while(0) #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ @@ -32,6 +60,7 @@ extern void FASTCALL(__switch_to(struct "a" (prev), "d" (next), \ "b" (prev)); \ } while (0) +#endif /* CONFIG_ADEOS_CORE */ #define _set_base(addr,base) do { unsigned long __pr; \ __asm__ __volatile__ ("movw %%dx,%1\n\t" \ @@ -313,6 +342,40 @@ static inline unsigned long __cmpxchg(vo #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ + +#ifdef CONFIG_ADEOS_CORE + +void __adeos_stall_root(void); + +void __adeos_unstall_root(void); + +unsigned long __adeos_test_root(void); + +unsigned long __adeos_test_and_stall_root(void); + +void FASTCALL(__adeos_restore_root(unsigned long flags)); + +#define __save_flags(x) ((x) = __adeos_test_root()) +#define __restore_flags(x) __adeos_restore_root(x) +#define __cli() __adeos_stall_root() +#define __sti() __adeos_unstall_root() +/* used in the idle loop; sti takes one instruction cycle to complete */ +#define safe_halt() __asm__ __volatile__("call "__stringify(__adeos_unstall_root)"; hlt": : :"memory") + +#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0); +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + +/* For spinlocks etc */ +#define local_irq_save(x) ((x) = __adeos_test_and_stall_root()) +#define local_irq_set(x) __save_and_sti(x) +#define local_irq_restore(x) __adeos_restore_root(x) +#define local_irq_disable() __adeos_stall_root() +#define local_irq_enable() __adeos_unstall_root() + +#define irqs_disabled() __adeos_test_root() + +#else /* !CONFIG_ADEOS_CORE */ + #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") @@ -336,6 +399,8 @@ static inline unsigned long __cmpxchg(vo #define local_irq_disable() __cli() #define local_irq_enable() __sti() +#endif /* CONFIG_ADEOS_CORE */ + #ifdef CONFIG_SMP extern void __global_cli(void); diff -uNrp linux-2.4.31/include/linux/adeos.h linux-2.4.31-r18/include/linux/adeos.h --- linux-2.4.31/include/linux/adeos.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/include/linux/adeos.h 2005-06-02 23:17:45.000000000 +0200 @@ -0,0 +1,431 @@ +/* + * include/linux/adeos.h + * + * Copyright (C) 2002,2003,2004 Philippe Gerum. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LINUX_ADEOS_H +#define __LINUX_ADEOS_H + +#include +#include + +#define ADEOS_VERSION_PREFIX "2.4" +#define ADEOS_VERSION_STRING (ADEOS_VERSION_PREFIX ADEOS_ARCH_STRING) +#define ADEOS_RELEASE_NUMBER (0x02040000|((ADEOS_MAJOR_NUMBER&0xff)<<8)|(ADEOS_MINOR_NUMBER&0xff)) + +#define ADEOS_ROOT_PRI 100 +#define ADEOS_ROOT_ID 0 +#define ADEOS_ROOT_NPTDKEYS 4 /* Must be <= 32 */ + +#define ADEOS_OTHER_CPUS 0 +#define ADEOS_RESET_TIMER 0x1 +#define ADEOS_SAME_HANDLER ((void (*)(unsigned))(-1)) + +/* Global domain flags */ +#define ADEOS_SPRINTK_FLAG 0 /* Synchronous printk() allowed */ +#define ADEOS_PPRINTK_FLAG 1 /* Asynchronous printk() request pending */ + +/* Per-cpu pipeline flags */ +#define IPIPE_STALL_FLAG 0 /* Stalls a pipeline stage */ +#define IPIPE_XPEND_FLAG 1 /* Exception notification is pending */ +#define IPIPE_SLEEP_FLAG 2 /* Domain has self-suspended */ + +#define IPIPE_HANDLE_FLAG 0 +#define IPIPE_PASS_FLAG 1 +#define IPIPE_ENABLE_FLAG 2 +#define IPIPE_DYNAMIC_FLAG IPIPE_HANDLE_FLAG +#define IPIPE_EXCLUSIVE_FLAG 3 +#define IPIPE_STICKY_FLAG 4 +#define IPIPE_SYSTEM_FLAG 5 +#define IPIPE_LOCK_FLAG 6 +#define IPIPE_SHARED_FLAG 7 +#define IPIPE_CALLASM_FLAG 8 /* Arch-specific -- might be unused. */ + +#define IPIPE_HANDLE_MASK (1 << IPIPE_HANDLE_FLAG) +#define IPIPE_PASS_MASK (1 << IPIPE_PASS_FLAG) +#define IPIPE_ENABLE_MASK (1 << IPIPE_ENABLE_FLAG) +#define IPIPE_DYNAMIC_MASK IPIPE_HANDLE_MASK +#define IPIPE_EXCLUSIVE_MASK (1 << IPIPE_EXCLUSIVE_FLAG) +#define IPIPE_STICKY_MASK (1 << IPIPE_STICKY_FLAG) +#define IPIPE_SYSTEM_MASK (1 << IPIPE_SYSTEM_FLAG) +#define IPIPE_LOCK_MASK (1 << IPIPE_LOCK_FLAG) +#define IPIPE_SHARED_MASK (1 << IPIPE_SHARED_FLAG) +#define IPIPE_CALLASM_MASK (1 << IPIPE_CALLASM_FLAG) + +#define IPIPE_DEFAULT_MASK (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK) + +typedef struct adattr { + + unsigned domid; /* Domain identifier -- Magic value set by caller */ + const char *name; /* Domain name -- Warning: won't be dup'ed! */ + int priority; /* Priority in interrupt pipeline */ + void (*entry)(int); /* Domain entry point */ + int estacksz; /* Stack size for entry context -- 0 means unspec */ + void (*dswitch)(void); /* Handler called each time the domain is switched in */ + int nptdkeys; /* Max. number of per-thread data keys */ + void (*ptdset)(int,void *); /* Routine to set pt values */ + void *(*ptdget)(int); /* Routine to get pt values */ + +} adattr_t; + +extern adomain_t *adp_cpu_current[], + *adp_root; + +extern int __adeos_event_monitors[]; + +extern unsigned __adeos_printk_virq; + +extern unsigned long __adeos_virtual_irq_map; + +extern struct list_head __adeos_pipeline; + +extern spinlock_t __adeos_pipelock; + +#ifdef CONFIG_ADEOS_PROFILING + +typedef struct adprofdata { + + struct { + unsigned long long t_handled; + unsigned long long t_synced; + unsigned long n_handled; + unsigned long n_synced; + } irqs[IPIPE_NR_IRQS]; + +} adprofdata_t; + +extern adprofdata_t __adeos_profile_data[ADEOS_NR_CPUS]; + +#endif /* CONFIG_ADEOS_PROFILING */ + +/* Private interface */ + +#ifdef CONFIG_PROC_FS +void __adeos_init_proc(void); +#endif /* CONFIG_PROC_FS */ + +void __adeos_takeover(void); + +asmlinkage int __adeos_handle_event(unsigned event, + void *evdata); + +void __adeos_sync_console(unsigned irq); + +void __adeos_dump_state(void); + +static inline void __adeos_schedule_head(void *evdata) { + + if (unlikely(__adeos_event_monitors[ADEOS_SCHEDULE_HEAD] > 0)) + __adeos_handle_event(ADEOS_SCHEDULE_HEAD,evdata); +} + +static inline int __adeos_schedule_tail(void *evdata) { + + if (unlikely(__adeos_event_monitors[ADEOS_SCHEDULE_TAIL] > 0)) + return __adeos_handle_event(ADEOS_SCHEDULE_TAIL,evdata); + + return 0; +} + +static inline void __adeos_enter_process(void) { + + if (unlikely(__adeos_event_monitors[ADEOS_ENTER_PROCESS] > 0)) + __adeos_handle_event(ADEOS_ENTER_PROCESS,NULL); +} + +static inline void __adeos_exit_process(void *evdata) { + + if (unlikely(__adeos_event_monitors[ADEOS_EXIT_PROCESS] > 0)) + __adeos_handle_event(ADEOS_EXIT_PROCESS,evdata); +} + +static inline int __adeos_signal_process(void *evdata) { + + if (unlikely(__adeos_event_monitors[ADEOS_SIGNAL_PROCESS] > 0)) + return __adeos_handle_event(ADEOS_SIGNAL_PROCESS,evdata); + + return 0; +} + +static inline void __adeos_kick_process(void *evdata) { + + if (unlikely(__adeos_event_monitors[ADEOS_KICK_PROCESS] > 0)) + __adeos_handle_event(ADEOS_KICK_PROCESS,evdata); +} + +static inline int __adeos_renice_process(void *evdata) { + + if (unlikely(__adeos_event_monitors[ADEOS_RENICE_PROCESS] > 0)) + return __adeos_handle_event(ADEOS_RENICE_PROCESS,evdata); + + return 0; +} + +void __adeos_stall_root(void); + +void __adeos_unstall_root(void); + +unsigned long __adeos_test_root(void); + +unsigned long __adeos_test_and_stall_root(void); + +void FASTCALL(__adeos_restore_root(unsigned long flags)); + +void __adeos_schedule_back_root(struct task_struct *prev); + +#define __adeos_pipeline_head_p(adp) (&(adp)->p_link == __adeos_pipeline.next) + +static inline int __adeos_domain_work_p (adomain_t *adp, int cpuid) + +{ + return (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[cpuid].status) || + (!test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status) && + adp->cpudata[cpuid].irq_pending_hi != 0) || + test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[cpuid].status)); +} + +/* Public interface */ + +int adeos_register_domain(adomain_t *adp, + adattr_t *attr); + +int adeos_unregister_domain(adomain_t *adp); + +void adeos_suspend_domain(void); + +int adeos_virtualize_irq_from(adomain_t *adp, + unsigned irq, + void (*handler)(unsigned irq), + int (*acknowledge)(unsigned irq), + unsigned modemask); + +static inline int adeos_virtualize_irq(unsigned irq, + void (*handler)(unsigned irq), + int (*acknowledge)(unsigned irq), + unsigned modemask) { + + return adeos_virtualize_irq_from(adp_current, + irq, + handler, + acknowledge, + modemask); +} + +int adeos_control_irq(unsigned irq, + unsigned clrmask, + unsigned setmask); + +unsigned long adeos_set_irq_affinity(unsigned irq, + unsigned long cpumask); + +static inline int adeos_share_irq (unsigned irq, int (*acknowledge)(unsigned irq)) { + + return adeos_virtualize_irq(irq, + ADEOS_SAME_HANDLER, + acknowledge, + IPIPE_SHARED_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK); +} + +unsigned adeos_alloc_irq(void); + +int adeos_free_irq(unsigned irq); + +int FASTCALL(adeos_trigger_irq(unsigned irq)); + +int FASTCALL(adeos_propagate_irq(unsigned irq)); + +int FASTCALL(adeos_schedule_irq(unsigned irq)); + +int FASTCALL(adeos_send_ipi(unsigned ipi, + cpumask_t cpumask)); + +static inline void adeos_stall_pipeline_from (adomain_t *adp) + +{ + adeos_declare_cpuid; +#ifdef CONFIG_SMP + unsigned long flags; + + adeos_lock_cpu(flags); + + __set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (!__adeos_pipeline_head_p(adp)) + adeos_unlock_cpu(flags); +#else /* CONFIG_SMP */ + set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (__adeos_pipeline_head_p(adp)) + adeos_hw_cli(); +#endif /* CONFIG_SMP */ +} + +static inline unsigned long adeos_test_pipeline_from (adomain_t *adp) + +{ + unsigned long flags, s; + adeos_declare_cpuid; + + adeos_get_cpu(flags); + s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + adeos_put_cpu(flags); + + return s; +} + +static inline unsigned long adeos_test_and_stall_pipeline_from (adomain_t *adp) + +{ + adeos_declare_cpuid; + unsigned long s; +#ifdef CONFIG_SMP + unsigned long flags; + + adeos_lock_cpu(flags); + + s = __test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (!__adeos_pipeline_head_p(adp)) + adeos_unlock_cpu(flags); +#else /* CONFIG_SMP */ + s = test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + if (__adeos_pipeline_head_p(adp)) + adeos_hw_cli(); +#endif /* CONFIG_SMP */ + + return s; +} + +void FASTCALL(adeos_unstall_pipeline_from(adomain_t *adp)); + +static inline unsigned long adeos_test_and_unstall_pipeline_from(adomain_t *adp) + +{ + unsigned long flags, s; + adeos_declare_cpuid; + + adeos_get_cpu(flags); + s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + adeos_unstall_pipeline_from(adp); + adeos_put_cpu(flags); + + return s; +} + +static inline void adeos_unstall_pipeline(void) { + + adeos_unstall_pipeline_from(adp_current); +} + +static inline unsigned long adeos_test_and_unstall_pipeline(void) { + + return adeos_test_and_unstall_pipeline_from(adp_current); +} + +static inline unsigned long adeos_test_pipeline (void) { + + return adeos_test_pipeline_from(adp_current); +} + +static inline unsigned long adeos_test_and_stall_pipeline (void) { + + return adeos_test_and_stall_pipeline_from(adp_current); +} + +static inline void adeos_restore_pipeline_from (adomain_t *adp, unsigned long flags) { + + if (flags) + adeos_stall_pipeline_from(adp); + else + adeos_unstall_pipeline_from(adp); +} + +static inline void adeos_stall_pipeline (void) { + + adeos_stall_pipeline_from(adp_current); +} + +static inline void adeos_restore_pipeline (unsigned long flags) { + + adeos_restore_pipeline_from(adp_current,flags); +} + +static inline void adeos_restore_pipeline_nosync (adomain_t *adp, unsigned long flags, int cpuid) { + + /* If cpuid is current, then it must be held on entry + (adeos_get_cpu/adeos_hw_local_irq_save/adeos_hw_cli). */ + + if (flags) + __set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + else + __clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); +} + +int adeos_catch_event_from(adomain_t *adp, + unsigned event, + void (*handler)(adevinfo_t *)); + +static inline int adeos_catch_event (unsigned event, void (*handler)(adevinfo_t *)) { + return adeos_catch_event_from(adp_current,event,handler); +} + +static inline void adeos_propagate_event(adevinfo_t *evinfo) { + + evinfo->propagate = 1; +} + +void adeos_init_attr(adattr_t *attr); + +int adeos_get_sysinfo(adsysinfo_t *sysinfo); + +int adeos_tune_timer(unsigned long ns, + int flags); + +int adeos_alloc_ptdkey(void); + +int adeos_free_ptdkey(int key); + +int adeos_set_ptd(int key, + void *value); + +void *adeos_get_ptd(int key); + +unsigned long adeos_critical_enter(void (*syncfn)(void)); + +void adeos_critical_exit(unsigned long flags); + +int adeos_init_mutex(admutex_t *mutex); + +int adeos_destroy_mutex(admutex_t *mutex); + +unsigned long FASTCALL(adeos_lock_mutex(admutex_t *mutex)); + +void FASTCALL(adeos_unlock_mutex(admutex_t *mutex, + unsigned long flags)); + +static inline void adeos_set_printk_sync (adomain_t *adp) { + set_bit(ADEOS_SPRINTK_FLAG,&adp->flags); +} + +static inline void adeos_set_printk_async (adomain_t *adp) { + clear_bit(ADEOS_SPRINTK_FLAG,&adp->flags); +} + +#endif /* !__LINUX_ADEOS_H */ diff -uNrp linux-2.4.31/include/linux/sched.h linux-2.4.31-r18/include/linux/sched.h --- linux-2.4.31/include/linux/sched.h 2005-01-19 15:10:12.000000000 +0100 +++ linux-2.4.31-r18/include/linux/sched.h 2005-06-20 23:56:59.000000000 +0200 @@ -125,6 +125,10 @@ struct completion; #include +#ifdef CONFIG_ADEOS_CORE +#include +#endif /* CONFIG_ADEOS_CORE */ + /* * This serializes "schedule()" and also protects * the run-queue from deletions/modifications (but @@ -415,6 +419,10 @@ struct task_struct { /* journalling filesystem info */ void *journal_info; + +#ifdef CONFIG_ADEOS_CORE + void *ptd[ADEOS_ROOT_NPTDKEYS]; +#endif /* CONFIG_ADEOS_CORE */ }; /* @@ -469,6 +477,51 @@ extern struct exec_domain default_exec_d * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ +#ifdef CONFIG_ADEOS_CORE +#define INIT_TASK(tsk) \ +{ \ + state: 0, \ + flags: 0, \ + sigpending: 0, \ + addr_limit: KERNEL_DS, \ + exec_domain: &default_exec_domain, \ + lock_depth: -1, \ + counter: DEF_COUNTER, \ + nice: DEF_NICE, \ + policy: SCHED_OTHER, \ + mm: NULL, \ + active_mm: &init_mm, \ + cpus_runnable: ~0UL, \ + cpus_allowed: ~0UL, \ + run_list: LIST_HEAD_INIT(tsk.run_list), \ + next_task: &tsk, \ + prev_task: &tsk, \ + p_opptr: &tsk, \ + p_pptr: &tsk, \ + thread_group: LIST_HEAD_INIT(tsk.thread_group), \ + wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ + real_timer: { \ + function: it_real_fn \ + }, \ + cap_effective: CAP_INIT_EFF_SET, \ + cap_inheritable: CAP_INIT_INH_SET, \ + cap_permitted: CAP_FULL_SET, \ + keep_capabilities: 0, \ + rlim: INIT_RLIMITS, \ + user: INIT_USER, \ + comm: "swapper", \ + thread: INIT_THREAD, \ + fs: &init_fs, \ + files: &init_files, \ + sigmask_lock: SPIN_LOCK_UNLOCKED, \ + sig: &init_signals, \ + pending: { NULL, &tsk.pending.head, {{0}}}, \ + blocked: {{0}}, \ + alloc_lock: SPIN_LOCK_UNLOCKED, \ + journal_info: NULL, \ + ptd: { [ 0 ... ADEOS_ROOT_NPTDKEYS - 1] = 0 }, \ +} +#else /* !CONFIG_ADEOS_CORE */ #define INIT_TASK(tsk) \ { \ state: 0, \ @@ -511,6 +564,7 @@ extern struct exec_domain default_exec_d alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ } +#endif /* CONFIG_ADEOS_CORE */ #ifndef INIT_TASK_SIZE diff -uNrp linux-2.4.31/init/main.c linux-2.4.31-r18/init/main.c --- linux-2.4.31/init/main.c 2004-11-17 12:54:22.000000000 +0100 +++ linux-2.4.31-r18/init/main.c 2005-06-20 23:54:09.000000000 +0200 @@ -370,6 +370,9 @@ asmlinkage void __init start_kernel(void parse_options(command_line); trap_init(); init_IRQ(); +#ifdef CONFIG_ADEOS_CORE + __adeos_init(); +#endif /* CONFIG_ADEOS_CORE */ sched_init(); softirq_init(); time_init(); @@ -535,6 +538,9 @@ static void __init do_basic_setup(void) #ifdef CONFIG_TC tc_init(); #endif +#ifdef CONFIG_ADEOS + __adeos_takeover(); +#endif /* CONFIG_ADEOS */ /* Networking initialization needs a process context */ sock_init(); diff -uNrp linux-2.4.31/kernel/adeos.c linux-2.4.31-r18/kernel/adeos.c --- linux-2.4.31/kernel/adeos.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.31-r18/kernel/adeos.c 2005-06-02 23:16:40.000000000 +0200 @@ -0,0 +1,646 @@ +/* + * linux/kernel/adeos.c + * + * Copyright (C) 2002,2003,2004 Philippe Gerum. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Architecture-independent ADEOS core support. + */ + +#include +#ifdef CONFIG_PROC_FS +#include +#endif /* CONFIG_PROC_FS */ +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ + +/* The pre-defined domain slot for the root domain. */ +static adomain_t adeos_root_domain; + +/* A constant pointer to the root domain. */ +adomain_t *adp_root = &adeos_root_domain; + +/* A pointer to the current domain. */ +adomain_t *adp_cpu_current[ADEOS_NR_CPUS] = { [ 0 ... ADEOS_NR_CPUS - 1] = &adeos_root_domain }; + +/* The spinlock protecting from races while modifying the pipeline. */ +spinlock_t __adeos_pipelock = SPIN_LOCK_UNLOCKED; + +/* The pipeline data structure. Enqueues adomain_t objects by priority. */ +struct list_head __adeos_pipeline; + +/* An array of global counters tracking domains monitoring events. */ +int __adeos_event_monitors[ADEOS_NR_EVENTS] = { [ 0 ... ADEOS_NR_EVENTS - 1] = 0 }; + +/* The allocated VIRQ map. */ +unsigned long __adeos_virtual_irq_map = 0; + +/* A VIRQ to kick printk() output out when the root domain is in control. */ +unsigned __adeos_printk_virq; + +#ifdef CONFIG_ADEOS_PROFILING +adprofdata_t __adeos_profile_data[ADEOS_NR_CPUS]; +#endif /* CONFIG_ADEOS_PROFILING */ + +static void __adeos_set_root_ptd (int key, void *value) { + + current->ptd[key] = value; +} + +static void *__adeos_get_root_ptd (int key) { + + return current->ptd[key]; +} + +/* adeos_init() -- Initialization routine of the ADEOS layer. Called + by the host kernel early during the boot procedure. */ + +void __adeos_init (void) + +{ + adomain_t *adp = &adeos_root_domain; + + __adeos_check_machine(); /* Do platform dependent checks first. */ + + /* + A lightweight registration code for the root domain. Current + assumptions are: + - We are running on the boot CPU, and secondary CPUs are still + lost in space. + - adeos_root_domain has been zero'ed. + */ + + INIT_LIST_HEAD(&__adeos_pipeline); + + adp->name = "Linux"; + adp->domid = ADEOS_ROOT_ID; + adp->priority = ADEOS_ROOT_PRI; + adp->ptd_setfun = &__adeos_set_root_ptd; + adp->ptd_getfun = &__adeos_get_root_ptd; + adp->ptd_keymax = ADEOS_ROOT_NPTDKEYS; + + __adeos_init_stage(adp); + + INIT_LIST_HEAD(&adp->p_link); + list_add_tail(&adp->p_link,&__adeos_pipeline); + + __adeos_printk_virq = adeos_alloc_irq(); /* Cannot fail here. */ + adp->irqs[__adeos_printk_virq].handler = &__adeos_sync_console; + adp->irqs[__adeos_printk_virq].acknowledge = NULL; + adp->irqs[__adeos_printk_virq].control = IPIPE_HANDLE_MASK; + + printk(KERN_WARNING "Adeos %s: Root domain %s registered.\n", + ADEOS_VERSION_STRING, + adp->name); +} + +/* adeos_handle_event() -- Adeos' generic event handler. This routine + calls the per-domain handlers registered for a given + exception/event. Each domain before the one which raised the event + in the pipeline will get a chance to process the event. The latter + will eventually be allowed to process its own event too if a valid + handler exists for it. Handler executions are always scheduled by + the domain which raised the event for the prioritary domains + wanting to be notified of such event. Note: evdata might be + NULL. */ + +asmlinkage int __adeos_handle_event (unsigned event, void *evdata) +/* asmlinkage is there just in case -mregparm is used... */ +{ + struct list_head *pos, *npos; + adomain_t *this_domain; + unsigned long flags; + adeos_declare_cpuid; + adevinfo_t evinfo; + int propagate = 1; + + adeos_lock_cpu(flags); + + this_domain = adp_cpu_current[cpuid]; + + list_for_each_safe(pos,npos,&__adeos_pipeline) { + + adomain_t *next_domain = list_entry(pos,adomain_t,p_link); + + if (next_domain->events[event].handler != NULL) + { + if (next_domain == this_domain) + { + adeos_unlock_cpu(flags); + evinfo.domid = this_domain->domid; + evinfo.event = event; + evinfo.evdata = evdata; + evinfo.propagate = 0; + this_domain->events[event].handler(&evinfo); + propagate = evinfo.propagate; + goto done; + } + + next_domain->cpudata[cpuid].event_info.domid = this_domain->domid; + next_domain->cpudata[cpuid].event_info.event = event; + next_domain->cpudata[cpuid].event_info.evdata = evdata; + next_domain->cpudata[cpuid].event_info.propagate = 0; + __set_bit(IPIPE_XPEND_FLAG,&next_domain->cpudata[cpuid].status); + + /* Let the prioritary domain process the event. */ + __adeos_switch_to(this_domain,next_domain,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!next_domain->cpudata[cpuid].event_info.propagate) + { + propagate = 0; + break; + } + } + + if (next_domain == this_domain) + break; + } + + adeos_unlock_cpu(flags); + + done: + + return !propagate; +} + +void __adeos_stall_root (void) + +{ + if (adp_pipelined) + { + adeos_declare_cpuid; + +#ifdef CONFIG_SMP + unsigned long flags; + adeos_lock_cpu(flags); + __set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + adeos_unlock_cpu(flags); +#else /* !CONFIG_SMP */ + set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); +#endif /* CONFIG_SMP */ + } + else + adeos_hw_cli(); +} + +void __adeos_unstall_root (void) + +{ + if (adp_pipelined) + { + adeos_declare_cpuid; + + adeos_hw_cli(); + + adeos_load_cpuid(); + + __clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + + if (adp_root->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + adeos_hw_sti(); /* Needed in both cases. */ +} + +unsigned long __adeos_test_root (void) + +{ + if (adp_pipelined) + { + unsigned long flags, s; + adeos_declare_cpuid; + + adeos_get_cpu(flags); + s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + adeos_put_cpu(flags); + + return s; + } + + return adeos_hw_irqs_disabled(); +} + +unsigned long __adeos_test_and_stall_root (void) + +{ + unsigned long flags; + + if (adp_pipelined) + { + adeos_declare_cpuid; + unsigned long s; + +#ifdef CONFIG_SMP + adeos_lock_cpu(flags); + s = __test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); + adeos_unlock_cpu(flags); +#else /* !CONFIG_SMP */ + s = test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status); +#endif /* CONFIG_SMP */ + + return s; + } + + adeos_hw_local_irq_save(flags); + + return !adeos_hw_test_iflag(flags); +} +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +void fastcall __adeos_restore_root (unsigned long flags) +#else /* LINUX_VERSION_CODE < 2.4.27 */ +void __adeos_restore_root (unsigned long flags) +#endif + +{ + if (flags) + __adeos_stall_root(); + else + __adeos_unstall_root(); +} + +/* adeos_unstall_pipeline_from() -- Unstall the interrupt pipeline and + synchronize pending events from a given domain. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27) +void fastcall adeos_unstall_pipeline_from (adomain_t *adp) +#else /* LINUX_VERSION_CODE < 2.4.27 */ +void adeos_unstall_pipeline_from (adomain_t *adp) +#endif +{ + adomain_t *this_domain; + struct list_head *pos; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + __clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status); + + this_domain = adp_cpu_current[cpuid]; + + if (adp == this_domain) + { + if (adp->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + + goto release_cpu_and_exit; + } + + /* Attempt to flush all events that might be pending at the + unstalled domain level. This code is roughly lifted from + __adeos_walk_pipeline(). */ + + list_for_each(pos,&__adeos_pipeline) { + + adomain_t *next_domain = list_entry(pos,adomain_t,p_link); + + if (test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) + break; /* Stalled stage -- do not go further. */ + + if (next_domain->cpudata[cpuid].irq_pending_hi != 0) + { + /* Since the critical IPI might be triggered by the + following actions, the current domain might not be + linked to the pipeline anymore after its handler + returns on SMP boxen, even if the domain remains valid + (see adeos_unregister_domain()), so don't make any + hazardous assumptions here. */ + + if (next_domain == this_domain) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + else + { + __adeos_switch_to(this_domain,next_domain,cpuid); + + adeos_load_cpuid(); /* Processor might have changed. */ + + if (!test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status) && + this_domain->cpudata[cpuid].irq_pending_hi != 0) + __adeos_sync_stage(IPIPE_IRQMASK_ANY); + } + + break; + } + else if (next_domain == this_domain) + break; + } + +release_cpu_and_exit: + + if (__adeos_pipeline_head_p(adp)) + adeos_hw_sti(); + else + adeos_unlock_cpu(flags); +} + +/* adeos_suspend_domain() -- tell the ADEOS layer that the current + domain is now dormant. The calling domain is switched out, while + the next domain with work in progress or pending in the pipeline is + switched in. */ + +#define __flush_pipeline_stage() \ +do { \ + if (!test_bit(IPIPE_STALL_FLAG,&cpudata->status) && \ + cpudata->irq_pending_hi != 0) \ + { \ + __adeos_sync_stage(IPIPE_IRQMASK_ANY); \ + adeos_load_cpuid(); \ + cpudata = &this_domain->cpudata[cpuid]; \ + } \ +} while(0) + +void adeos_suspend_domain (void) + +{ + adomain_t *this_domain, *next_domain; + struct adcpudata *cpudata; + struct list_head *ln; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + this_domain = next_domain = adp_cpu_current[cpuid]; + cpudata = &this_domain->cpudata[cpuid]; + + /* A suspending domain implicitely unstalls the pipeline. */ + __clear_bit(IPIPE_STALL_FLAG,&cpudata->status); + + /* Make sure that no event remains stuck in the pipeline. This + could happen with emerging SMP instances, or domains which + forget to unstall their stage before calling us. */ + __flush_pipeline_stage(); + + for (;;) + { + ln = next_domain->p_link.next; + + if (ln == &__adeos_pipeline) /* End of pipeline reached? */ + /* Caller should loop on its idle task on return. */ + goto release_cpu_and_exit; + + next_domain = list_entry(ln,adomain_t,p_link); + + /* Make sure the domain was preempted (i.e. not sleeping) or + has some event to process before switching to it. */ + + if (__adeos_domain_work_p(next_domain,cpuid)) + break; + } + + /* Mark the outgoing domain as aslept (i.e. not preempted). */ + __set_bit(IPIPE_SLEEP_FLAG,&cpudata->status); + + /* Suspend the calling domain, switching to the next one. */ + __adeos_switch_to(this_domain,next_domain,cpuid); + + /* Clear the sleep bit for the incoming domain. */ + __clear_bit(IPIPE_SLEEP_FLAG,&cpudata->status); + +#ifdef CONFIG_SMP + adeos_load_cpuid(); /* Processor might have changed. */ + cpudata = &this_domain->cpudata[cpuid]; +#endif /* CONFIG_SMP */ + + /* Now, we are back into the calling domain. Flush the interrupt + log and fire the event interposition handler if needed. CPU + migration is allowed in SMP-mode on behalf of an event handler + provided that the current domain raised it. Otherwise, it's + not. */ + + __flush_pipeline_stage(); + + if (__test_and_clear_bit(IPIPE_XPEND_FLAG,&cpudata->status)) + this_domain->events[cpudata->event_info.event].handler(&cpudata->event_info); + +release_cpu_and_exit: + + adeos_unlock_cpu(flags); + + /* Return to the point of suspension in the calling domain. */ +} + +/* adeos_alloc_irq() -- Allocate a virtual/soft pipelined interrupt. + Virtual interrupts are handled in exactly the same way than their + hw-generated counterparts. This is a very basic, one-way only, + inter-domain communication system (see adeos_trigger_irq()). Note: + it is not necessary for a domain to allocate a virtual interrupt to + trap it using adeos_virtualize_irq(). The newly allocated VIRQ + number which can be passed to other IRQ-related services is + returned on success, zero otherwise (i.e. no more virtual interrupt + channel is available). We need this service as part of the Adeos + bootstrap code, hence it must reside in a built-in area. */ + +unsigned adeos_alloc_irq (void) + +{ + unsigned long flags, irq = 0; + int ipos; + + adeos_spin_lock_irqsave(&__adeos_pipelock,flags); + + if (__adeos_virtual_irq_map != ~0) + { + ipos = ffz(__adeos_virtual_irq_map); + set_bit(ipos,&__adeos_virtual_irq_map); + irq = ipos + IPIPE_VIRQ_BASE; + } + + adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags); + + return irq; +} + +#ifdef CONFIG_PROC_FS + +#include + +static struct proc_dir_entry *adeos_proc_entry; + +static int __adeos_read_proc (char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + unsigned long ctlbits; + struct list_head *pos; + unsigned irq, _irq; + char *p = page; + int len; + +#ifdef CONFIG_ADEOS_MODULE + p += sprintf(p,"Adeos %s -- Pipelining: %s\n\n",ADEOS_VERSION_STRING,adp_pipelined ? "active" : "stopped"); +#else /* !CONFIG_ADEOS_MODULE */ + p += sprintf(p,"Adeos %s -- Pipelining: permanent\n\n",ADEOS_VERSION_STRING); +#endif /* CONFIG_ADEOS_MODULE */ + + spin_lock(&__adeos_pipelock); + + list_for_each(pos,&__adeos_pipeline) { + + adomain_t *adp = list_entry(pos,adomain_t,p_link); + + p += sprintf(p,"%8s: priority=%d, id=0x%.8x, ptdkeys=%d/%d\n", + adp->name, + adp->priority, + adp->domid, + adp->ptd_keycount, + adp->ptd_keymax); + irq = 0; + + while (irq < IPIPE_NR_IRQS) + { + ctlbits = (adp->irqs[irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK)); + + if (irq >= IPIPE_NR_XIRQS && !adeos_virtual_irq_p(irq)) + { + /* There maybe a hole between the last external IRQ + and the first virtual one; skip it. */ + irq++; + continue; + } + + if (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)) + { + /* Non-allocated virtual IRQ; skip it. */ + irq++; + continue; + } + + /* Attempt to group consecutive IRQ numbers having the + same virtualization settings in a single line. */ + + _irq = irq; + + while (++_irq < IPIPE_NR_IRQS) + { + if (adeos_virtual_irq_p(_irq) != adeos_virtual_irq_p(irq) || + (adeos_virtual_irq_p(_irq) && !test_bit(_irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)) || + ctlbits != (adp->irqs[_irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK))) + break; + } + + if (_irq == irq + 1) + p += sprintf(p,"\tirq%u: ",irq); + else + p += sprintf(p,"\tirq%u-%u: ",irq,_irq - 1); + + /* Statuses are as follows: + o "accepted" means handled _and_ passed down the + pipeline. + o "grabbed" means handled, but the interrupt might be + terminated _or_ passed down the pipeline depending on + what the domain handler asks for to Adeos. + o "passed" means unhandled by the domain but passed + down the pipeline. + o "discarded" means unhandled and _not_ passed down the + pipeline. The interrupt merely disappears from the + current domain down to the end of the pipeline. */ + + if (ctlbits & IPIPE_HANDLE_MASK) + { + if (ctlbits & IPIPE_PASS_MASK) + p += sprintf(p,"accepted"); + else + p += sprintf(p,"grabbed"); + } + else if (ctlbits & IPIPE_PASS_MASK) + p += sprintf(p,"passed"); + else + p += sprintf(p,"discarded"); + + if (ctlbits & IPIPE_STICKY_MASK) + p += sprintf(p,", sticky"); + + if (ctlbits & IPIPE_SHARED_MASK) + p += sprintf(p,", shared"); + + if (adeos_virtual_irq_p(irq)) + p += sprintf(p,", virtual"); + + p += sprintf(p,"\n"); + + irq = _irq; + } + } + + spin_unlock(&__adeos_pipelock); + + len = p - page; + + if (len <= off + count) + *eof = 1; + + *start = page + off; + + len -= off; + + if (len > count) + len = count; + + if (len < 0) + len = 0; + + return len; +} + +void __adeos_init_proc (void) { + + adeos_proc_entry = create_proc_read_entry("adeos", + 0444, + NULL, + &__adeos_read_proc, + NULL); +} + +#endif /* CONFIG_PROC_FS */ + +void __adeos_dump_state (void) + +{ + int _cpuid, nr_cpus = smp_num_cpus; + struct list_head *pos; + unsigned long flags; + adeos_declare_cpuid; + + adeos_lock_cpu(flags); + + printk(KERN_WARNING "Adeos: Current domain=%s on CPU #%d [stackbase=%p]\n", + adp_current->name, + cpuid, + (void *)adp_current->estackbase[cpuid]); + + list_for_each(pos,&__adeos_pipeline) { + + adomain_t *adp = list_entry(pos,adomain_t,p_link); + + for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++) + printk(KERN_WARNING "%8s[cpuid=%d]: priority=%d, status=0x%lx, pending_hi=0x%lx\n", + adp->name, + _cpuid, + adp->priority, + adp->cpudata[_cpuid].status, + adp->cpudata[_cpuid].irq_pending_hi); + } + + adeos_unlock_cpu(flags); +} diff -uNrp linux-2.4.31/kernel/exit.c linux-2.4.31-r18/kernel/exit.c --- linux-2.4.31/kernel/exit.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.31-r18/kernel/exit.c 2005-06-20 23:56:02.000000000 +0200 @@ -439,6 +439,9 @@ fake_volatile: #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif +#ifdef CONFIG_ADEOS_CORE + __adeos_exit_process(tsk); +#endif /* CONFIG_ADEOS_CORE */ __exit_mm(tsk); lock_kernel(); diff -uNrp linux-2.4.31/kernel/fork.c linux-2.4.31-r18/kernel/fork.c --- linux-2.4.31/kernel/fork.c 2005-01-19 15:10:13.000000000 +0100 +++ linux-2.4.31-r18/kernel/fork.c 2005-06-20 23:56:08.000000000 +0200 @@ -235,7 +235,13 @@ static struct mm_struct * mm_init(struct atomic_set(&mm->mm_count, 1); init_rwsem(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_ADEOS_CORE + adeos_spin_lock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ mm->pgd = pgd_alloc(mm); +#ifdef CONFIG_ADEOS_CORE + adeos_spin_unlock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ mm->def_flags = 0; if (mm->pgd) return mm; @@ -267,8 +273,15 @@ struct mm_struct * mm_alloc(void) void fastcall __mmdrop(struct mm_struct *mm) { BUG_ON(mm == &init_mm); - pgd_free(mm->pgd); +#ifdef CONFIG_ADEOS_CORE + adeos_hw_sti(); + adeos_spin_lock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ + pgd_free(mm->pgd); check_pgt_cache(); +#ifdef CONFIG_ADEOS_CORE + adeos_spin_unlock(&init_mm.page_table_lock); +#endif /* CONFIG_ADEOS_CORE */ destroy_context(mm); free_mm(mm); } @@ -820,6 +833,15 @@ int do_fork(unsigned long clone_flags, u nr_threads++; write_unlock_irq(&tasklist_lock); +#ifdef CONFIG_ADEOS_CORE + { + int k; + + for (k = 0; k < ADEOS_ROOT_NPTDKEYS; k++) + p->ptd[k] = NULL; + } +#endif /* CONFIG_ADEOS_CORE */ + if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); diff -uNrp linux-2.4.31/kernel/ksyms.c linux-2.4.31-r18/kernel/ksyms.c --- linux-2.4.31/kernel/ksyms.c 2004-02-18 14:36:32.000000000 +0100 +++ linux-2.4.31-r18/kernel/ksyms.c 2005-06-20 23:55:52.000000000 +0200 @@ -59,6 +59,37 @@ #include #endif +#ifdef CONFIG_ADEOS_CORE +EXPORT_SYMBOL(adeos_suspend_domain); +EXPORT_SYMBOL(adeos_alloc_irq); +EXPORT_SYMBOL(adp_cpu_current); +EXPORT_SYMBOL(adp_root); +EXPORT_SYMBOL(__adeos_init_stage); +EXPORT_SYMBOL(__adeos_handle_event); +EXPORT_SYMBOL(__adeos_stall_root); +EXPORT_SYMBOL(__adeos_unstall_root); +EXPORT_SYMBOL(__adeos_test_root); +EXPORT_SYMBOL(__adeos_test_and_stall_root); +EXPORT_SYMBOL(__adeos_restore_root); +EXPORT_SYMBOL(__adeos_schedule_back_root); +EXPORT_SYMBOL(__adeos_dump_state); +EXPORT_SYMBOL(adeos_unstall_pipeline_from); +extern struct list_head __adeos_pipeline; +EXPORT_SYMBOL(__adeos_pipeline); +extern spinlock_t __adeos_pipelock; +EXPORT_SYMBOL(__adeos_pipelock); +EXPORT_SYMBOL(__adeos_virtual_irq_map); +EXPORT_SYMBOL(__adeos_event_monitors); +#ifdef CONFIG_ADEOS_PROFILING +EXPORT_SYMBOL(__adeos_profile_data); +#endif /* CONFIG_ADEOS_PROFILING */ +/* The following are convenience exports which are needed by some + Adeos domains loaded as kernel modules. */ +EXPORT_SYMBOL_NOVERS(__mmdrop); +EXPORT_SYMBOL_NOVERS(do_fork); +EXPORT_SYMBOL_NOVERS(do_exit); +#endif /* CONFIG_ADEOS_CORE */ + extern void set_device_ro(kdev_t dev,int flag); extern void *sys_call_table; diff -uNrp linux-2.4.31/kernel/Makefile linux-2.4.31-r18/kernel/Makefile --- linux-2.4.31/kernel/Makefile 2001-09-17 06:22:40.000000000 +0200 +++ linux-2.4.31-r18/kernel/Makefile 2005-06-20 23:55:28.000000000 +0200 @@ -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 = adeos.o signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.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 \ @@ -19,6 +19,7 @@ obj-y = sched.o dma.o fork.o exec_do obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_ADEOS_CORE) += adeos.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -uNrp linux-2.4.31/kernel/panic.c linux-2.4.31-r18/kernel/panic.c --- linux-2.4.31/kernel/panic.c 2004-11-17 12:54:22.000000000 +0100 +++ linux-2.4.31-r18/kernel/panic.c 2005-06-20 23:56:28.000000000 +0200 @@ -68,6 +68,9 @@ NORET_TYPE void panic(const char * fmt, printk(KERN_EMERG "In idle task - not syncing\n"); else sys_sync(); +#ifdef CONFIG_ADEOS_CORE + __adeos_dump_state(); +#endif /* CONFIG_ADEOS_CORE */ bust_spinlocks(0); #ifdef CONFIG_SMP diff -uNrp linux-2.4.31/kernel/printk.c linux-2.4.31-r18/kernel/printk.c --- linux-2.4.31/kernel/printk.c 2004-11-17 12:54:22.000000000 +0100 +++ linux-2.4.31-r18/kernel/printk.c 2005-06-20 23:56:22.000000000 +0200 @@ -29,6 +29,17 @@ #include +#ifdef CONFIG_ADEOS_CORE +#undef spin_lock_irq +#define spin_lock_irq(lock) adeos_spin_lock_disable(lock) +#undef spin_unlock_irq +#define spin_unlock_irq(lock) adeos_spin_unlock_enable(lock) +#undef spin_lock_irqsave +#define spin_lock_irqsave(lock, flags) adeos_spin_lock_irqsave(lock,flags) +#undef spin_unlock_irqrestore +#define spin_unlock_irqrestore(lock, flags) adeos_spin_unlock_irqrestore(lock,flags) +#endif /* CONFIG_ADEOS_CORE */ + #if !defined(CONFIG_LOG_BUF_SHIFT) || (CONFIG_LOG_BUF_SHIFT == 0) #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) #define LOG_BUF_LEN (65536) @@ -451,6 +462,24 @@ asmlinkage int printk(const char *fmt, . log_level_unknown = 1; } +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root && !test_bit(ADEOS_SPRINTK_FLAG,&adp_current->flags)) { + /* When operating in asynchronous printk() mode, ensure + the console drivers and klogd wakeup are only run by + Linux, delegating the actual output to the root domain + by mean of a virtual IRQ kicking our sync handler. If + the current domain has a lower priority than Linux, + then we'll get immediately preempted by it. In + synchronous printk() mode, immediately call the console + drivers. */ + spin_unlock_irqrestore(&logbuf_lock, flags); + + if (!test_and_set_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags)) + adeos_trigger_irq(__adeos_printk_virq); + + goto out; + } +#endif /* CONFIG_ADEOS_CORE */ if (!arch_consoles_callable()) { /* * On some architectures, the consoles are not usable @@ -459,7 +488,11 @@ asmlinkage int printk(const char *fmt, . spin_unlock_irqrestore(&logbuf_lock, flags); goto out; } - if (!down_trylock(&console_sem)) { +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root || !down_trylock(&console_sem)) { +#else /* !CONFIG_ADEOS_CORE */ + if (!down_trylock(&console_sem)) { +#endif /* CONFIG_ADEOS_CORE */ /* * We own the drivers. We can drop the spinlock and let * release_console_sem() print the text @@ -529,12 +562,44 @@ void release_console_sem(void) call_console_drivers(_con_start, _log_end); } console_may_schedule = 0; +#ifdef CONFIG_ADEOS_CORE + if (adp_root != adp_current) { + spin_unlock_irqrestore(&logbuf_lock, flags); + return; + } + spin_unlock_irqrestore(&logbuf_lock, flags); + up(&console_sem); +#else /* !CONFIG_ADEOS_CORE */ up(&console_sem); spin_unlock_irqrestore(&logbuf_lock, flags); +#endif /* CONFIG_ADEOS_CORE */ if (must_wake_klogd && !oops_in_progress) wake_up_interruptible(&log_wait); } +#ifdef CONFIG_ADEOS_CORE +void __adeos_sync_console (unsigned virq) { + + /* This handler always runs on behalf of the root (Linux) domain. */ + unsigned long flags; + + spin_lock_irqsave(&logbuf_lock, flags); + + /* Not absolutely atomic wrt to the triggering point, but this is + harmless. We only try to reduce the useless triggers by a cheap + trick here. */ + + clear_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags); + + if (arch_consoles_callable() && !down_trylock(&console_sem)) { + spin_unlock_irqrestore(&logbuf_lock, flags); + console_may_schedule = 0; + release_console_sem(); + } else + spin_unlock_irqrestore(&logbuf_lock, flags); +} +#endif /* CONFIG_ADEOS_CORE */ + /** console_conditional_schedule - yield the CPU if required * * If the console code is currently allowed to sleep, and diff -uNrp linux-2.4.31/kernel/sched.c linux-2.4.31-r18/kernel/sched.c --- linux-2.4.31/kernel/sched.c 2004-11-17 12:54:22.000000000 +0100 +++ linux-2.4.31-r18/kernel/sched.c 2005-06-20 23:55:45.000000000 +0200 @@ -532,6 +532,9 @@ needs_resched: asmlinkage void schedule_tail(struct task_struct *prev) { __schedule_tail(prev); +#ifdef CONFIG_ADEOS_CORE + __adeos_enter_process(); +#endif /* CONFIG_ADEOS_CORE */ } /* @@ -551,6 +554,10 @@ asmlinkage void schedule(void) struct list_head *tmp; int this_cpu, c; +#ifdef CONFIG_ADEOS_CORE + if (adp_current != adp_root) /* Let's be helpful and conservative. */ + return; +#endif /* CONFIG_ADEOS_CORE */ spin_lock_prefetch(&runqueue_lock); @@ -668,7 +675,11 @@ repeat_schedule: * but prev is set to (the just run) 'last' process by switch_to(). * This might sound slightly confusing but makes tons of sense. */ +#ifdef CONFIG_ADEOS_CORE + prepare_to_switch(prev,next); +#else /* !CONFIG_ADEOS_CORE */ prepare_to_switch(); +#endif /* CONFIG_ADEOS_CORE */ { struct mm_struct *mm = next->mm; struct mm_struct *oldmm = prev->active_mm; @@ -693,6 +704,12 @@ repeat_schedule: * stack. */ switch_to(prev, next, prev); +#ifdef CONFIG_ADEOS_CORE + if (__adeos_schedule_tail(prev) > 0) + /* Some event handler asked for a truncated + scheduling tail. Just obey. */ + return; +#endif /* CONFIG_ADEOS_CORE */ __schedule_tail(prev); same_process: @@ -702,6 +719,20 @@ same_process: return; } +#ifdef CONFIG_ADEOS_CORE + +void __adeos_schedule_back_root (struct task_struct *prev) + +{ + __schedule_tail(prev); + reacquire_kernel_lock(current); +#ifdef CONFIG_PREEMPT + preempt_enable_no_resched(); +#endif /* CONFIG_PREEMPT */ +} + +#endif /* CONFIG_ADEOS_CORE */ + /* * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just wake everything * up. If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the @@ -989,6 +1020,13 @@ static int setscheduler(pid_t pid, int p goto out_unlock; retval = 0; +#ifdef CONFIG_ADEOS_CORE + { + struct { struct task_struct *task; int policy; struct sched_param *param; } evdata = { p, policy, &lp }; + if (__adeos_renice_process(&evdata)) + goto out_unlock; + } +#endif /* CONFIG_ADEOS_CORE */ p->policy = policy; p->rt_priority = lp.sched_priority; diff -uNrp linux-2.4.31/kernel/signal.c linux-2.4.31-r18/kernel/signal.c --- linux-2.4.31/kernel/signal.c 2004-02-18 14:36:32.000000000 +0100 +++ linux-2.4.31-r18/kernel/signal.c 2005-06-20 23:55:36.000000000 +0200 @@ -496,6 +496,13 @@ static inline void signal_wake_up(struct { t->sigpending = 1; +#ifdef CONFIG_ADEOS_CORE + { + struct { struct task_struct *t; } evdata = { t }; + __adeos_kick_process(&evdata); + } +#endif /* CONFIG_ADEOS_CORE */ + #ifdef CONFIG_SMP /* * If the task is running on a different CPU @@ -554,6 +561,17 @@ printk("SIG queue (%s:%d): %d ", t->comm if (!sig || !t->sig) goto out_nolock; +#ifdef CONFIG_ADEOS_CORE + /* If some domain handler in the pipeline doesn't ask for + propagation, return success pretending that 'sig' was + delivered. */ + { + struct { struct task_struct *task; int sig; } evdata = { t, sig }; + if (__adeos_signal_process(&evdata)) + goto out_nolock; + } +#endif /* CONFIG_ADEOS_CORE */ + spin_lock_irqsave(&t->sigmask_lock, flags); handle_stop_signal(sig, t); diff -uNrp linux-2.4.31/kernel/sysctl.c linux-2.4.31-r18/kernel/sysctl.c --- linux-2.4.31/kernel/sysctl.c 2005-01-19 15:10:13.000000000 +0100 +++ linux-2.4.31-r18/kernel/sysctl.c 2005-06-20 23:56:15.000000000 +0200 @@ -365,6 +365,9 @@ void __init sysctl_init(void) #ifdef CONFIG_PROC_FS register_proc_table(root_table, proc_sys_root); init_irq_proc(); +#ifdef CONFIG_ADEOS_CORE + __adeos_init_proc(); +#endif /* CONFIG_ADEOS_CORE */ #endif } diff -uNrp linux-2.4.31/Makefile linux-2.4.31-r18/Makefile --- linux-2.4.31/Makefile 2005-06-20 23:24:35.000000000 +0200 +++ linux-2.4.31-r18/Makefile 2005-06-20 23:54:29.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 31 -EXTRAVERSION = +EXTRAVERSION = -adeos KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -74,7 +74,7 @@ endif # images. Uncomment if you want to place them anywhere other than root. # -#export INSTALL_PATH=/boot +export INSTALL_PATH=/boot # # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory @@ -128,13 +128,14 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/f NETWORKS =net/network.o LIBS =$(TOPDIR)/lib/lib.a -SUBDIRS =kernel drivers mm fs net ipc lib crypto +SUBDIRS =kernel adeos drivers mm fs net ipc lib crypto DRIVERS-n := DRIVERS-y := DRIVERS-m := DRIVERS- := +DRIVERS-$(CONFIG_ADEOS) += adeos/built-in.o DRIVERS-$(CONFIG_ACPI_BOOT) += drivers/acpi/acpi.o DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o DRIVERS-y += drivers/char/char.o \ diff -uNrp linux-2.4.31/mm/vmalloc.c linux-2.4.31-r18/mm/vmalloc.c --- linux-2.4.31/mm/vmalloc.c 2004-04-14 15:05:41.000000000 +0200 +++ linux-2.4.31-r18/mm/vmalloc.c 2005-06-20 23:49:59.000000000 +0200 @@ -165,6 +165,9 @@ static inline int __vmalloc_area_pages ( dir = pgd_offset_k(address); spin_lock(&init_mm.page_table_lock); do { +#ifdef CONFIG_ADEOS_CORE + pgd_t olddir = *dir; +#endif /* CONFIG_ADEOS_CORE */ pmd_t *pmd; pmd = pmd_alloc(&init_mm, dir, address); @@ -174,6 +177,11 @@ static inline int __vmalloc_area_pages ( if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages)) goto err; // The kernel NEVER reclaims pmds, so no need to undo pmd_alloc() here +#ifdef CONFIG_ADEOS_CORE + if (pgd_val(olddir) != pgd_val(*dir)) + set_pgdir(address,*dir); +#endif /* CONFIG_ADEOS_CORE */ + address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end));