# # Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher # --- linux-2.4.28/CREDITS~colinux-0.6.1 2004-11-17 06:54:20.000000000 -0500 +++ linux-2.4.28/CREDITS 2004-11-27 15:59:21.283010512 -0500 @@ -54,6 +54,12 @@ S: CH-1015 Lausanne S: Switzerland +A: Dan Aloni +E: da-x@gmx.net +D: Cooperative Linux +D: Various kernel patches +S: Israel + N: Tim Alpaerts E: tim_alpaerts@toyota-motor-europe.com D: 802.2 class II logical link control layer, --- linux-2.4.28/Documentation/devices.txt~colinux-0.6.1 2004-02-18 08:36:30.000000000 -0500 +++ linux-2.4.28/Documentation/devices.txt 2004-11-27 15:59:21.285010208 -0500 @@ -1926,6 +1926,13 @@ 17 = /dev/cosa1c1 2nd board, 2nd channel ... + block coLinux Block devices + 0 = /dev/cobd0 First coLinux device + 1 = /dev/cobd1 Second coLinux device + ... + + These block devices map to files or devices in the host FS. + 118 char Solidum ??? 0 = /dev/solnp0 1 = /dev/solnp1 --- linux-2.4.28/Makefile~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 +++ linux-2.4.28/Makefile 2004-11-27 15:59:30.235649504 -0500 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 28 -EXTRAVERSION = +EXTRAVERSION = -co-0.6.1 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -27,7 +27,11 @@ AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -CC = $(CROSS_COMPILE)gcc +ifeq ($(GCCTRACE),Y) +CC = $(CROSS_COMPILE)$(COLINUX_ROOT)/bin/tracewrapper.py gcc +else +CC = $(CROSS_COMPILE)gcc +endif CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm --- linux-2.4.28/arch/i386/config.in~colinux-0.6.1 2004-11-17 06:54:21.000000000 -0500 +++ linux-2.4.28/arch/i386/config.in 2004-11-27 15:59:21.286010056 -0500 @@ -226,13 +226,20 @@ bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_SMP" != "y" ]; then - bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC - dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC - if [ "$CONFIG_X86_UP_APIC" = "y" ]; then - define_bool CONFIG_X86_LOCAL_APIC y - fi - if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then - define_bool CONFIG_X86_IO_APIC y + if [ "$CONFIG_COOPERATIVE" = "y" ]; then + bool 'Cooperative PIC (COPIC) support' CONFIG_X86_UP_COPIC + if [ "$CONFIG_X86_UP_COPIC" = "y" ]; then + define_bool CONFIG_X86_COPIC y + fi + else + bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC + dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC + if [ "$CONFIG_X86_UP_APIC" = "y" ]; then + define_bool CONFIG_X86_LOCAL_APIC y + fi + if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then + define_bool CONFIG_X86_IO_APIC y + fi fi else int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32 @@ -343,12 +350,13 @@ bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi +bool 'Cooperative Mode' CONFIG_COOPERATIVE + source drivers/acpi/Config.in endmenu source drivers/mtd/Config.in - source drivers/parport/Config.in source drivers/pnp/Config.in @@ -445,7 +453,11 @@ if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' - bool 'VGA text console' CONFIG_VGA_CONSOLE + if [ "$CONFIG_COOPERATIVE" = "n" ]; then + bool 'VGA text console' CONFIG_VGA_CONSOLE + else + bool 'coLinux Pseudo-VGA text console' CONFIG_COOPERATIVE_CONSOLE + fi bool 'Video mode selection support' CONFIG_VIDEO_SELECT if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE --- linux-2.4.28/arch/i386/kernel/Makefile~colinux-0.6.1 2003-11-28 13:26:19.000000000 -0500 +++ linux-2.4.28/arch/i386/kernel/Makefile 2004-11-27 15:59:21.287009904 -0500 @@ -18,7 +18,7 @@ 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 \ - pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o + pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o cooperative.o \ ifdef CONFIG_PCI --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/arch/i386/kernel/cooperative.c 2004-11-27 15:59:21.287009904 -0500 @@ -0,0 +1,160 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +CO_TRACE_STOP; + + +/* + * The next asm code is the first Linux code that runs in the + * coLinux kernel context. It receives %ecx which contains the + * address of the passage page. The passage page code sets %ecx + * to this value in its context restore part. + */ + +asm( + "" + ".section .text\n" + ".globl colinux_start\n" + "colinux_start:\n" + " call colinux_start_arch\n" + ".previous\n" + ""); + +static void colinux_early_cpu_init(void) +{ + /* + * On the first switch to Linux we must set up a valid TR because + * the passage page code assumes such one exists. This is basically + * copied code from cpu_init(). + * + * P.S this is protected by CO_TRACE_STOP so that we don't + * have a monitor context switch. + */ + + int nr = smp_processor_id(); + struct tss_struct * t = &init_tss[nr]; + + set_tss_desc(nr,t); + gdt_table[__TSS(nr)].b &= 0xfffffdff; + load_TR(nr); + gdt_table[__TSS(nr)].b &= 0xfffffdff; + + __asm__ __volatile__("movl %%cr4, %0" : "=r" (mmu_cr4_features)); +} + +void colinux_start_arch() +{ + colinux_early_cpu_init(); + colinux_start_c(); +} + +extern void ctrl_alt_del(void); + +void co_handle_device_interrupt(co_linux_message_t *message) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (message->device) { + case CO_DEVICE_TIMER: { + co_linux_message_idle_t data = *(co_linux_message_idle_t *)message->data; + + if (data.tick_count > HZ) { + xtime.tv_sec += data.tick_count / HZ; + data.tick_count -= ((data.tick_count / HZ) * HZ); + } + + + while (data.tick_count > 0) { + struct pt_regs regs = {0, }; + regs.orig_eax = TIMER_IRQ; + do_IRQ(regs); + + data.tick_count--; + } + break; + } + case CO_DEVICE_POWER: { + co_linux_message_power_t *type = (co_scan_code_t *)message->data; + switch (type->type) { + case CO_LINUX_MESSAGE_POWER_ALT_CTRL_DEL: { + ctrl_alt_del(); + break; + } + } + break; + } + + case CO_DEVICE_KEYBOARD: { + struct pt_regs regs; + co_received_message(message); + regs.orig_eax = KEYBOARD_IRQ; + do_IRQ(regs); + break; + } + + case CO_DEVICE_NETWORK: { + struct pt_regs regs; + if (message->size > 1600) { + printk("co_handle_device_interrupt: warning, packet len: %d\n", message->size); + break; + } + co_received_message(message); + regs.orig_eax = NETWORK_IRQ; + do_IRQ(regs); + break; + } + default: + break; + } + + local_irq_restore(flags); +} + +void co_switch_wrapper_protected(void) +{ + /* + * We don't trust the passage page code to safely restore %gs and %fs. + * + * This wrapper ensures that if %fs or %gs are invalid, the processes + * exits with a segmentation fault rather than bringing down the + * machine. + **/ + unsigned long fs = 0; + unsigned long gs = 0; + + asm volatile("movl %%fs,%0": "=m" (fs)); + asm volatile("movl %%gs,%0": "=m" (gs)); + + /* + * Nullify the registers so the passage page code restores to + * null segment values on return. + */ + asm volatile("movl %0, %%fs; movl %0, %%gs" : : "r" (0)); + + /* And switch... */ + co_switch(); + + /* + * Safely restore the registers. + */ + loadsegment(fs, fs); + loadsegment(gs, gs); +} + +void co_switch_wrapper(void) +{ + co_switch_wrapper_protected(); +} + +CO_TRACE_CONTINUE; + --- linux-2.4.28/arch/i386/kernel/head.S~colinux-0.6.1 2003-11-28 13:26:19.000000000 -0500 +++ linux-2.4.28/arch/i386/kernel/head.S 2004-11-27 15:59:21.287009904 -0500 @@ -320,7 +320,7 @@ ret ENTRY(stack_start) - .long SYMBOL_NAME(init_task_union)+8192 + .long SYMBOL_NAME(init_task_union)+8192-100 .long __KERNEL_DS /* This is the default interrupt "handler" :-) */ @@ -361,12 +361,14 @@ ALIGN .word 0 +.globl idt_descr idt_descr: .word IDT_ENTRIES*8-1 # idt contains 256 entries SYMBOL_NAME(idt): .long SYMBOL_NAME(idt_table) .word 0 +.globl gdt_descr gdt_descr: .word GDT_ENTRIES*8-1 SYMBOL_NAME(gdt): --- linux-2.4.28/arch/i386/kernel/i387.c~colinux-0.6.1 2003-08-25 07:44:39.000000000 -0400 +++ linux-2.4.28/arch/i386/kernel/i387.c 2004-11-27 15:59:21.288009752 -0500 @@ -342,6 +342,8 @@ return 1; } +CO_TRACE_STOP; + int save_i387( struct _fpstate *buf ) { if ( !current->used_math ) @@ -363,6 +365,8 @@ } } +CO_TRACE_CONTINUE; + static inline int restore_i387_fsave( struct _fpstate *buf ) { struct task_struct *tsk = current; @@ -383,6 +387,8 @@ return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf ); } +CO_TRACE_STOP; + int restore_i387( struct _fpstate *buf ) { int err; @@ -400,6 +406,8 @@ return err; } +CO_TRACE_CONTINUE; + /* * ptrace request handlers. */ --- linux-2.4.28/arch/i386/kernel/i8259.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/arch/i386/kernel/i8259.c 2004-11-27 15:59:21.288009752 -0500 @@ -24,6 +24,7 @@ #include #include +#include /* * Common place to define all x86 IRQ vectors @@ -121,6 +122,81 @@ #undef IRQ #undef IRQLIST_16 +#ifdef CONFIG_COOPERATIVE + +CO_TRACE_STOP; + +void proxy_interrupt_handler(unsigned long interrupt, struct pt_regs regs) +{ + co_passage_page->operation = CO_OPERATION_FORWARD_INTERRUPT; + co_passage_page->params[0] = interrupt + 0x20; + co_passage_page->params[1] = regs.eip; + co_passage_page->params[2] = (unsigned long)(&((&interrupt)[10])); + co_passage_page->host_state.flags &= ~(1 << 9); /* Turn IF off */ + + co_switch_wrapper(); + co_callback(); +} + +CO_TRACE_CONTINUE; + +#define IRQLIST_16(x) \ + IRQ(x,0) IRQ(x,1) IRQ(x,2) IRQ(x,3) \ + IRQ(x,4) IRQ(x,5) IRQ(x,6) IRQ(x,7) \ + IRQ(x,8) IRQ(x,9) IRQ(x,a) IRQ(x,b) \ + IRQ(x,c) IRQ(x,d) IRQ(x,e) IRQ(x,f) + +#define IRQLIST_224 \ + IRQLIST_16(0x0) IRQLIST_16(0x1) IRQLIST_16(0x2) IRQLIST_16(0x3) \ + IRQLIST_16(0x4) IRQLIST_16(0x5) IRQLIST_16(0x6) IRQLIST_16(0x7) \ + IRQLIST_16(0x8) IRQLIST_16(0x9) IRQLIST_16(0xa) IRQLIST_16(0xb) \ + IRQLIST_16(0xc) IRQLIST_16(0xd) + +#define IRQ(x,y) \ + extern asmlinkage void IRQ_proxy_##x##y##_interrupt(void); +IRQLIST_224; +#undef IRQ + +struct _fpstate co_interrupt_register_state; + +#define BIRQ(id) \ +asm( \ + "\n"__ALIGN_STR"\n" \ + ".section .text\n" \ + ".globl IRQ_proxy_" #id "_interrupt\n" \ + "IRQ_proxy_" #id "_interrupt:\n" \ + "push %eax\n\t" \ + SAVE_ALL \ + \ + "pushl $co_interrupt_register_state\n\t" \ + "call save_i387\n\t" \ + "popl %ebx\n\t" \ + "pushl $" #id "\n\t" \ + "call proxy_interrupt_handler\n\t" \ + "popl %ebx\n\t" \ + "pushl $co_interrupt_register_state\n\t" \ + "call restore_i387\n\t" \ + "popl %ebx\n\t" \ + \ + "jmp ret_from_intr\n" \ + ".previous\n" \ + ); \ + +#define IRQ(x,y) BIRQ(x##y) +IRQLIST_224; +#undef IRQ + +#define IRQ(x,y) &IRQ_proxy_##x##y##_interrupt, +void (*proxy_interrupt[NR_IRQS])(void) = { + IRQLIST_224 +}; +#undef IRQ + +#undef IRQLIST_16 +#undef IRQLIST_224 + +#endif + /* * This is the 'legacy' 8259A Programmable Interrupt Controller, * present in the majority of PC/AT boxes. @@ -441,15 +517,74 @@ } } +#ifdef CONFIG_X86_COPIC + +/* + * Not like you have any other choice other than using + * COPIC in Cooperative mode. + */ + +static void end_COPIC_irq(unsigned int irq) +{ +} + +#define shutdown_COPIC_irq disable_COPIC_irq + +static void mask_and_ack_COPIC(unsigned int irq) +{ +} + +static unsigned int startup_COPIC_irq(unsigned int irq) +{ + return 0; +} + +void disable_COPIC_irq(unsigned int irq) +{ +} + +void enable_COPIC_irq(unsigned int irq) +{ +} + +static struct hw_interrupt_type co_pic_irq_type = { + "CO-PIC", + startup_COPIC_irq, + shutdown_COPIC_irq, + enable_COPIC_irq, + disable_COPIC_irq, + mask_and_ack_COPIC, + end_COPIC_irq, + NULL +}; + +void __init init_COPIC_irqs(void) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + + irq_desc[i].handler = &co_pic_irq_type; + } + +} + +#endif + void __init init_IRQ(void) { int i; +#ifndef CONFIG_COOPERATIVE #ifndef CONFIG_X86_VISWS_APIC init_ISA_irqs(); #else init_VISWS_APIC_irqs(); #endif + /* * Cover the whole vector space, no vector can escape * us. (some of these will be overridden and become @@ -490,6 +625,8 @@ set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); #endif + +#ifndef CONFIG_COOPERATIVE /* * Set the clock to HZ Hz, we already have a valid * vector now: @@ -509,4 +646,20 @@ */ if (boot_cpu_data.hard_math && !cpu_has_fpu) setup_irq(13, &irq13); +#endif + +#else + printk("Setting proxy interrupt vectors\n"); + +#ifdef CONFIG_X86_COPIC + init_COPIC_irqs(); +#endif + + for (i = 0; i < NR_IRQS; i++) { + int vector = FIRST_EXTERNAL_VECTOR + i; + if (vector != SYSCALL_VECTOR) { + set_intr_gate(vector, proxy_interrupt[i]); + } + } +#endif } --- linux-2.4.28/arch/i386/kernel/ioport.c~colinux-0.6.1 2003-06-13 10:51:29.000000000 -0400 +++ linux-2.4.28/arch/i386/kernel/ioport.c 2004-11-27 15:59:21.289009600 -0500 @@ -54,6 +54,7 @@ */ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { +#ifndef CONFIG_COOPERATIVE struct thread_struct * t = ¤t->thread; struct tss_struct * tss = init_tss + smp_processor_id(); @@ -86,6 +87,10 @@ } return 0; +#else + /* No ports for yer VM */ + return -EPERM; +#endif } /* @@ -101,6 +106,7 @@ asmlinkage int sys_iopl(unsigned long unused) { +#ifndef CONFIG_COOPERATIVE struct pt_regs * regs = (struct pt_regs *) &unused; unsigned int level = regs->ebx; unsigned int old = (regs->eflags >> 12) & 3; @@ -114,4 +120,8 @@ } regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); return 0; +#else + /* No IPL for yer VM */ + return -EPERM; +#endif } --- linux-2.4.28/arch/i386/kernel/process.c~colinux-0.6.1 2004-11-17 06:54:21.000000000 -0500 +++ linux-2.4.28/arch/i386/kernel/process.c 2004-11-27 15:59:21.289009600 -0500 @@ -51,6 +51,7 @@ #include #include +#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -131,11 +132,15 @@ current->counter = -100; while (1) { +#ifdef CONFIG_COOPERATIVE + co_idle_processor(); +#else void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; while (!current->need_resched) idle(); +#endif schedule(); check_pgt_cache(); } @@ -280,6 +285,7 @@ */ void machine_real_restart(unsigned char *code, int length) { +#ifndef CONFIG_COOPERATIVE unsigned long flags; cli(); @@ -363,10 +369,14 @@ __asm__ __volatile__ ("ljmp $0x0008,%0" : : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +#else + co_terminate(CO_TERMINATE_REBOOT); +#endif } void machine_restart(char * __unused) { +#ifndef CONFIG_COOPERATIVE #if CONFIG_SMP int cpuid; @@ -430,16 +440,26 @@ } machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); +#else + co_terminate(CO_TERMINATE_REBOOT); +#endif } void machine_halt(void) { +#ifdef CONFIG_COOPERATIVE + co_terminate(CO_TERMINATE_HALT); +#endif } void machine_power_off(void) { +#ifndef CONFIG_COOPERATIVE if (pm_power_off) pm_power_off(); +#else + co_terminate(CO_TERMINATE_POWEROFF); +#endif } extern void show_trace(unsigned long* esp); @@ -657,12 +677,20 @@ */ tss->esp0 = next->esp0; +#ifdef CONFIG_COOPERATIVE + /* + * We would save %fs and %gs using an atomic operation in the + * just before the LDT of the next process is loaded. It is + * not here, it's in... + */ +#else /* * Save away %fs and %gs. No need to save %es and %ds, as * those are always kernel segments while inside the kernel. */ asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs)); asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); +#endif /* * Restore %fs and %gs. --- linux-2.4.28/arch/i386/kernel/setup.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/arch/i386/kernel/setup.c 2004-11-27 15:59:21.291009296 -0500 @@ -108,6 +108,7 @@ #include #include #include +#include #include #include #include @@ -782,9 +783,18 @@ int len = 0; int userdef = 0; +#ifdef CONFIG_COOPERATIVE + /* + * Better to have 'root=/dev/cobd0' here. + */ + from = co_boot_parameters; + snprintf(saved_command_line, COMMAND_LINE_SIZE, "%s", + co_boot_parameters); +#else /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; +#endif for (;;) { if (c != ' ') @@ -1044,16 +1054,23 @@ static unsigned long __init setup_memory(void) { unsigned long bootmap_size, start_pfn, max_low_pfn; - +#ifdef CONFIG_COOPERATIVE + unsigned long bootmem_size; + unsigned long bootmem_start; +#endif /* * partially used pages are not usable - thus * we are rounding upwards: */ start_pfn = PFN_UP(__pa(&_end)); +#ifdef CONFIG_COOPERATIVE + max_low_pfn = max_pfn = co_memory_size / PAGE_SIZE; +#else find_max_pfn(); max_low_pfn = find_max_low_pfn(); +#endif #ifdef CONFIG_HIGHMEM highstart_pfn = highend_pfn = max_pfn; @@ -1065,12 +1082,19 @@ #endif printk(KERN_NOTICE "%ldMB LOWMEM available.\n", pages_to_mb(max_low_pfn)); + /* * Initialize the boot-time allocator (with low memory only): */ bootmap_size = init_bootmem(start_pfn, max_low_pfn); - register_bootmem_low_pages(max_low_pfn); +#ifdef CONFIG_COOPERATIVE + bootmap_size = (bootmap_size + PAGE_SIZE - 1) & PAGE_MASK; + bootmem_size = (0x800 << PAGE_SHIFT) - bootmap_size; + bootmem_start = co_core_end + bootmap_size; + + free_bootmem(__pa(bootmem_start), bootmem_size); +#else /* * Reserve the bootmem bitmap itself as well. We do this in two @@ -1124,7 +1148,7 @@ } } #endif - +#endif return max_low_pfn; } @@ -1176,7 +1200,9 @@ void __init setup_arch(char **cmdline_p) { +#ifndef CONFIG_COOPERATIVE unsigned long max_low_pfn; +#endif #ifdef CONFIG_VISWS visws_get_board_type_and_rev(); @@ -1186,6 +1212,7 @@ blk_nohighio = 1; #endif + boot_cpu_data.hard_math = 1; ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; @@ -1203,7 +1230,10 @@ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif + +#ifndef CONFIG_COOPERATIVE setup_memory_region(); +#endif copy_edd(); if (!MOUNT_ROOT_RDONLY) @@ -1230,8 +1260,10 @@ #ifdef CONFIG_SMP smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif + paging_init(); +#ifndef CONFIG_COOPERATIVE dmi_scan_machine(); /* @@ -1248,14 +1280,19 @@ #endif register_memory(max_low_pfn); +#endif #ifdef CONFIG_VT +#ifdef CONFIG_COOPERATIVE_CONSOLE + conswitchp = &colinux_con; +#else #if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; #elif defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; #endif #endif +#endif } static int cachesize_override __initdata = -1; @@ -3216,29 +3253,41 @@ if(current->mm) BUG(); enter_lazy_tlb(&init_mm, current, nr); - t->esp0 = current->thread.esp0; + set_tss_desc(nr,t); gdt_table[__TSS(nr)].b &= 0xfffffdff; + load_TR(nr); load_LDT(&init_mm.context); /* * Clear all 6 debug registers: */ - +#ifndef CONFIG_COOPERATIVE #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7); #undef CD - +#endif /* * Force FPU initialization: */ current->flags &= ~PF_USEDFPU; current->used_math = 0; +#ifndef CONFIG_COOPERATIVE stts(); +#else +#if (0) + clear_in_cr4(X86_CR4_PVI); + clear_in_cr4(X86_CR4_DE); + clear_in_cr4(X86_CR4_MCE); + clear_in_cr4(X86_CR4_PGE); + flush_tlb_all(); + clear_in_cr4(X86_CR4_OSXMMEXCPT); +#endif +#endif } /* --- linux-2.4.28/arch/i386/kernel/time.c~colinux-0.6.1 2004-02-18 08:36:30.000000000 -0500 +++ linux-2.4.28/arch/i386/kernel/time.c 2004-11-27 15:59:21.292009144 -0500 @@ -84,8 +84,24 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; -static inline unsigned long do_fast_gettimeoffset(void) +static inline unsigned long long rdtsc_u64(void) +{ + register unsigned long eax, edx; + + rdtsc(eax,edx); + + return ((((unsigned long long)edx) << 32) | eax); +} + +#ifdef CONFIG_COOPERATIVE +static unsigned long long co_last_interrupt_time; +static unsigned long co_tsc_per_5_ticks; +static long co_last_time_offset; +#endif + +static inline long do_fast_gettimeoffset(void) { +#ifndef CONFIG_COOPERATIVE register unsigned long eax, edx; /* Read the Time Stamp Counter */ @@ -111,6 +127,32 @@ /* our adjusted time offset in microseconds */ return delay_at_last_interrupt + edx; +#else + union { + unsigned long long ll_var; + struct { unsigned long low, high; }; + } differential; + unsigned long edx; + unsigned long ret = 0; + + differential.ll_var = rdtsc_u64() - co_last_interrupt_time; + if (differential.high) + return 0; + + if (co_tsc_per_5_ticks == 0) + return 0; + + differential.ll_var *= 50000; + + __asm__("divl %2" + :"=a" (ret), "=d" (edx) + :"r" (co_tsc_per_5_ticks), + "0" (differential.low), "1" (differential.high)); + + ret += co_last_time_offset; + + return ret; +#endif } #define TICK_SIZE tick @@ -121,6 +163,8 @@ extern spinlock_t i8259A_lock; +#ifndef CONFIG_COOPERATIVE + #ifndef CONFIG_X86_TSC /* This function must be called with interrupts disabled @@ -254,7 +298,16 @@ return count; } -static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; +#else + +static unsigned long do_slow_gettimeoffset(void) +{ + return 0; +} + +#endif + +static long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; /* IBM Summit (EXA) Cyclone Timer code*/ @@ -305,7 +358,7 @@ delay_at_last_interrupt = (count + LATCH/2) / LATCH; } -static unsigned long do_gettimeoffset_cyclone(void) +static long do_gettimeoffset_cyclone(void) { u32 offset; @@ -443,7 +496,8 @@ void do_gettimeofday(struct timeval *tv) { unsigned long flags; - unsigned long usec, sec; + unsigned long sec; + long usec; read_lock_irqsave(&xtime_lock, flags); usec = do_gettimeoffset(); @@ -461,6 +515,11 @@ sec++; } + if (usec < 0) { + usec = usec + 1000000; + sec -= 1; + } + tv->tv_sec = sec; tv->tv_usec = usec; } @@ -502,6 +561,7 @@ */ static int set_rtc_mmss(unsigned long nowtime) { +#ifndef CONFIG_COOPERATIVE int retval = 0; int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; @@ -554,8 +614,13 @@ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); spin_unlock(&rtc_lock); - return retval; +#else + /* + * Don't let Linux change the system time of the host machine. + */ + return -1; +#endif } /* last time the cmos clock got updated */ @@ -603,6 +668,7 @@ smp_local_timer_interrupt(regs); #endif +#ifndef CONFIG_COOPERATIVE /* * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be @@ -617,6 +683,7 @@ else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } +#endif #ifdef CONFIG_MCA if( MCA_bus ) { @@ -655,6 +722,7 @@ */ write_lock(&xtime_lock); +#ifndef CONFIG_COOPERATIVE if(use_cyclone) mark_timeoffset_cyclone(); else if (use_tsc) { @@ -706,7 +774,15 @@ count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; } - +#else + if (use_tsc) { + if (co_last_interrupt_time == 0) + co_last_time_offset = 0; + else + co_last_time_offset = ((long)do_fast_gettimeoffset()) - 10000; + co_last_interrupt_time = rdtsc_u64(); + } +#endif do_timer_interrupt(irq, NULL, regs); write_unlock(&xtime_lock); @@ -716,6 +792,7 @@ /* not static: needed by APM */ unsigned long get_cmos_time(void) { +#ifndef CONFIG_COOPERATIVE unsigned int year, mon, day, hour, min, sec; int i; @@ -753,6 +830,9 @@ if ((year += 1900) < 1970) year += 100; return mktime(year, mon, day, hour, min, sec); +#else + return co_get_host_time(); +#endif } static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; @@ -818,6 +898,10 @@ if (endlow <= CALIBRATE_TIME) goto bad_ctc; +#ifdef CONFIG_COOPERATIVE + co_tsc_per_5_ticks = endlow; +#endif + __asm__("divl %2" :"=a" (endlow), "=d" (endhigh) :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME)); @@ -870,7 +954,13 @@ if(use_cyclone) init_cyclone_clock(); - + +#ifdef CONFIG_COOPERATIVE + /* + * We pretty much depend on this at the moment... + */ + set_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability); +#endif if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); if (tsc_quotient) { --- linux-2.4.28/arch/i386/kernel/traps.c~colinux-0.6.1 2002-11-28 18:53:09.000000000 -0500 +++ linux-2.4.28/arch/i386/kernel/traps.c 2004-11-27 15:59:21.293008992 -0500 @@ -852,11 +852,20 @@ "rorl $16,%%eax" \ : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) +CO_TRACE_STOP; + +/* + * We use this in colinux_early_cpu_init(), so it must be protected + * from traces. + */ + void set_tss_desc(unsigned int n, void *addr) { _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89); } +CO_TRACE_CONTINUE; + void set_ldt_desc(unsigned int n, void *addr, unsigned int size) { _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); --- linux-2.4.28/arch/i386/mm/fault.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/arch/i386/mm/fault.c 2004-11-27 15:59:21.293008992 -0500 @@ -380,7 +380,11 @@ pte_t *pte_k; asm("movl %%cr3,%0":"=r" (pgd)); +#ifndef CONFIG_COOPERATIVE pgd = offset + (pgd_t *)__va(pgd); +#else + pgd = offset + (pgd_t *)CO_VA(((unsigned long)pgd)); +#endif pgd_k = init_mm.pgd + offset; if (!pgd_present(*pgd_k)) --- linux-2.4.28/arch/i386/mm/init.c~colinux-0.6.1 2004-04-14 09:05:25.000000000 -0400 +++ linux-2.4.28/arch/i386/mm/init.c 2004-11-27 15:59:21.294008840 -0500 @@ -38,6 +38,8 @@ #include #include +#include + mmu_gather_t mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; static unsigned long totalram_pages; @@ -122,7 +124,7 @@ /* References to section boundaries */ -extern char _text, _etext, _edata, __bss_start, _end; +extern char _text, _etext, _edata, _sdata, __bss_start, _end; extern char __init_begin, __init_end; static inline void set_pte_phys (unsigned long vaddr, @@ -204,6 +206,7 @@ static void __init pagetable_init (void) { +#ifndef CONFIG_COOPERATIVE unsigned long vaddr, end; pgd_t *pgd, *pgd_base; int i, j, k; @@ -300,6 +303,8 @@ */ pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; #endif +#else +#endif } void __init zap_low_mappings (void) @@ -325,6 +330,7 @@ unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; unsigned int max_dma, high, low; +#ifndef CONFIG_COOPERATIVE max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; low = max_low_pfn; high = highend_pfn; @@ -338,6 +344,11 @@ zones_size[ZONE_HIGHMEM] = high - low; #endif } +#else + zones_size[ZONE_DMA] = 0; + zones_size[ZONE_NORMAL] = max_low_pfn; + zones_size[ZONE_HIGHMEM] = 0; +#endif free_area_init(zones_size); } @@ -485,6 +496,22 @@ bad_ppro = ppro_with_ram_bug(); +#ifdef CONFIG_COOPERATIVE + /* + * Only at this stage, after the buddy allocator's maps + * have been allocated, we can let the kernel use its + * other pseudo physical space. + */ + { + unsigned long bootmem_end = co_core_end + + (0x800 << PAGE_SHIFT); + unsigned long physical_end = __PAGE_OFFSET + + (max_low_pfn << PAGE_SHIFT); + + free_bootmem(__pa(bootmem_end), physical_end - bootmem_end); + } + +#endif /* this will put all low memory onto the freelists */ totalram_pages += free_all_bootmem(); @@ -529,7 +556,7 @@ reservedpages = free_pages_init(); codesize = (unsigned long) &_etext - (unsigned long) &_text; - datasize = (unsigned long) &_edata - (unsigned long) &_etext; + datasize = (unsigned long) &_edata - (unsigned long) &_sdata; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", @@ -546,19 +573,21 @@ if (!cpu_has_pae) panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); #endif +#ifndef CONFIG_COOPERATIVE if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); - +#endif /* * Subtle. SMP is doing it's boot stuff late (because it has to * fork idle threads) - but it also needs low mappings for the * protected-mode entry to work. We zap these entries only after * the WP-bit has been tested. */ +#ifndef CONFIG_COOPERATIVE #ifndef CONFIG_SMP zap_low_mappings(); #endif - +#endif } /* Put this after the callers, so that it cannot be inlined */ --- linux-2.4.28/arch/i386/vmlinux.lds~colinux-0.6.1 2002-02-25 14:37:53.000000000 -0500 +++ linux-2.4.28/arch/i386/vmlinux.lds 2004-11-27 15:59:21.294008840 -0500 @@ -7,50 +7,72 @@ SECTIONS { . = 0xC0000000 + 0x100000; - _text = .; /* Text and read-only data */ + _kernel_start = .; .text : { + _text = .; /* Text and read-only data */ *(.text) *(.fixup) *(.gnu.warning) - } = 0x9090 - - _etext = .; /* End of text section */ + _etext = .; /* End of text section */ + } .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; + __ex_table : { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; + . = ALIGN(4); + __import_table_address : { + __start_import_address = .; + *(__im_table_address) + __stop_import_address = .; + } + __ksymtab : { + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + } .data : { /* Data */ + _sdata = .; /* Start of data section */ *(.data) CONSTRUCTORS - } + _edata = .; /* End of data section */ + } - _edata = .; /* End of data section */ + . = ALIGN(4096); /* gdt */ + .data.gdt : { + *(.data.gdt) + } + .data.idt : { + *(.data.idt) + } . = ALIGN(8192); /* init_task */ - .data.init_task : { *(.data.init_task) } + .data.init_task : { + *(.data.init_task) + } . = ALIGN(4096); /* Init code and data */ - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); - __init_end = .; + .init : { + __init_begin = .; + *(.text.init) + *(.data.init) + . = ALIGN(16); + __setup_start = .; + *(.setup.init) + __setup_end = .; + __initcall_start = .; + *(.initcall.init) + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + } . = ALIGN(4096); .data.page_aligned : { *(.data.idt) } @@ -58,11 +80,11 @@ . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } - __bss_start = .; /* BSS */ .bss : { + __bss_start = .; /* BSS */ *(.bss) - } - _end = . ; + _end = . ; + } /* Sections to be discarded */ /DISCARD/ : { --- linux-2.4.28/drivers/block/Config.in~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/drivers/block/Config.in 2004-11-27 15:59:21.294008840 -0500 @@ -50,6 +50,10 @@ fi dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM +if [ "$CONFIG_COOPERATIVE" = "y" ]; then + tristate 'coLinux block device support' CONFIG_BLK_DEV_PBD +fi + bool 'Per partition statistics in /proc/partitions' CONFIG_BLK_STATS endmenu --- linux-2.4.28/drivers/block/Makefile~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/drivers/block/Makefile 2004-11-27 15:59:21.295008688 -0500 @@ -31,6 +31,7 @@ obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o +obj-$(CONFIG_BLK_DEV_PBD) += cobd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o subdir-$(CONFIG_PARIDE) += paride --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/drivers/block/cobd.c 2004-11-27 15:59:21.295008688 -0500 @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2003 Dan Aloni + * + * Cooperative Linux Block Device implementation + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR COLINUX_MAJOR +#define DEVICE_NR(device) MINOR(device) /* has no partition bits */ +#define DEVICE_NAME "cobd" /* name for messaging */ +#define DEVICE_NO_RANDOM /* no entropy to contribute */ +#define DEVICE_REQUEST cobd_request +#define DEVICE_OFF(d) /* do-nothing */ + +#include +#include +#include +#include + +#include + +#define PBD_BLOCK_SIZE 512 + +static int *cobd_sizes; +static int *cobd_blksizes; +static int *cobd_hardsects; +static int cobd_devs; +static int cobd_rahead = 1; + +struct cobd_device_aliases_minor { + int cobd_minor; +}; + +struct cobd_device_aliases_major { + int sizes[0x100]; + int blksizes[0x100]; + int cobd_hardsects[0x100]; + struct cobd_device_aliases_minor *minors[0x100]; +}; + +static struct cobd_device_aliases_major *alias_majors; + +static int cobd_stat(int dev, co_block_request_t *out_request) +{ + co_block_request_t *request; + unsigned long flags; + long rc = 0; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_DEVICE; + co_passage_page->params[0] = CO_DEVICE_BLOCK; + co_passage_page->params[1] = dev; + request = (co_block_request_t *)&co_passage_page->params[2]; + request->type = CO_BLOCK_STAT; + co_switch_wrapper(); + rc = request->rc; + *out_request = *request; + local_irq_restore(flags); + + return rc; +} + +static int cobd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int err; + int dev; + + dev = MINOR(inode->i_rdev); + + switch(cmd) { + + case BLKGETSIZE: { + unsigned long size; + + /* Return the device size, expressed in sectors */ + if (!arg) + return -EINVAL; /* NULL pointer: not valid */ + + err = !access_ok (VERIFY_WRITE, arg, sizeof(long)); + if (err) + return -EFAULT; + + size = (cobd_sizes[dev]) * (1024 / cobd_hardsects[dev]); + if (copy_to_user((unsigned long *) arg, &size, sizeof (unsigned long))) + return -EFAULT; + + return 0; + } + + case BLKGETSIZE64: { + unsigned long long size; + + /* Return the device size, expressed in sectors */ + if (!arg) + return -EINVAL; /* NULL pointer: not valid */ + + err = !access_ok (VERIFY_WRITE, arg, sizeof(unsigned long long)); + if (err) + return -EFAULT; + + size = cobd_sizes[dev]; + size = size * 1024; + if (copy_to_user((unsigned long long *) arg, &size, sizeof (unsigned long long))) + return -EFAULT; + + return 0; + } + + case BLKRRPART: /* reread partition table: can't do it */ + return -ENOTTY; + + default: + /* + * For ioctls we don't understand, let the block layer + * handle them. + */ + return blk_ioctl(inode->i_rdev, cmd, arg); + } + + return -ENOTTY; /* unknown command */ +} + +static int cobd_open(struct inode *inode, struct file *file) +{ + co_block_request_t *co_request; + co_block_request_t stat_request; + unsigned long flags; + int ret = 0; + int dev = MINOR(inode->i_rdev); + + if (dev >= cobd_devs) + return -EIO; + + if (!cobd_stat(dev, &stat_request)) { + unsigned long long size; + + /* Request succeeded */ + size = stat_request.disk_size; + cobd_sizes[dev] = size / 1024; + } else { + cobd_sizes[dev] = 0; + } + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_DEVICE; + co_passage_page->params[0] = CO_DEVICE_BLOCK; + co_passage_page->params[1] = DEVICE_NR(inode->i_rdev); + co_request = (co_block_request_t *)&co_passage_page->params[2]; + co_request->type = CO_BLOCK_OPEN; + co_switch_wrapper(); + if (co_request->rc) + ret = -EIO; + local_irq_restore(flags); + + return ret; +} + +static int cobd_release(struct inode *inode, struct file *file) +{ + co_block_request_t *co_request; + unsigned long flags; + int ret = 0; + local_irq_save(flags); + + co_passage_page->operation = CO_OPERATION_DEVICE; + co_passage_page->params[0] = CO_DEVICE_BLOCK; + co_passage_page->params[1] = DEVICE_NR(inode->i_rdev); + co_request = (co_block_request_t *)&co_passage_page->params[2]; + co_request->type = CO_BLOCK_CLOSE; + co_switch_wrapper(); + if (co_request->rc) + ret = -EIO; + local_irq_restore(flags); + + return ret; +} + +static int cobd_transfer(int dev, const struct request *req) +{ + co_block_request_t *co_request; + unsigned long flags; + int ret = 0; + + local_irq_save(flags); + + co_passage_page->operation = CO_OPERATION_DEVICE; + co_passage_page->params[0] = CO_DEVICE_BLOCK; + co_passage_page->params[1] = dev; + co_request = (co_block_request_t *)&co_passage_page->params[2]; + if (req->cmd == READ) + co_request->type = CO_BLOCK_READ; + else + co_request->type = CO_BLOCK_WRITE; + co_request->offset = ((unsigned long long)req->sector) * PBD_BLOCK_SIZE; + co_request->size = req->current_nr_sectors * PBD_BLOCK_SIZE; + co_request->address = req->buffer; + co_request->rc = 0; + + co_switch_wrapper(); + + if (!co_request->rc) + ret = 1; + + local_irq_restore(flags); + + return ret; +} + +static void cobd_request(request_queue_t *q) +{ + int status; + int devno; + + while (1) { + INIT_REQUEST; /* returns when queue is empty */ + + devno = DEVICE_NR(CURRENT->rq_dev); + + status = cobd_transfer(devno, CURRENT); + + end_request(status); + } +} + +static int cobd_check_change(kdev_t dev) +{ + return 1; +} + +static struct block_device_operations cobd_fops = { + owner: THIS_MODULE, + open: cobd_open, + release: cobd_release, + ioctl: cobd_ioctl, + check_media_change: cobd_check_change, +}; + +int __init cobd_init(void) +{ + int result; + int i; + + if (devfs_register_blkdev(MAJOR_NR, "cobd", &cobd_fops)) { + printk(KERN_WARNING "Unable to get major number %d for cobd device\n", MAJOR_NR); + return -EIO; + } + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), cobd_request); + + read_ahead[MAJOR_NR] = cobd_rahead; + result = -ENOMEM; /* for the possible errors */ + + cobd_devs = CO_MODULE_MAX_COBD; + + cobd_sizes = kmalloc(cobd_devs * sizeof(int), GFP_KERNEL); + if (!cobd_sizes) + goto fail_malloc; + + cobd_blksizes = kmalloc(cobd_devs * sizeof(int), GFP_KERNEL); + if (!cobd_blksizes) + goto fail_malloc_1; + + cobd_hardsects = kmalloc(cobd_devs * sizeof(int), GFP_KERNEL); + if (!cobd_hardsects) + goto fail_malloc_2; + + for (i=0; i < cobd_devs; i++) { + co_block_request_t request; + unsigned long long size = 0; + + if (!cobd_stat(i, &request)) { + /* Request successed */ + size = request.disk_size; + cobd_sizes[i] = size >> 10; + } else { + cobd_sizes[i] = 0; + } + + if (cobd_sizes[i] != 0) + printk(KERN_DEBUG "cobd%d size: %d kb\n", i, cobd_sizes[i]); + + cobd_blksizes[i] = PAGE_SIZE; + cobd_hardsects[i] = PBD_BLOCK_SIZE; + } + + blk_size[MAJOR_NR] = cobd_sizes; + blksize_size[MAJOR_NR] = cobd_blksizes; + hardsect_size[MAJOR_NR] = cobd_hardsects; + + devfs_register_series(NULL, "cobd%u", cobd_devs, DEVFS_FL_DEFAULT, + MAJOR_NR, 0, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &cobd_fops, NULL); + + printk(KERN_DEBUG "cobd: loaded (max %d devices)\n", cobd_devs); + + return 0; + +fail_malloc_2: + kfree(cobd_blksizes); +fail_malloc_1: + kfree(cobd_sizes); +fail_malloc: + + if (devfs_unregister_blkdev(MAJOR_NR, "cobd")) + printk(KERN_WARNING "loop: cannot unregister blkdev\n"); + + return result; +} + +void cobd_exit(void) +{ + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + + if (devfs_unregister_blkdev(MAJOR_NR, "cobd")) + printk(KERN_WARNING "cobd: cannot unregister blkdev\n"); + + kfree(blk_size[MAJOR_NR]); + kfree(blksize_size[MAJOR_NR]); + kfree(hardsect_size[MAJOR_NR]); +} + +module_init(cobd_init); +module_exit(cobd_exit); + + --- linux-2.4.28/drivers/block/ll_rw_blk.c~colinux-0.6.1 2004-11-17 06:54:21.000000000 -0500 +++ linux-2.4.28/drivers/block/ll_rw_blk.c 2004-11-27 15:59:21.298008232 -0500 @@ -1576,7 +1576,7 @@ #ifdef CONFIG_BLK_DEV_FD floppy_init(); #else -#if defined(__i386__) /* Do we even need this? */ +#if defined(__i386__) && !defined(CONFIG_COOPERATIVE) /* Do we even need this? */ outb_p(0xc, 0x3f2); #endif #endif --- linux-2.4.28/drivers/char/Makefile~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/drivers/char/Makefile 2004-11-27 15:59:21.298008232 -0500 @@ -169,6 +169,10 @@ KEYBD = dummy_keyb.o endif +ifeq ($(CONFIG_COOPERATIVE),y) + KEYBD = colx_keyb.o +endif + obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) obj-$(CONFIG_PARPORT_SERIAL) += parport_serial.o --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/drivers/char/colx_keyb.c 2004-11-27 15:59:21.299008080 -0500 @@ -0,0 +1,1228 @@ +/* + * linux/drivers/char/pc_keyb.c + * + * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 + * See keyboard.c for the whole history. + * + * Major cleanup by Martin Mares, May 1997 + * + * Combined the keyboard and PS/2 mouse handling into one file, + * because they share the same hardware. + * Johan Myreen 1998-10-08. + * + * Code fixes to handle mouse ACKs properly. + * C. Scott Ananian 1999-01-29. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* Some configuration switches are present in the include file... */ + +#include + +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char pckbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +static void kbd_write_command_w(int data); +static void kbd_write_output_w(int data); +#ifdef CONFIG_PSMOUSE +static void aux_write_ack(int val); +static void __aux_write_ack(int val); +static int aux_reconnect = 0; +#endif + +#ifndef kbd_controller_present +#define kbd_controller_present() 1 +#endif +static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); + +/* used only by send_data - set by keyboard_interrupt */ +static volatile unsigned char reply_expected; +static volatile unsigned char acknowledge; +static volatile unsigned char resend; + + +#if defined CONFIG_PSMOUSE +/* + * PS/2 Auxiliary Device + */ + +static int __init psaux_init(void); + +#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */ +#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */ + +static struct aux_queue *queue; /* Mouse data buffer. */ +static int aux_count; +/* used when we send commands to the mouse that expect an ACK. */ +static unsigned char mouse_reply_expected; + +#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) +#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) + +#define MAX_RETRIES 60 /* some aux operations take long time*/ +#endif /* CONFIG_PSMOUSE */ + +/* + * Wait for keyboard controller input buffer to drain. + * + * Don't use 'jiffies' so that we don't depend on + * interrupts.. + * + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be written only when + * the input-buffer-full bit and output-buffer-full bit in the + * Controller Status register are set 0." + */ + +static void kb_wait(void) +{ + unsigned long timeout = KBC_TIMEOUT; + + do { + /* + * "handle_kbd_event()" will handle any incoming events + * while we wait - keypresses or mouse movement. + */ + unsigned char status = handle_kbd_event(); + + if (! (status & KBD_STAT_IBF)) + return; + mdelay(1); + timeout--; + } while (timeout); +#ifdef KBD_REPORT_TIMEOUTS + printk(KERN_WARNING "Keyboard timed out[1]\n"); +#endif +} + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable. + * The keycodes 1-88,96-111,119 are fairly standard, and + * should probably not be changed - changing might confuse X. + * X also interprets scancode 0x5d (KEY_Begin). + * + * For 1-88 keycode equals scancode. + */ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +#define E1_PAUSE 119 + +/* + * The keycodes below are randomly located in 89-95,112-118,120-127. + * They could be thrown away (and all occurrences below replaced by 0), + * but that would force many users to use the `setkeycodes' utility, where + * they needed not before. It does not matter that there are duplicates, as + * long as no duplication occurs for any single keyboard. + */ +#define SC_LIM 89 + +#define FOCUS_PF1 85 /* actual code! */ +#define FOCUS_PF2 89 +#define FOCUS_PF3 90 +#define FOCUS_PF4 91 +#define FOCUS_PF5 92 +#define FOCUS_PF6 93 +#define FOCUS_PF7 94 +#define FOCUS_PF8 95 +#define FOCUS_PF9 120 +#define FOCUS_PF10 121 +#define FOCUS_PF11 122 +#define FOCUS_PF12 123 + +#define JAP_86 124 +/* tfj@olivia.ping.dk: + * The four keys are located over the numeric keypad, and are + * labelled A1-A4. It's an rc930 keyboard, from + * Regnecentralen/RC International, Now ICL. + * Scancodes: 59, 5a, 5b, 5c. + */ +#define RGN1 124 +#define RGN2 125 +#define RGN3 126 +#define RGN4 127 + +static unsigned char high_keys[128 - SC_LIM] = { + RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ + 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ + FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ + FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ +}; + +/* BTC */ +#define E0_MACRO 112 +/* LK450 */ +#define E0_F13 113 +#define E0_F14 114 +#define E0_HELP 115 +#define E0_DO 116 +#define E0_F17 117 +#define E0_KPMINPLUS 118 +/* + * My OmniKey generates e0 4c for the "OMNI" key and the + * right alt key does nada. [kkoller@nyx10.cs.du.edu] + */ +#define E0_OK 124 +/* + * New microsoft keyboard is rumoured to have + * e0 5b (left window button), e0 5c (right window button), + * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] + * [or: Windows_L, Windows_R, TaskMan] + */ +#define E0_MSLW 125 +#define E0_MSRW 126 +#define E0_MSTM 127 + +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ + E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ + E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode < SC_LIM || scancode > 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +int pckbd_getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < 128) ? high_keys[scancode - SC_LIM] : + e0_keys[scancode - 128]; +} + +static int do_acknowledge(unsigned char scancode) +{ + if (reply_expected) { + /* Unfortunately, we must recognise these codes only if we know they + * are known to be valid (i.e., after sending a command), because there + * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have + * keys with such codes :( + */ + if (scancode == KBD_REPLY_ACK) { + acknowledge = 1; + reply_expected = 0; + return 0; + } else if (scancode == KBD_REPLY_RESEND) { + resend = 1; + reply_expected = 0; + return 0; + } + /* Should not happen... */ +#if 0 + printk(KERN_DEBUG "keyboard reply expected - got %02x\n", + scancode); +#endif + } + return 1; +} + +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + /* + * The keyboard maintains its own internal caps lock and + * num lock statuses. In caps lock mode E0 AA precedes make + * code and E0 2A follows break code. In num lock mode, + * E0 2A precedes make code and E0 AA follows break code. + * We do our own book-keeping, so we will just ignore these. + */ + /* + * For my keyboard there is no caps lock mode, but there are + * both Shift-L and Shift-R modes. The former mode generates + * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. + * So, we should also ignore the latter. - aeb@cwi.nl + */ + if (scancode == 0x2a || scancode == 0x36) + return 0; + + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); +#endif + return 0; + } + } + } else if (scancode >= SC_LIM) { + /* This happens with the FOCUS 9000 keyboard + Its keys PF1..PF12 are reported to generate + 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f + Moreover, unless repeated, they do not generate + key-down events, so we have to zero up_flag below */ + /* Also, Japanese 86/106 keyboards are reported to + generate 0x73 and 0x7d for \ - and \ | respectively. */ + /* Also, some Brazilian keyboard is reported to produce + 0x73 and 0x7e for \ ? and KP-dot, respectively. */ + + *keycode = high_keys[scancode - SC_LIM]; + + if (!*keycode) { + if (!raw_mode) { +#ifdef KBD_REPORT_UNKN + printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" + " - ignored\n", scancode); +#endif + } + return 0; + } + } else + *keycode = scancode; + return 1; +} + +char pckbd_unexpected_up(unsigned char keycode) +{ + /* unexpected, but this can happen: maybe this was a key release for a + FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ + if (keycode >= SC_LIM || keycode == 85) + return 0; + else + return 0200; +} + +int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) +{ +#if defined CONFIG_PSMOUSE + unsigned long flags; + + if (rqst == PM_RESUME) { + if (queue) { /* Aux port detected */ + if (aux_count == 0) { /* Mouse not in use */ + spin_lock_irqsave(&kbd_controller_lock, flags); + /* + * Dell Lat. C600 A06 enables mouse after resume. + * When user touches the pad, it posts IRQ 12 + * (which we do not process), thus holding keyboard. + */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); + /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MODE); + kb_wait(); + kbd_write_output(AUX_INTS_OFF); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + } + } + } +#endif + return 0; +} + + +static inline void handle_mouse_event(unsigned char scancode) +{ +#ifdef CONFIG_PSMOUSE + static unsigned char prev_code; + if (mouse_reply_expected) { + if (scancode == AUX_ACK) { + mouse_reply_expected--; + return; + } + mouse_reply_expected = 0; + } + else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1 + && aux_reconnect) { + printk (KERN_INFO "PS/2 mouse reconnect detected\n"); + queue->head = queue->tail = 0; /* Flush input queue */ + __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ + return; + } + + prev_code = scancode; + add_mouse_randomness(scancode); + if (aux_count) { + int head = queue->head; + + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } + } +#endif +} + +static unsigned char kbd_exists = 1; + +void handle_keyboard_event(unsigned char scancode) +{ +#ifdef CONFIG_VT + kbd_exists = 1; + if (do_acknowledge(scancode)) + handle_scancode(scancode, !(scancode & 0x80)); +#endif + tasklet_schedule(&keyboard_tasklet); +} + +/* + * This reads the keyboard status port, and does the + * appropriate action. + * + * It requires that we hold the keyboard controller + * spinlock. + */ +static unsigned char handle_kbd_event(void) +{ + unsigned char scancode; + co_linux_message_t *message; + + while (co_get_message(&message, CO_DEVICE_KEYBOARD)) { + co_scan_code_t *sc = (co_scan_code_t *)message->data; + unsigned long scancode = sc->code; + + if (!sc->down) + scancode |= 0x80; + + handle_keyboard_event(scancode); + + co_free_message(message); + } + + return 0; +} + + +static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ +#ifdef CONFIG_VT + kbd_pt_regs = regs; +#endif + + spin_lock_irq(&kbd_controller_lock); + handle_kbd_event(); + spin_unlock_irq(&kbd_controller_lock); +} + +/* + * send_data sends a character to the keyboard and waits + * for an acknowledge, possibly retrying if asked to. Returns + * the success status. + * + * Don't use 'jiffies', so that we don't depend on interrupts + */ +static int send_data(unsigned char data) +{ + return 0; +} + +void pckbd_leds(unsigned char leds) +{ + if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { + send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ + kbd_exists = 0; + } +} + +#define DEFAULT_KEYB_REP_DELAY 250 +#define DEFAULT_KEYB_REP_RATE 30 /* cps */ + +static struct kbd_repeat kbdrate={ + DEFAULT_KEYB_REP_DELAY, + DEFAULT_KEYB_REP_RATE +}; + +static unsigned char parse_kbd_rate(struct kbd_repeat *r) +{ + static struct r2v{ + int rate; + unsigned char val; + } kbd_rates[]={ {5,0x14}, + {7,0x10}, + {10,0x0c}, + {15,0x08}, + {20,0x04}, + {25,0x02}, + {30,0x00} + }; + static struct d2v{ + int delay; + unsigned char val; + } kbd_delays[]={{250,0}, + {500,1}, + {750,2}, + {1000,3} + }; + int rate=0,delay=0; + if (r != NULL){ + int i,new_rate=30,new_delay=250; + if (r->rate <= 0) + r->rate=kbdrate.rate; + if (r->delay <= 0) + r->delay=kbdrate.delay; + for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++) + if (kbd_rates[i].rate == r->rate){ + new_rate=kbd_rates[i].rate; + rate=kbd_rates[i].val; + break; + } + for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++) + if (kbd_delays[i].delay == r->delay){ + new_delay=kbd_delays[i].delay; + delay=kbd_delays[i].val; + break; + } + r->rate=new_rate; + r->delay=new_delay; + } + return (delay << 5) | rate; +} + +static int write_kbd_rate(unsigned char r) +{ + if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){ + send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ + return 0; + }else + return 1; +} + +static int pckbd_rate(struct kbd_repeat *rep) +{ + if (rep == NULL) + return -EINVAL; + else{ + unsigned char r=parse_kbd_rate(rep); + struct kbd_repeat old_rep; + memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat)); + if (write_kbd_rate(r)){ + memcpy(&kbdrate,rep,sizeof(struct kbd_repeat)); + memcpy(rep,&old_rep,sizeof(struct kbd_repeat)); + return 0; + } + } + return -EIO; +} + +/* + * In case we run on a non-x86 hardware we need to initialize both the + * keyboard controller and the keyboard. On a x86, the BIOS will + * already have initialized them. + * + * Some x86 BIOSes do not correctly initialize the keyboard, so the + * "kbd-reset" command line options can be given to force a reset. + * [Ranger] + */ +#ifdef __i386__ + int kbd_startup_reset __initdata = 0; +#else + int kbd_startup_reset __initdata = 1; +#endif + +/* for "kbd-reset" cmdline param */ +static int __init kbd_reset_setup(char *str) +{ + kbd_startup_reset = 1; + return 1; +} + +__setup("kbd-reset", kbd_reset_setup); + +#define KBD_NO_DATA (-1) /* No data */ +#define KBD_BAD_DATA (-2) /* Parity or other error */ + +static int __init kbd_read_data(void) +{ + int retval = KBD_NO_DATA; + +#if (0) + status = kbd_read_status(); + if (status & KBD_STAT_OBF) { + unsigned char data = kbd_read_input(); + + retval = data; + if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) + retval = KBD_BAD_DATA; + } +#endif + return retval; +} + +static void __init kbd_clear_input(void) +{ + int maxread = 100; /* Random number */ + + do { + if (kbd_read_data() == KBD_NO_DATA) + break; + } while (--maxread); +} + +static int __init kbd_wait_for_input(void) +{ + long timeout = KBD_INIT_TIMEOUT; + + do { + int retval = kbd_read_data(); + if (retval >= 0) + return retval; + mdelay(1); + } while (--timeout); + return -1; +} + +static void kbd_write_command_w(int data) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_command(data); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static void kbd_write_output_w(int data) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_output(data); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +#if defined(__alpha__) +/* + * Some Alphas cannot mask some/all interrupts, so we have to + * make sure not to allow interrupts AT ALL when polling for + * specific return values from the keyboard. + * + * I think this should work on any architecture, but for now, only Alpha. + */ +static int kbd_write_command_w_and_wait(int data) +{ + unsigned long flags; + int input; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_command(data); + input = kbd_wait_for_input(); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + return input; +} + +static int kbd_write_output_w_and_wait(int data) +{ + unsigned long flags; + int input; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_output(data); + input = kbd_wait_for_input(); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + return input; +} +#else +static int kbd_write_command_w_and_wait(int data) +{ + kbd_write_command_w(data); + return kbd_wait_for_input(); +} + +static int kbd_write_output_w_and_wait(int data) +{ + kbd_write_output_w(data); + return kbd_wait_for_input(); +} +#endif /* __alpha__ */ + +#if defined CONFIG_PSMOUSE +static void kbd_write_cmd(int cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MODE); + kb_wait(); + kbd_write_output(cmd); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} +#endif /* CONFIG_PSMOUSE */ + +static char * __init initialize_kbd(void) +{ + int status; + + /* + * Test the keyboard interface. + * This seems to be the only way to get it going. + * If the test is successful a x55 is placed in the input buffer. + */ + kbd_write_command_w(KBD_CCMD_SELF_TEST); + if (kbd_wait_for_input() != 0x55) + return "Keyboard failed self test"; + + /* + * Perform a keyboard interface test. This causes the controller + * to test the keyboard clock and data lines. The results of the + * test are placed in the input buffer. + */ + kbd_write_command_w(KBD_CCMD_KBD_TEST); + if (kbd_wait_for_input() != 0x00) + return "Keyboard interface failed self test"; + + /* + * Enable the keyboard by allowing the keyboard clock to run. + */ + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); + + /* + * Reset keyboard. If the read times out + * then the assumption is that no keyboard is + * plugged into the machine. + * This defaults the keyboard to scan-code set 2. + * + * Set up to try again if the keyboard asks for RESEND. + */ + do { + kbd_write_output_w(KBD_CMD_RESET); + status = kbd_wait_for_input(); + if (status == KBD_REPLY_ACK) + break; + if (status != KBD_REPLY_RESEND) + return "Keyboard reset failed, no ACK"; + } while (1); + + if (kbd_wait_for_input() != KBD_REPLY_POR) + return "Keyboard reset failed, no POR"; + + /* + * Set keyboard controller mode. During this, the keyboard should be + * in the disabled state. + * + * Set up to try again if the keyboard asks for RESEND. + */ + do { + kbd_write_output_w(KBD_CMD_DISABLE); + status = kbd_wait_for_input(); + if (status == KBD_REPLY_ACK) + break; + if (status != KBD_REPLY_RESEND) + return "Disable keyboard: no ACK"; + } while (1); + + kbd_write_command_w(KBD_CCMD_WRITE_MODE); + kbd_write_output_w(KBD_MODE_KBD_INT + | KBD_MODE_SYS + | KBD_MODE_DISABLE_MOUSE + | KBD_MODE_KCC); + + /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ + if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC)) + { + /* + * If the controller does not support conversion, + * Set the keyboard to scan-code set 1. + */ + kbd_write_output_w(0xF0); + kbd_wait_for_input(); + kbd_write_output_w(0x01); + kbd_wait_for_input(); + } + + if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK) + return "Enable keyboard: no ACK"; + + /* + * Finally, set the typematic rate to maximum. + */ + if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK) + return "Set rate: no ACK"; + if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK) + return "Set rate: no 2nd ACK"; + + return NULL; +} + +void __init pckbd_init_hw(void) +{ + if (!kbd_controller_present()) { + kbd_exists = 0; + return; + } + + kbd_request_region(); + + /* Flush any pending input. */ + kbd_clear_input(); + + if (kbd_startup_reset) { + char *msg = initialize_kbd(); + if (msg) + printk(KERN_WARNING "initialize_kbd: %s\n", msg); + } + +#if defined CONFIG_PSMOUSE + psaux_init(); +#endif + + kbd_rate = pckbd_rate; + + /* Ok, finally allocate the IRQ, and off we go.. */ + kbd_request_irq(keyboard_interrupt); +} + +#if defined CONFIG_PSMOUSE + +static int __init aux_reconnect_setup (char *str) +{ + aux_reconnect = 1; + return 1; +} + +__setup("psaux-reconnect", aux_reconnect_setup); + +/* + * Check if this is a dual port controller. + */ +static int __init detect_auxiliary_port(void) +{ + unsigned long flags; + int loops = 10; + int retval = 0; + + /* Check if the BIOS detected a device on the auxiliary port. */ + if (aux_device_present == 0xaa) + return 1; + + spin_lock_irqsave(&kbd_controller_lock, flags); + + /* Put the value 0x5A in the output buffer using the "Write + * Auxiliary Device Output Buffer" command (0xD3). Poll the + * Status Register for a while to see if the value really + * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF + * bit is also set to 1 in the Status Register, we assume this + * controller has an Auxiliary Port (a.k.a. Mouse Port). + */ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); + + kb_wait(); + kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ + + do { + unsigned char status = kbd_read_status(); + + if (status & KBD_STAT_OBF) { + (void) kbd_read_input(); + if (status & KBD_STAT_MOUSE_OBF) { + printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); + retval = 1; + } + break; + } + mdelay(1); + } while (--loops); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + + return retval; +} + +/* + * Send a byte to the mouse. + */ +static void aux_write_dev(int val) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); + kb_wait(); + kbd_write_output(val); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +/* + * Send a byte to the mouse & handle returned ack + */ +static void __aux_write_ack(int val) +{ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); + kb_wait(); + kbd_write_output(val); + /* we expect an ACK in response. */ + mouse_reply_expected++; + kb_wait(); +} + +static void aux_write_ack(int val) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + __aux_write_ack(val); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static unsigned char get_from_queue(void) +{ + unsigned char result; + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + return result; +} + + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int fasync_aux(int fd, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + + +/* + * Random magic cookie for the aux device + */ +#define AUX_DEV ((void *)queue) + +static int release_aux(struct inode * inode, struct file * file) +{ + lock_kernel(); + fasync_aux(-1, file, 0); + if (--aux_count) { + unlock_kernel(); + return 0; + } + kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + aux_free_irq(AUX_DEV); + unlock_kernel(); + return 0; +} + +/* + * Install interrupt handler. + * Enable auxiliary device. + */ + +static int open_aux(struct inode * inode, struct file * file) +{ + if (aux_count++) { + return 0; + } + queue->head = queue->tail = 0; /* Flush input queue */ + if (aux_request_irq(keyboard_interrupt, AUX_DEV)) { + aux_count--; + return -EBUSY; + } + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the + auxiliary port on + controller. */ + aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ + + mdelay(2); /* Ensure we follow the kbc access delay rules.. */ + + send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ + + return 0; +} + +/* + * Put bytes from input queue to buffer. + */ + +static ssize_t read_aux(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_user(c, buffer++); + i--; + } + if (count-i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* + * Write to the aux device. + */ + +static ssize_t write_aux(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + ssize_t retval = 0; + + if (count) { + ssize_t written = 0; + + if (count > 32) + count = 32; /* Limit to 32 bytes. */ + do { + char c; + get_user(c, buffer++); + aux_write_dev(c); + written++; + } while (--count); + retval = -EIO; + if (written) { + retval = written; + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + } + } + + return retval; +} + +/* No kernel lock held - fine */ +static unsigned int aux_poll(struct file *file, poll_table * wait) +{ + poll_wait(file, &queue->proc_list, wait); + if (!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations psaux_fops = { + read: read_aux, + write: write_aux, + poll: aux_poll, + open: open_aux, + release: release_aux, + fasync: fasync_aux, +}; + +/* + * Initialize driver. + */ +static struct miscdevice psaux_mouse = { + PSMOUSE_MINOR, "psaux", &psaux_fops +}; + +static int __init psaux_init(void) +{ + int retval; + + if (!detect_auxiliary_port()) + return -EIO; + + if ((retval = misc_register(&psaux_mouse))) + return retval; + + queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (queue == NULL) { + printk(KERN_ERR "psaux_init(): out of memory\n"); + misc_deregister(&psaux_mouse); + return -ENOMEM; + } + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + +#ifdef INITIALIZE_MOUSE + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ + aux_write_ack(AUX_SET_SAMPLE); + aux_write_ack(100); /* 100 samples/sec */ + aux_write_ack(AUX_SET_RES); + aux_write_ack(3); /* 8 counts per mm */ + aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ +#endif /* INITIALIZE_MOUSE */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ + kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ + + return 0; +} + +#endif /* CONFIG_PSMOUSE */ + + +static int blink_frequency = HZ/2; + +/* Tell the user who may be running in X and not see the console that we have + panic'ed. This is to distingush panics from "real" lockups. + Could in theory send the panic message as morse, but that is left as an + exercise for the reader. */ +void panic_blink(void) +{ + static unsigned long last_jiffie; + static char led; + /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is + different. */ + if (!blink_frequency) + return; + if (jiffies - last_jiffie > blink_frequency) { + led ^= 0x01 | 0x04; + while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); + kbd_write_output(KBD_CMD_SET_LEDS); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); + mdelay(1); + kbd_write_output(led); + last_jiffie = jiffies; + } +} + +static int __init panicblink_setup(char *str) +{ + int par; + if (get_option(&str,&par)) + blink_frequency = par*(1000/HZ); + return 1; +} + +/* panicblink=0 disables the blinking as it caused problems with some console + switches. otherwise argument is ms of a blink period. */ +__setup("panicblink=", panicblink_setup); + --- linux-2.4.28/drivers/char/mem.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/drivers/char/mem.c 2004-11-27 15:59:21.304007320 -0500 @@ -667,20 +667,24 @@ static int memory_open(struct inode * inode, struct file * filp) { switch (MINOR(inode->i_rdev)) { +#ifndef CONFIG_COOPERATIVE case 1: filp->f_op = &mem_fops; break; case 2: filp->f_op = &kmem_fops; break; +#endif case 3: filp->f_op = &null_fops; break; +#ifndef CONFIG_COOPERATIVE #if defined(CONFIG_ISA) || !defined(__mc68000__) case 4: filp->f_op = &port_fops; break; #endif +#endif case 5: filp->f_op = &zero_fops; break; @@ -710,12 +714,16 @@ umode_t mode; struct file_operations *fops; } list[] = { /* list of minor devices */ +#ifndef CONFIG_COOPERATIVE {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, +#endif {3, "null", S_IRUGO | S_IWUGO, &null_fops}, +#ifndef CONFIG_COOPERATIVE #if defined(CONFIG_ISA) || !defined(__mc68000__) {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, #endif +#endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, {7, "full", S_IRUGO | S_IWUGO, &full_fops}, {8, "random", S_IRUGO | S_IWUSR, &random_fops}, --- linux-2.4.28/drivers/char/vt.c~colinux-0.6.1 2002-11-28 18:53:12.000000000 -0500 +++ linux-2.4.28/drivers/char/vt.c 2004-11-27 15:59:21.305007168 -0500 @@ -90,10 +90,10 @@ * comments - KDMKTONE doesn't put the process to sleep. */ -#if defined(__i386__) || defined(__alpha__) || defined(CONFIG_PPC_ISATIMER) \ - || (defined(__mips__) && defined(CONFIG_ISA)) \ - || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ - || defined(__x86_64__) +#if (defined(__i386__) || defined(__alpha__) || defined(CONFIG_PPC_ISATIMER) \ + || (defined(__mips__) && defined(CONFIG_ISA)) \ + || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ + || defined(__x86_64__)) && !defined(CONFIG_COOPERATIVE) static void kd_nosound(unsigned long ignored) --- linux-2.4.28/drivers/net/Config.in~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/drivers/net/Config.in 2004-11-27 15:59:21.306007016 -0500 @@ -287,6 +287,10 @@ dep_tristate 'iSeries Virtual Ethernet driver support' CONFIG_VETH $CONFIG_PPC_ISERIES fi +if [ "$CONFIG_COOPERATIVE" = "y" ]; then + tristate 'Coooperative Virtual Ethernet driver support' CONFIG_COOPERATIVE_CONET +fi + if [ "$CONFIG_4xx" = "y" ]; then source drivers/net/ibm_emac/Config.in fi --- linux-2.4.28/drivers/net/Makefile~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 +++ linux-2.4.28/drivers/net/Makefile 2004-11-27 15:59:21.306007016 -0500 @@ -212,6 +212,7 @@ # This is also a 82596 and should probably be merged obj-$(CONFIG_LP486E) += lp486e.o +obj-$(CONFIG_COOPERATIVE_CONET) += conet.o obj-$(CONFIG_ETH16I) += eth16i.o obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/drivers/net/conet.c 2004-11-27 15:59:21.307006864 -0500 @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2003-2004 Dan Aloni + * Copyright (C) 2004 Pat Erley + * Copyright (C) 2004 George Boutwell + * + * Cooperative Linux Network Device implementation + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +struct conet_priv { + struct net_device_stats stats; + co_linux_message_t *message; + int status; + int unit; + int enabled; +}; + +struct net_device *conet_dev[CO_MODULE_MAX_CONET]; + +void conet_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr); + +static int conet_get_mac(int unit, char *address) +{ + unsigned long flags = 0; + co_network_request_t *net_request; + int result = 0; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_DEVICE; + co_passage_page->params[0] = CO_DEVICE_NETWORK; + net_request = (typeof(net_request))&co_passage_page->params[1]; + net_request->unit = unit; + net_request->type = CO_NETWORK_GET_MAC; + co_switch_wrapper(); + memcpy(address, net_request->mac_address, ETH_ALEN); + result = net_request->result; + local_irq_restore(flags); + + return result; +} + +int conet_open(struct net_device *dev) +{ + struct conet_priv *priv = (struct conet_priv *)dev->priv; + + if (priv->enabled) + return 0; + + MOD_INC_USE_COUNT; + + conet_get_mac(priv->unit, dev->dev_addr); + + priv->enabled = 1; + + netif_start_queue(dev); + + return 0; +} + +int conet_stop(struct net_device *dev) +{ + struct conet_priv *priv = (struct conet_priv *)dev->priv; + + priv->enabled = 0; + + netif_stop_queue(dev); /* can't transmit any more */ + + MOD_DEC_USE_COUNT; + + return 0; +} + +int conet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int len; + char *data; + struct conet_priv *priv = (struct conet_priv *)dev->priv; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + data = skb->data; + + dev->trans_start = jiffies; /* save the timestamp */ + + co_send_message(CO_MODULE_LINUX, + CO_MODULE_CONET0 + priv->unit, + CO_PRIORITY_DISCARDABLE, + CO_MESSAGE_TYPE_OTHER, + len, + data); + + priv->stats.tx_bytes+=skb->len; + priv->stats.tx_packets++; + + dev_kfree_skb(skb); + + return 0; +} + +void conet_rx(struct net_device *dev) +{ + struct sk_buff *skb; + struct conet_priv *priv = (struct conet_priv *)dev->priv; + int len; + unsigned char *buf; + co_linux_message_t *message; + + message = priv->message; + if (message == NULL) { + printk("conet rx: no message\n"); + return; + } + + priv->message = NULL; + + len = message->size; + buf = message->data; + + /* + * The packet has been retrieved from the transmission + * medium. Build an skb around it, so upper layers can handle it + */ + skb = dev_alloc_skb(len+2); + if (!skb) { + printk("conet rx: low on mem - packet dropped\n"); + priv->stats.rx_dropped++; + co_free_message(message); + return; + } + + memcpy(skb_put(skb, len), buf, len); + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + priv->stats.rx_bytes += len; + priv->stats.rx_packets++; + + netif_rx(skb); + + co_free_message(message); + return; +} + +void conet_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +{ + co_linux_message_t *message; + + while (co_get_message(&message, CO_DEVICE_NETWORK)) { + struct net_device *dev; + struct conet_priv *priv; + + if (message->unit < 0 || message->unit >= CO_MODULE_MAX_CONET) { + printk("conet intrrupt: buggy network reception\n"); + return; + } + + dev = conet_dev[message->unit]; + if (!netif_running(dev)) { + co_free_message(message); + continue; + } + + priv = (struct conet_priv *)dev->priv; + if (priv->message != NULL) { + printk("conet intrrupt: freeing unhandled packet\n"); + co_free_message(message); + continue; + } + + priv->message = message; + conet_rx(dev); + } +} + +struct net_device_stats* conet_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +int conet_init(struct net_device *dev) +{ + struct conet_priv *priv = (struct conet_priv *)dev->priv; + + memset(&priv->stats, 0, sizeof(priv->stats)); + + ether_setup(dev); + + dev->open = conet_open; + dev->stop = conet_stop; + dev->hard_start_xmit = conet_hard_start_xmit; + dev->get_stats = conet_get_stats; + dev->irq = NETWORK_IRQ; + + SET_MODULE_OWNER(dev); + + return 0; +} + +void conet_uninit(struct net_device *dev) +{ +} + +static struct net_device *conet_create(int unit) +{ + struct net_device *dev; + struct conet_priv *priv; + int result = 0; + + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + return ERR_PTR(-ENOMEM); + } + + memset(dev, 0, sizeof(struct net_device)); + + priv = kmalloc(sizeof(struct conet_priv), GFP_KERNEL); + if (priv == NULL) { + kfree(dev); + return ERR_PTR(-ENOMEM); + } + + memset(priv, 0, sizeof(struct conet_priv)); + priv->unit = unit; + + dev->priv = priv; + dev->init = conet_init; + dev->uninit = conet_uninit; + strcpy(dev->name, "eth%d"); + + result = register_netdev(dev); + if (result) { + printk("conet: error %d registering device \"%s\"\n", result, dev->name); + kfree(dev->priv); + kfree(dev); + return ERR_PTR(-ENODEV); + } + + printk("conet%d: initialized\n", priv->unit); + + return dev; +} + +static void conet_destroy(struct net_device *dev) +{ + struct conet_priv *priv = (struct conet_priv *) dev->priv; + + printk("conet%d: freed\n", priv->unit); + + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +static int __init conet_init_module(void) +{ + int unit = 0, result; + struct net_device *dev; + char mac_address[6]; + + result = request_irq(NETWORK_IRQ, &conet_interrupt, 0, "conet", NULL); + + printk("conet: loaded (max %d devices)\n", CO_MODULE_MAX_CONET); + + for (unit=0; unit < CO_MODULE_MAX_CONET; unit++) { + conet_dev[unit] = NULL; + + result = conet_get_mac(unit, mac_address); + if (!result) + continue; + + dev = conet_create(unit); + if (!IS_ERR(dev)) + conet_dev[unit] = dev; + } + + return result; +} + +static void __exit conet_cleanup_module(void) +{ + int unit = 0; + + free_irq(NETWORK_IRQ, NULL); + + for (unit=0; unit < CO_MODULE_MAX_CONET; unit++) { + if (!conet_dev[unit]) + continue; + + conet_destroy(conet_dev[unit]); + } +} + +module_init(conet_init_module); +module_exit(conet_cleanup_module); --- linux-2.4.28/drivers/video/Makefile~colinux-0.6.1 2004-02-18 08:36:31.000000000 -0500 +++ linux-2.4.28/drivers/video/Makefile 2004-11-27 15:59:21.307006864 -0500 @@ -15,7 +15,8 @@ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \ - cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o + cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o cocon.o \ + # Each configuration option enables a list of files. @@ -23,6 +24,7 @@ obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o +obj-$(CONFIG_COOPERATIVE_CONSOLE) += cocon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o obj-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/drivers/video/cocon.c 2004-11-27 15:59:21.308006712 -0500 @@ -0,0 +1,484 @@ +/* + * linux/drivers/video/cocon.c -- Cooperative Linux console VGA driver + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Based on code copied from vgacon.c. + * + * Dan Aloni , 2003-2004 (c) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Interface used by the world + */ + +static const char *cocon_startup(void); +static void cocon_init(struct vc_data *c, int init); +static void cocon_deinit(struct vc_data *c); +static void cocon_clear(struct vc_data *c, int, int, int, int); +static void cocon_cursor(struct vc_data *c, int mode); +static int cocon_switch(struct vc_data *c); +static int cocon_blank(struct vc_data *c, int blank); +static int cocon_font_op(struct vc_data *c, struct console_font_op *op); +static int cocon_set_palette(struct vc_data *c, unsigned char *table); +static int cocon_scrolldelta(struct vc_data *c, int lines); +static int cocon_set_origin(struct vc_data *c); +static void cocon_save_screen(struct vc_data *c); +static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines); +static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse); +static void cocon_invert_region(struct vc_data *c, u16 *p, int count); + +static const char __init *cocon_startup(void) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_STARTUP; + co_send_message_restore(flags); + + return "CoCON"; +} + +static void cocon_init(struct vc_data *c, int init) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + /* We cannot be loaded as a module, therefore init is always 1 */ + c->vc_can_do_color = 1; + c->vc_cols = 80; + c->vc_rows = 25; + c->vc_complement_mask = 0x7700; + c->vc_visible_origin = 0; + c->vc_origin = 0; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_INIT; + co_send_message_restore(flags); +} + +static void cocon_deinit(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_DEINIT; + co_send_message_restore(flags); + +} + +static void cocon_clear(struct vc_data *c, int top, int left, int rows, int cols) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->clear + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_CLEAR; + message->clear.top = top; + message->clear.left = left; + message->clear.bottom = top + rows - 1; + message->clear.right = left + cols - 1; + message->clear.charattr = c->vc_video_erase_char; + co_send_message_restore(flags); +} + +static void cocon_putc(struct vc_data *c, int charattr, int y, int x) +{ + unsigned long flags; + co_message_t *co_message; + co_console_message_t *message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->putc + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_PUTC; + message->putc.x = x; + message->putc.y = y; + message->putc.charattr = charattr; + co_send_message_restore(flags); +} + + +static void cocon_putcs(struct vc_data *conp, + const unsigned short *s, int count, int yy, int xx) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + if (count > CO_MAX_PARAM_SIZE/2 - 16) + return; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->putcs + 1)) - ((char *)message) + + count * sizeof(unsigned short); + message->type = CO_OPERATION_CONSOLE_PUTCS; + message->putcs.x = xx; + message->putcs.y = yy; + message->putcs.count = count; + memcpy(&message->putcs.data, s, count * sizeof(unsigned short)); + co_send_message_restore(flags); +} + +static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse) +{ + u8 attr = color; + + if (underline) + attr = (attr & 0xf0) | c->vc_ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | c->vc_halfcolor; + if (reverse) + attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77); + if (blink) + attr ^= 0x80; + if (intensity == 2) + attr ^= 0x08; + + return attr; +} + +static void cocon_invert_region(struct vc_data *c, u16 *p, int count) +{ + unsigned long flags; + co_message_t *co_message; + co_console_message_t *message; + unsigned x = p - c->vc_origin ; // UPDATE: vc_origin = 0; but not yet + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->invert + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_INVERT_REGION; + message->invert.y = ((unsigned)x)/c->vc_cols; + message->invert.x = ((unsigned)x)-(message->invert.y); + message->invert.count = count; + co_send_message_restore(flags); + + while (count--) { + u16 a = scr_readw(p); + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); + scr_writew(a, p++); + } + +} + +static void cocon_cursor(struct vc_data *c, int mode) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->cursor + 1)) - ((char *)message);; + if (mode==CM_ERASE) { + message->type = CO_OPERATION_CONSOLE_CURSOR_ERASE; + message->cursor.height = 0; + co_send_message_restore(flags); + return; + } + + if(mode==CM_MOVE) { + message->type = CO_OPERATION_CONSOLE_CURSOR_MOVE; + } else /*(mode==CM_DRAW)*/ { + message->type = CO_OPERATION_CONSOLE_CURSOR_DRAW; + } + message->cursor.x = c->vc_x; + message->cursor.y = c->vc_y; + + switch (c->vc_cursor_type & CUR_HWMASK) { + case CUR_UNDERLINE: + message->cursor.height = 5; + break; + case CUR_TWO_THIRDS: + message->cursor.height = 66; + break; + case CUR_LOWER_THIRD: + message->cursor.height = 33; + break; + case CUR_LOWER_HALF: + message->cursor.height = 50; + break; + case CUR_NONE: + message->cursor.height = 0; + break; + default: + message->cursor.height = 5; + break; + } + + co_send_message_restore(flags); +} + +static int cocon_switch(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SWITCH; + co_send_message_restore(flags); + + return 1; /* Redrawing not needed */ +} + +static int cocon_set_palette(struct vc_data *c, unsigned char *table) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SET_PALETTE; + co_send_message_restore(flags); + + return 1; +} + +static int cocon_blank(struct vc_data *c, int blank) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_BLANK; + co_send_message_restore(flags); + + return 1; +} + +static int cocon_font_op(struct vc_data *c, struct console_font_op *op) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_FONT_OP; + co_send_message_restore(flags); + + return 1; +} + +static int cocon_scrolldelta(struct vc_data *c, int lines) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SCROLLDELTA; + co_send_message_restore(flags); + + return 1; +} + +static int cocon_set_origin(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SET_ORIGIN; + co_send_message_restore(flags); + + return 1; +} + +static void cocon_save_screen(struct vc_data *c) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->type + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_SAVE_SCREEN; + co_send_message_restore(flags); +} + +static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->scroll + 1)) - ((char *)message); + if (dir == SM_UP) + message->type = CO_OPERATION_CONSOLE_SCROLL_UP; + else + message->type = CO_OPERATION_CONSOLE_SCROLL_DOWN; + message->scroll.top = t; + message->scroll.bottom = b-1; + message->scroll.lines = lines; + co_send_message_restore(flags); + + return 0; +} + +static void cocon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int h, int w) +{ + unsigned long flags; + co_console_message_t *message; + co_message_t *co_message; + + co_message = co_send_message_save(&flags); + message = (co_console_message_t *)co_message->data; + co_message->from = CO_MODULE_LINUX; + co_message->to = CO_MODULE_CONSOLE; + co_message->priority = CO_PRIORITY_DISCARDABLE; + co_message->type = CO_MESSAGE_TYPE_STRING; + co_message->size = ((char *)(&message->bmove + 1)) - ((char *)message); + message->type = CO_OPERATION_CONSOLE_BMOVE; + message->bmove.row = dy; + message->bmove.column = dx; + message->bmove.top = sy; + message->bmove.left = sx; + message->bmove.bottom = sy + h - 1; + message->bmove.right = sx + w - 1; + co_send_message_restore(flags); +} + +/* + * The console `switch' structure for the VGA based console + */ + +const struct consw colinux_con = { + con_startup: cocon_startup, + con_init: cocon_init, + con_deinit: cocon_deinit, + con_clear: cocon_clear, + con_putc: cocon_putc, + con_putcs: cocon_putcs, + con_cursor: cocon_cursor, + con_scroll: cocon_scroll, + con_bmove: cocon_bmove, + con_switch: cocon_switch, + con_blank: cocon_blank, + con_font_op: cocon_font_op, + con_set_palette: cocon_set_palette, + con_scrolldelta: cocon_scrolldelta, + con_set_origin: cocon_set_origin, + con_save_screen: cocon_save_screen, + con_build_attr: cocon_build_attr, + con_invert_region: cocon_invert_region, +}; + +MODULE_LICENSE("GPL"); --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/include/asm-i386/cooperative.h 2004-11-27 15:59:21.308006712 -0500 @@ -0,0 +1,175 @@ +#ifndef __LINUX_ASM_COOPERATIVE_H__ +#define __LINUX_ASM_COOPERATIVE_H__ + +typedef struct { + unsigned short size; + struct x86_idt_entry *table; +} __attribute__((packed)) x86_idt_t; + +typedef struct { + unsigned short limit; + struct x86_dt_entry *base; +} __attribute__((packed)) x86_gdt_t; + +typedef struct { + unsigned char border2[0x4]; + + unsigned long cs; + #define CO_ARCH_STATE_STACK_CS "0x04" + + unsigned long ds; + #define CO_ARCH_STATE_STACK_DS "0x08" + + unsigned long es; + #define CO_ARCH_STATE_STACK_ES "0x0C" + + unsigned long cr3; + #define CO_ARCH_STATE_STACK_CR3 "0x10" + + unsigned long cr4; + #define CO_ARCH_STATE_STACK_CR4 "0x14" + + unsigned long cr2; + #define CO_ARCH_STATE_STACK_CR2 "0x18" + + unsigned long cr0; + #define CO_ARCH_STATE_STACK_CR0 "0x1C" + + x86_gdt_t gdt; + #define CO_ARCH_STATE_STACK_GDT "0x20" + + unsigned long fs; + #define CO_ARCH_STATE_STACK_FS "0x26" + + unsigned long gs; + #define CO_ARCH_STATE_STACK_GS "0x2A" + + unsigned short ldt; + #define CO_ARCH_STATE_STACK_LDT "0x2E" + + x86_idt_t idt; + #define CO_ARCH_STATE_STACK_IDT "0x30" + + unsigned short tr; + #define CO_ARCH_STATE_STACK_TR "0x36" + + unsigned long return_eip; + #define CO_ARCH_STATE_STACK_RETURN_EIP "0x38" + + unsigned long flags; + #define CO_ARCH_STATE_STACK_FLAGS "0x3C" + + unsigned long esp; + #define CO_ARCH_STATE_STACK_ESP "0x40" + + unsigned long ss; + #define CO_ARCH_STATE_STACK_SS "0x44" + + unsigned long dr0; + #define CO_ARCH_STATE_STACK_DR0 "0x48" + + unsigned long dr1; + #define CO_ARCH_STATE_STACK_DR1 "0x4C" + + unsigned long dr2; + #define CO_ARCH_STATE_STACK_DR2 "0x50" + + unsigned long dr3; + #define CO_ARCH_STATE_STACK_DR3 "0x54" + + unsigned long dr6; + #define CO_ARCH_STATE_STACK_DR6 "0x58" + + unsigned long dr7; + #define CO_ARCH_STATE_STACK_DR7 "0x5C" + + unsigned long other_map; + #define CO_ARCH_STATE_STACK_OTHERMAP "0x60" + + unsigned long relocate_eip; + #define CO_ARCH_STATE_STACK_RELOCATE_EIP "0x64" + #define CO_ARCH_STATE_STACK_RELOCATE_EIP_AFTER "0x68" + + unsigned long pad1; + unsigned long pad2; + + unsigned char fxstate[0x200]; + #define CO_ARCH_STATE_STACK_FXSTATE "0x70" +} __attribute__((packed)) co_arch_state_stack_t; + +extern void co_debug(const char *fmt, ...); + +static inline void co_passage_page_dump_state(co_arch_state_stack_t *state) +{ + co_debug("cs: %04x ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", + state->cs, state->ds, state->es, state->fs, state->gs, state->ss); + + co_debug("cr0: %08x cr2: %08x cr3: %08x cr4: %08x\n", + state->cr0, state->cr2, state->cr3, state->cr4); + + co_debug("dr0: %08x dr1: %08x dr2: %08x dr3: %08x dr6: %08x dr7: %08x\n", + state->dr0, state->dr1, state->dr2, state->dr3, state->dr6, state->dr7); + + co_debug("gdt: %08x:%04x idt:%08x:%04x ldt:%04x tr:%04x\n", + state->gdt.base, state->gdt.limit, state->idt.table, state->idt.size, + state->ldt, state->tr); + + co_debug("return_eip: %08x flags: %08x esp: %8x\n", + state->return_eip, state->flags, state->esp); + + co_debug("other_map: %08x relocate_eip: %08x\n", + state->other_map, state->relocate_eip); +} + +#define CO_MAX_PARAM_SIZE 0x400 + +typedef struct co_arch_passage_page { + union { + struct { + union { + struct { + unsigned long temp_pgd_physical; + unsigned long dr0; + unsigned long dr1; + unsigned long dr2; + unsigned long dr3; + unsigned long dr6; + unsigned long dr7; + unsigned char code[0x1c0]; + } __attribute__((packed)); + unsigned char pad[0x210]; + } __attribute__((packed)); + + /* Machine states */ + co_arch_state_stack_t host_state; + co_arch_state_stack_t linuxvm_state; + + /* Control parameters */ + unsigned long operation; + unsigned long params[]; + } __attribute__((packed)); + unsigned char first_page[0x1000]; + }; + unsigned long temp_pgd[0x400]; + unsigned long temp_pte[2][0x400]; +} co_arch_passage_page_t; + +static inline void co_passage_page_dump(co_arch_passage_page_t *page) +{ + co_debug("Host state\n"); + co_passage_page_dump_state(&page->host_state); + + co_debug("Linux state\n"); + co_passage_page_dump_state(&page->linuxvm_state); +} + +/* + * Address space layout: + */ + +#define CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP (0xff000000) +#define CO_VPTR_PSEUDO_RAM_PAGE_TABLES (0xfef00000) +#define CO_VPTR_PASSAGE_PAGE (0xfeeff000) +#define CO_VPTR_SELF_MAP (0xfec00000) + +#endif --- linux-2.4.28/include/asm-i386/dma.h~colinux-0.6.1 2003-08-25 07:44:43.000000000 -0400 +++ linux-2.4.28/include/asm-i386/dma.h 2004-11-27 15:59:21.309006560 -0500 @@ -268,6 +268,8 @@ * * Assumes DMA flip-flop is clear. */ + +#ifndef CONFIG_COOPERATIVE static __inline__ int get_dma_residue(unsigned int dmanr) { unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE @@ -281,7 +283,7 @@ return (dmanr<=3)? count : (count<<1); } - +#endif /* These are in kernel/dma.c: */ extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ --- linux-2.4.28/include/asm-i386/io.h~colinux-0.6.1 2003-06-13 10:51:38.000000000 -0400 +++ linux-2.4.28/include/asm-i386/io.h 2004-11-27 15:59:21.309006560 -0500 @@ -2,6 +2,7 @@ #define _ASM_IO_H #include +#include /* * This file contains the definitions for the x86 IO instructions @@ -45,6 +46,7 @@ #ifdef __KERNEL__ #include +#include /* * Temporary debugging check to catch old code using @@ -121,6 +123,9 @@ static inline void * ioremap (unsigned long offset, unsigned long size) { +#ifdef CONFIG_COOPERATIVE + panic("ioremap %ld:%ld\n", offset, size); +#endif return __ioremap(offset, size, 0); } @@ -146,6 +151,9 @@ static inline void * ioremap_nocache (unsigned long offset, unsigned long size) { +#ifdef CONFIG_COOPERATIVE + panic("ioremap_nocache %ld:%ld\n", offset, size); +#endif return __ioremap(offset, size, _PAGE_PCD); } @@ -308,6 +316,8 @@ #endif /* __KERNEL__ */ +#ifndef CONFIG_COOPERATIVE_NOT + #ifdef SLOW_IO_BY_JUMPING #define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:" #else @@ -427,4 +437,21 @@ __OUTS(w) __OUTS(l) +#else + +static inline unsigned long badio(const char *file, int line) +{ +#ifdef CONFIG_COOPERATIVE + panic("badio %s:%d\n", file, line); +#endif + return 0; +} + +#define outb(port, data) badio(__FILE__, __LINE__) +#define inb(port) badio(__FILE__, __LINE__) +#define outb_p(port, data) badio(__FILE__, __LINE__) +#define inb_p(port) badio(__FILE__, __LINE__) + +#endif + #endif --- linux-2.4.28/include/asm-i386/irq.h~colinux-0.6.1 2002-08-02 20:39:45.000000000 -0400 +++ linux-2.4.28/include/asm-i386/irq.h 2004-11-27 15:59:21.310006408 -0500 @@ -14,6 +14,10 @@ #define TIMER_IRQ 0 +#ifdef CONFIG_COOPERATIVE +#define NETWORK_IRQ 2 +#endif + /* * 16 8259A IRQ's, 208 potential APIC interrupt sources. * Right now the APIC is mostly only used for SMP. @@ -23,7 +27,7 @@ * Since vectors 0x00-0x1f are used/reserved for the CPU, * the usable vector space is 0x20-0xff (224 vectors) */ -#ifdef CONFIG_X86_IO_APIC +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_COPIC) #define NR_IRQS 224 #else #define NR_IRQS 16 --- linux-2.4.28/include/asm-i386/mc146818rtc.h~colinux-0.6.1 2001-11-22 14:46:58.000000000 -0500 +++ linux-2.4.28/include/asm-i386/mc146818rtc.h 2004-11-27 15:59:21.310006408 -0500 @@ -4,6 +4,7 @@ #ifndef _ASM_MC146818RTC_H #define _ASM_MC146818RTC_H +#include #include #ifndef RTC_PORT @@ -11,6 +12,7 @@ #define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ #endif +#ifndef CONFIG_COOPERATIVE /* * The yet supported machines all access the RTC index register via * an ISA port access but the way to access the date register differs ... @@ -24,6 +26,11 @@ outb_p((val),RTC_PORT(1)); \ }) +#else +#define CMOS_READ(addr) (0) +#define CMOS_WRITE(val, addr) (0) +#endif + #define RTC_IRQ 8 #endif /* _ASM_MC146818RTC_H */ --- linux-2.4.28/include/asm-i386/page.h~colinux-0.6.1 2002-08-02 20:39:45.000000000 -0400 +++ linux-2.4.28/include/asm-i386/page.h 2004-11-27 15:59:21.310006408 -0500 @@ -1,6 +1,10 @@ #ifndef _I386_PAGE_H #define _I386_PAGE_H +#ifdef CONFIG_COOPERATIVE +#define WANT_PAGE_VIRTUAL +#endif + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -10,6 +14,7 @@ #ifndef __ASSEMBLY__ #include +#include #ifdef CONFIG_X86_USE_3DNOW @@ -80,6 +85,22 @@ #define __PAGE_OFFSET (0xC0000000) +#ifdef CONFIG_COOPERATIVE + +#define CO_PPTM_OFFSET (CO_VPTR_PSEUDO_RAM_PAGE_TABLES) +#define CO_RPPTM_OFFSET (CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP) + +#define CO_PFN(vaddr) ((((unsigned long)vaddr) - __PAGE_OFFSET) >> PAGE_SHIFT) +#define CO_PA(pfn) (((unsigned long *)CO_PPTM_OFFSET)[pfn]) +#define CO_PFN_PA(vaddr) CO_PA(CO_PFN(vaddr)) +#define CO_PPTM_SIZE (max_low_pfn * sizeof(pte_t)) + +#define CO_VA_PFN(pa) (((unsigned long *)CO_RPPTM_OFFSET)[((pa) >> PAGE_SHIFT)]) +#define CO_VA_PAGE(pa) (mem_map + CO_VA_PFN(pa)) +#define CO_VA(pa) ((CO_VA_PFN(pa) << PAGE_SHIFT) + __PAGE_OFFSET) + +#endif + /* * This much address space is reserved for vmalloc() and iomap() * as well as fixmap mappings. @@ -96,11 +117,16 @@ */ #if 1 /* Set to zero for a slightly smaller kernel */ +#ifdef CONFIG_COOPERATIVE +#define BUG() do { panic("BUG %s:%d\n", __FILE__, __LINE__); } while(0) +#else #define BUG() \ __asm__ __volatile__( "ud2\n" \ "\t.word %c0\n" \ "\t.long %c1\n" \ : : "i" (__LINE__), "i" (__FILE__)) + +#endif #else #define BUG() __asm__ __volatile__("ud2\n") #endif @@ -129,9 +155,11 @@ #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) #define __MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) -#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) +#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) + #define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) + #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ --- linux-2.4.28/include/asm-i386/pgalloc.h~colinux-0.6.1 2003-08-25 07:44:43.000000000 -0400 +++ linux-2.4.28/include/asm-i386/pgalloc.h 2004-11-27 15:59:21.313005952 -0500 @@ -11,8 +11,13 @@ #define pte_quicklist (current_cpu_data.pte_quick) #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) +#ifndef CONFIG_COOPERATIVE #define pmd_populate(mm, pmd, pte) \ - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) +#else +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + (CO_PFN_PA(pte) & PAGE_MASK))) +#endif /* * Allocate and free page tables. --- linux-2.4.28/include/asm-i386/pgtable-2level.h~colinux-0.6.1 2002-11-28 18:53:15.000000000 -0500 +++ linux-2.4.28/include/asm-i386/pgtable-2level.h 2004-11-27 15:59:21.313005952 -0500 @@ -58,8 +58,14 @@ } #define ptep_get_and_clear(xp) __pte(xchg(&(xp)->pte_low, 0)) #define pte_same(a, b) ((a).pte_low == (b).pte_low) -#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT)))) #define pte_none(x) (!(x).pte_low) + +#ifndef CONFIG_COOPERATIVE +#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT)))) #define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot)) +#else +#define pte_page(x) CO_VA_PAGE((x).pte_low) +#define __mk_pte(page_nr,pgprot) __pte((CO_PA(page_nr) & PAGE_MASK) | pgprot_val(pgprot)) +#endif #endif /* _I386_PGTABLE_2LEVEL_H */ --- linux-2.4.28/include/asm-i386/pgtable.h~colinux-0.6.1 2002-11-28 18:53:15.000000000 -0500 +++ linux-2.4.28/include/asm-i386/pgtable.h 2004-11-27 15:59:21.313005952 -0500 @@ -320,8 +320,13 @@ #define page_pte(page) page_pte_prot(page, __pgprot(0)) +#ifndef CONFIG_COOPERATIVE #define pmd_page(pmd) \ -((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +#else +#define pmd_page(pmd) \ + (CO_VA(pmd_val(pmd))) +#endif /* to find an entry in a page-table-directory. */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) --- linux-2.4.28/include/asm-i386/processor.h~colinux-0.6.1 2004-02-18 08:36:32.000000000 -0500 +++ linux-2.4.28/include/asm-i386/processor.h 2004-11-27 15:59:21.314005800 -0500 @@ -181,8 +181,18 @@ #define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ #define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ +#ifndef CONFIG_COOPERATIVE #define load_cr3(pgdir) \ - asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir))); +asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir))); +#else +/* + * In coLinux Mode we can't load CR3 with the pseudo physical + * address. Instead, we need to translate the pseudo physical address + * to the real physical address. + */ +#define load_cr3(pgdir) \ +asm volatile("movl %0,%%cr3": :"r" (CO_PFN_PA(pgdir))); +#endif /* * Save the cr4 feature set we're using (ie --- linux-2.4.28/include/asm-i386/system.h~colinux-0.6.1 2004-04-14 09:05:40.000000000 -0400 +++ linux-2.4.28/include/asm-i386/system.h 2004-11-27 15:59:21.314005800 -0500 @@ -12,7 +12,15 @@ 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_COOPERATIVE +#define prepare_to_switch() { \ + asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->thread.fs)); \ + asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->thread.gs)); \ +} +#else #define prepare_to_switch() do { } while(0) +#endif + #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ "pushl %%edi\n\t" \ --- linux-2.4.28/include/linux/console.h~colinux-0.6.1 2004-02-18 08:36:32.000000000 -0500 +++ linux-2.4.28/include/linux/console.h 2004-11-27 15:59:21.315005648 -0500 @@ -55,6 +55,7 @@ extern const struct consw dummy_con; /* dummy console buffer */ extern const struct consw fb_con; /* frame buffer based console */ extern const struct consw vga_con; /* VGA text console */ +extern const struct consw colinux_con; /* coLinux Mode text console */ extern const struct consw newport_con; /* SGI Newport console */ extern const struct consw prom_con; /* SPARC PROM console */ --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/include/linux/cooperative.h 2004-11-27 15:59:21.315005648 -0500 @@ -0,0 +1,323 @@ +#ifndef __LINUX_COOPERATIVE_H__ +#define __LINUX_COOPERATIVE_H__ + +#ifdef __KERNEL__ +#ifndef CO_KERNEL +#define CO_COLINUX_KERNEL +#define CO_KERNEL +#endif +#endif + +extern void co_debug(const char *fmt, ...); + +#include + +#define CO_LINUX_ABI_VERSION 1 + +#pragma pack(0) + +#define CO_BOOTPARAM_STRING_LENGTH 0x100 + +extern char co_boot_parameters[CO_BOOTPARAM_STRING_LENGTH]; + +typedef enum { + CO_OPERATION_EMPTY=0, + CO_OPERATION_START, + CO_OPERATION_IDLE, + CO_OPERATION_TERMINATE, + CO_OPERATION_MESSAGE_TO_MONITOR, + CO_OPERATION_MESSAGE_FROM_MONITOR, + CO_OPERATION_FORWARD_INTERRUPT, + CO_OPERATION_DEVICE, + CO_OPERATION_GET_TIME, + CO_OPERATION_DEBUG_LINE, + CO_OPERATION_GET_HIGH_PREC_QUOTIENT, + CO_OPERATION_TRACE_POINT, +} co_operation_t; + +#define CO_MODULE_MAX_CONET 16 +#define CO_MODULE_MAX_COBD 32 + +typedef enum { + CO_MODULE_LINUX, + CO_MODULE_MONITOR, + CO_MODULE_DAEMON, + CO_MODULE_IDLE, + CO_MODULE_KERNEL_SWITCH, + CO_MODULE_USER_SWITCH, + CO_MODULE_CONSOLE, + CO_MODULE_PRINTK, + + CO_MODULE_CONET0, + CO_MODULE_CONET_END=CO_MODULE_CONET0+CO_MODULE_MAX_CONET-1, + + CO_MODULE_COBD0, + CO_MODULE_COBD_END=CO_MODULE_COBD0+CO_MODULE_MAX_COBD-1, +} co_module_t; + +typedef enum { + CO_PRIORITY_DISCARDABLE=0, + CO_PRIORITY_IMPORTANT, +} co_priority_t; + +typedef enum { + CO_MESSAGE_TYPE_STRING=0, + CO_MESSAGE_TYPE_OTHER=1, +} co_message_type_t; + +typedef struct { + co_module_t from; + co_module_t to; + co_priority_t priority; + co_message_type_t type; + unsigned long size; + char data[0]; +} __attribute__((packed)) co_message_t; + +typedef enum { + CO_DEVICE_BLOCK=0, + CO_DEVICE_CONSOLE, + CO_DEVICE_KEYBOARD, + CO_DEVICE_NETWORK, + CO_DEVICE_TIMER, + CO_DEVICE_POWER, + + CO_DEVICES_TOTAL, +} co_device_t; + +typedef struct { + unsigned char code; + int down; +} co_scan_code_t; + +typedef enum { + CO_LINUX_MESSAGE_POWER_ALT_CTRL_DEL=0, +} co_linux_message_power_type_t; + +typedef struct { + co_linux_message_power_type_t type; +} __attribute__((packed)) co_linux_message_power_t; + +typedef struct { + unsigned long tick_count; +} __attribute__((packed)) co_linux_message_idle_t; + +typedef struct { + co_device_t device; + unsigned long unit; + unsigned long size; + char data[]; +} __attribute__((packed)) co_linux_message_t; + +typedef enum { + CO_TERMINATE_END=0, + CO_TERMINATE_REBOOT, + CO_TERMINATE_POWEROFF, + CO_TERMINATE_PANIC, + CO_TERMINATE_HALT, + CO_TERMINATE_FORCED_OFF, + CO_TERMINATE_FORCED_END, + CO_TERMINATE_INVALID_OPERATION, +} co_termination_reason_t; + +typedef void (*co_switcher_t)(co_arch_passage_page_t *page, + unsigned char *from, + unsigned char *to); + +#define co_passage_page_func_low(_from_,_to_) \ + (((co_switcher_t)(co_passage_page->code)) \ + (co_passage_page, \ + (char *)&_from_.border2, \ + (char *)&_to_.border2)) + +#define co_passage_page_func(_from_,_to_) \ + co_passage_page_func_low(co_passage_page->_from_, co_passage_page->_to_) + +#ifdef CO_KERNEL +# ifdef CO_COLINUX_KERNEL +# define co_passage_page ((co_arch_passage_page_t *)(CO_VPTR_PASSAGE_PAGE)) +# define co_current (co_passage_page->linuxvm_state) +# define co_other (co_passage_page->host_state) +# else +# define co_passage_page (cmon->passage_page) +# define co_other (co_passage_page->linuxvm_state) +# define co_current (co_passage_page->host_state) +# endif + +# define co_switch() co_passage_page_func_low(co_current, co_other) +#endif + +/* + * Defines operations on various virtual devices. + */ + +typedef enum { + CO_OPERATION_CONSOLE_STARTUP=0, + CO_OPERATION_CONSOLE_INIT=1, + CO_OPERATION_CONSOLE_DEINIT, + CO_OPERATION_CONSOLE_CLEAR, + CO_OPERATION_CONSOLE_PUTC, + CO_OPERATION_CONSOLE_PUTCS, + CO_OPERATION_CONSOLE_CURSOR_DRAW, + CO_OPERATION_CONSOLE_CURSOR_ERASE, + CO_OPERATION_CONSOLE_CURSOR_MOVE, + CO_OPERATION_CONSOLE_SCROLL_UP, + CO_OPERATION_CONSOLE_SCROLL_DOWN, + CO_OPERATION_CONSOLE_BMOVE, + CO_OPERATION_CONSOLE_SWITCH, + CO_OPERATION_CONSOLE_BLANK, + CO_OPERATION_CONSOLE_FONT_OP, + CO_OPERATION_CONSOLE_SET_PALETTE, + CO_OPERATION_CONSOLE_SCROLLDELTA, + CO_OPERATION_CONSOLE_SET_ORIGIN, + CO_OPERATION_CONSOLE_SAVE_SCREEN, + CO_OPERATION_CONSOLE_INVERT_REGION, +} co_operation_console_t; + + +typedef char co_console_code; +typedef unsigned short co_console_character; +typedef unsigned short co_console_unit; + +typedef struct { + co_console_unit x; + co_console_unit y; + co_console_unit height; +} __attribute__((packed)) co_cursor_pos_t; + +typedef struct { + co_operation_console_t type; + union { + struct { + co_console_unit top; + co_console_unit bottom; + co_console_unit lines; + } scroll; + struct { + co_console_unit y; + co_console_unit x; + co_console_unit count; + co_console_character data[]; + } putcs; + struct { + co_console_unit x; + co_console_unit y; + co_console_character charattr; + } putc; + struct { + co_console_unit top; + co_console_unit left; + co_console_unit bottom; + co_console_unit right; + co_console_character charattr; + } clear; + struct { + co_console_unit y; + co_console_unit x; + co_console_unit count; + } invert; + struct { + co_console_unit row; + co_console_unit column; + co_console_unit top; + co_console_unit left; + co_console_unit bottom; + co_console_unit right; + } bmove; + co_cursor_pos_t cursor; + }; +} __attribute__((packed)) co_console_message_t; + +typedef struct { + unsigned long index; + unsigned long flags; + unsigned long func; + unsigned long pid; +} __attribute__((packed)) co_trace_point_info_t; + +extern void co_printk(char *line); +extern void co_callback(void); +extern void co_switch_wrapper(void); +extern void co_idle_processor(void); +extern void co_terminate(co_termination_reason_t reason); + +extern void co_send_message(co_module_t from, + co_module_t to, + co_priority_t priority, + co_message_type_t type, + unsigned long size, + char *data); +extern co_message_t *co_send_message_save(unsigned long *flags); +extern co_message_t *co_get_message_save(unsigned long *flags); +extern void co_send_message_restore(unsigned long flags); + +extern void co_handle_device_interrupt(co_linux_message_t *message); +extern void co_received_message(co_linux_message_t *message); +extern int co_get_message(co_linux_message_t **message, co_device_t device); +extern void co_free_message(co_linux_message_t *message); + +extern unsigned long co_bootmem_pages; +extern unsigned long co_core_end; +extern unsigned long co_memory_size; +extern unsigned long co_rpptm_size; + +extern unsigned long co_get_host_time(void); +extern void handle_keyboard_event(unsigned char scancode); + +typedef enum { + CO_BLOCK_OPEN=0, + CO_BLOCK_STAT, + CO_BLOCK_READ, + CO_BLOCK_WRITE, + CO_BLOCK_CLOSE, + CO_BLOCK_GET_ALIAS, +} co_block_request_type_t; + +typedef enum { + CO_NETWORK_GET_MAC=0, +} co_network_request_type_t; + +#ifdef CO_KERNEL +/* If we are compiling kernel code (Linux or Host Driver) */ +# ifdef CO_COLINUX_KERNEL +/* Inside Linux, vm_ptr_t considered a valid pointer in its virtual address space */ +typedef void *vm_ptr_t; +# else +/* But inside the host, the type is considered not to be a pointer in its own address space */ +typedef unsigned long vm_ptr_t; +# endif + +typedef struct { + co_block_request_type_t type; + long rc; + union { + struct { + unsigned long long offset; + unsigned long long size; + unsigned long long disk_size; + vm_ptr_t address; + }; + struct { + char alias[20]; + }; + }; +} __attribute__((packed)) co_block_request_t; + +typedef struct { + co_network_request_type_t type; + unsigned long unit; + char mac_address[6]; + char _pad[2]; + int result; +} __attribute__((packed)) co_network_request_t; + +#endif + +#ifndef COLINUX_TRACE +#define CO_TRACE_STOP +#define CO_TRACE_CONTINUE +#endif + +#pragma pack() + +#endif --- linux-2.4.28/include/linux/major.h~colinux-0.6.1 2003-06-13 10:51:38.000000000 -0400 +++ linux-2.4.28/include/linux/major.h 2004-11-27 15:59:21.315005648 -0500 @@ -142,6 +142,7 @@ #define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ #define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ +#define COLINUX_MAJOR 117 #define RTF_MAJOR 150 #define RAW_MAJOR 162 --- linux-2.4.28/init/do_mounts.c~colinux-0.6.1 2003-11-28 13:26:21.000000000 -0500 +++ linux-2.4.28/init/do_mounts.c 2004-11-27 15:59:21.316005496 -0500 @@ -255,6 +255,9 @@ { "ftld", 0x2c18 }, { "mtdblock", 0x1f00 }, { "nb", 0x2b00 }, +#ifdef CONFIG_COOPERATIVE + { "cobd", 0x7500 }, +#endif { NULL, 0 } }; --- linux-2.4.28/init/main.c~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 +++ linux-2.4.28/init/main.c 2004-11-27 15:59:21.317005344 -0500 @@ -74,6 +74,8 @@ #include #endif +#include + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -305,7 +307,14 @@ #ifdef CONFIG_X86_LOCAL_APIC static void __init smp_init(void) { +#ifdef CONFIG_COOPERATIVE + /* + * It doesn't work yet because I haven't implemented the + * timer interrupt yet + */ +#else APIC_init_uniprocessor(); +#endif } #else #define smp_init() do { } while (0) --- linux-2.4.28/kernel/Makefile~colinux-0.6.1 2001-09-17 00:22:40.000000000 -0400 +++ linux-2.4.28/kernel/Makefile 2004-11-27 15:59:21.317005344 -0500 @@ -14,7 +14,7 @@ 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 \ sysctl.o acct.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o + signal.o sys.o kmod.o context.o cooperative.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o --- /dev/null 2004-04-06 13:56:48.000000000 -0400 +++ linux-2.4.28/kernel/cooperative.c 2004-11-27 15:59:21.318005192 -0500 @@ -0,0 +1,337 @@ +/* + * linux/kernel/cooperative.c + * + * Code for Cooperative mode (coLinux) + * + * Dan Aloni , 2003 (C). + * + */ + +#include +#include +#include +#include +#include +#include + +CO_TRACE_STOP; + +void start_kernel(void); +extern char _kernel_start, _end; + +unsigned long co_core_end = 0; +unsigned long co_memory_size = 0; +char co_boot_parameters[CO_BOOTPARAM_STRING_LENGTH]; + +void colinux_start_c() +{ + co_core_end = co_passage_page->params[0]; + co_memory_size = co_passage_page->params[1]; + memcpy(co_boot_parameters, &co_passage_page->params[2], + sizeof(co_boot_parameters)); + + start_kernel(); + + co_terminate(CO_TERMINATE_END); +} + +co_message_t *co_send_message_save(unsigned long *flags) +{ + local_irq_save(*flags); + co_passage_page->operation = CO_OPERATION_MESSAGE_TO_MONITOR; + co_passage_page->params[0] = 1; + return (co_message_t *)(&co_passage_page->params[1]); +} + +void co_send_message_restore(unsigned long flags) +{ + co_switch_wrapper(); + local_irq_restore(flags); +} + +void co_send_message_s(co_message_t *message, char *data) +{ + if ((sizeof(co_message_t) + message->size) < 2000) { + co_message_t *params; + unsigned long flags; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_MESSAGE_TO_MONITOR; + co_passage_page->params[0] = 1; + params = (co_message_t *)(&co_passage_page->params[1]); + *params = *message; + memcpy(params->data, data, message->size); + co_switch_wrapper(); + local_irq_restore(flags); + return; + } +} + +void co_send_message(co_module_t from, + co_module_t to, + co_priority_t priority, + co_message_type_t type, + unsigned long size, + char *data) +{ + co_message_t params; + + params.from = from; + params.to = to; + params.priority = priority; + params.type = type; + params.size = size; + + co_send_message_s(¶ms, data); +} + +void co_receive_message(co_message_t *message) +{ + struct { + co_message_t message; + co_linux_message_t linux_part; + } *linux_message; + + linux_message = (typeof(linux_message))message; + + co_handle_device_interrupt(&linux_message->linux_part); +} + +void co_callback(void) +{ + while (co_passage_page->operation == CO_OPERATION_MESSAGE_FROM_MONITOR) { + co_receive_message((co_message_t *)&co_passage_page->params[1]); + if (co_passage_page->params[0] == 0) { + break; + } + + co_passage_page->operation = CO_OPERATION_MESSAGE_FROM_MONITOR; + co_switch_wrapper(); + } +} + +void co_idle_processor(void) +{ + unsigned long flags; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_IDLE; + co_switch_wrapper(); + co_callback(); + local_irq_restore(flags); +} + +void co_printk(char *line) +{ + co_send_message(CO_MODULE_LINUX, + CO_MODULE_PRINTK, + CO_PRIORITY_DISCARDABLE, + CO_MESSAGE_TYPE_STRING, + strlen(line)+1, + line); +} + +void co_debug_line(char *line) +{ + unsigned long flags; + + if (!line) + return; + + if (strlen(line) > 0x200) + return; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_DEBUG_LINE; + strcpy((char *)&co_passage_page->params[0], line); + co_switch_wrapper(); + local_irq_restore(flags); +} + +void co_trace_ent_name(void *func, const char *name) +{ + static int reenterent = 0; + static int count = 0; + static char private_buffer[0x100]; + unsigned long flags; + + if (reenterent) + return; + + reenterent = 1; + + local_irq_save(flags); + count += 1; + + if (count > 1900000) { + snprintf(private_buffer, sizeof(private_buffer), "%d: %d: %x %s\n", count, current->pid, func, name); + co_debug_line(private_buffer); + } + + local_irq_restore(flags); + + reenterent = 0; +} + +static unsigned long trace_index = 0; + +void co_trace_ent(void *func) +{ + unsigned long flags; + co_trace_point_info_t *trace_point; + + local_irq_save(flags); + trace_index++; + co_passage_page->operation = CO_OPERATION_TRACE_POINT; + trace_point = (co_trace_point_info_t *)&co_passage_page->params[0]; + trace_point->pid = 0; + if (current) + trace_point->pid = current->pid; + trace_point->index = trace_index; + trace_point->flags = 1; + trace_point->func = (unsigned long)(func); + co_switch_wrapper(); + local_irq_restore(flags); +} + +void co_trace_ret(void *func) +{ + unsigned long flags; + co_trace_point_info_t *trace_point; + + local_irq_save(flags); + trace_index++; + co_passage_page->operation = CO_OPERATION_TRACE_POINT; + trace_point = (co_trace_point_info_t *)&co_passage_page->params[0]; + trace_point->pid = 0; + if (current) + trace_point->pid = current->pid; + trace_point->index = trace_index; + trace_point->flags = 0; + trace_point->func = (unsigned long)(func); + co_switch_wrapper(); + local_irq_restore(flags); +} + +void co_debug(const char *fmt, ...) +{ + static char co_buf[1024]; + unsigned long flags; + va_list args; + + local_irq_save(flags); + va_start(args, fmt); + vsnprintf(co_buf, sizeof(co_buf), fmt, args); + va_end(args); + co_debug_line(co_buf); + local_irq_restore(flags); +} + +void co_terminate(co_termination_reason_t reason) +{ + unsigned long flags; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_TERMINATE; + co_passage_page->params[0] = reason; + co_switch_wrapper(); + local_irq_restore(flags); +} + +unsigned long co_get_host_time(void) +{ + unsigned long flags; + unsigned long time; + + local_irq_save(flags); + co_passage_page->operation = CO_OPERATION_GET_TIME; + co_switch_wrapper(); + time = co_passage_page->params[0]; + local_irq_restore(flags); + + return time; +} + +typedef struct { + struct list_head node; + co_linux_message_t msg; +} co_linux_message_node_t; + +typedef struct { + struct list_head list; + int num_messages; +} co_linux_message_queue_t; + +co_linux_message_queue_t *co_msgqueues = NULL; + +void co_received_message(co_linux_message_t *message) +{ + co_linux_message_node_t *copy; + co_linux_message_queue_t *queue; + + if (!co_msgqueues) + return; + + if (message->device < 0 || (message->device >= CO_DEVICES_TOTAL)) + return; + + copy = (co_linux_message_node_t *)kmalloc(sizeof(co_linux_message_node_t) + message->size, GFP_ATOMIC); + if (!copy) + return; + + queue = &co_msgqueues[message->device]; + memcpy(©->msg, message, sizeof(co_linux_message_t) + message->size); + list_add(©->node, &queue->list); + queue->num_messages++; +} + +static int __init initcall_message_queues(void) +{ + int queue_index; + + co_msgqueues = kmalloc(sizeof(co_linux_message_queue_t) * CO_DEVICES_TOTAL, GFP_KERNEL); + if (!co_msgqueues) { + panic("Unable to allocate message queues\n"); + } + + for (queue_index=0; queue_index < CO_DEVICES_TOTAL; queue_index++) { + co_linux_message_queue_t *queue = &co_msgqueues[queue_index]; + queue->num_messages = 0; + INIT_LIST_HEAD(&queue->list); + } + + return 0; +} + +__initcall(initcall_message_queues); + +int co_get_message(co_linux_message_t **message, co_device_t device) +{ + co_linux_message_queue_t *queue; + co_linux_message_node_t *node; + + if (!co_msgqueues) + return 0; + + queue = &co_msgqueues[device]; + if (list_empty(&queue->list)) + return 0; + + node = list_entry(queue->list.prev, co_linux_message_node_t, node); + list_del(&node->node); + queue->num_messages--; + *message = &node->msg; + return 1; +} + +void co_free_message(co_linux_message_t *message) +{ + co_linux_message_node_t *node = NULL; + + node = (co_linux_message_node_t *)(((char *)message) - ((long)&node->msg)); + + kfree(node); +} + + +CO_TRACE_CONTINUE; --- linux-2.4.28/kernel/panic.c~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 +++ linux-2.4.28/kernel/panic.c 2004-11-27 15:59:21.318005192 -0500 @@ -18,6 +18,8 @@ #include #include +#include + asmlinkage void sys_sync(void); /* it's really int */ int panic_timeout; @@ -70,6 +72,8 @@ sys_sync(); bust_spinlocks(0); + co_terminate(CO_TERMINATE_PANIC); + #ifdef CONFIG_SMP smp_send_stop(); #endif --- linux-2.4.28/kernel/printk.c~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 +++ linux-2.4.28/kernel/printk.c 2004-11-27 15:59:21.319005040 -0500 @@ -29,6 +29,8 @@ #include +#include + #if !defined(CONFIG_LOG_BUF_SHIFT) || (CONFIG_LOG_BUF_SHIFT == 0) #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) #define LOG_BUF_LEN (65536) @@ -433,6 +435,9 @@ printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); va_end(args); +#ifdef CONFIG_COOPERATIVE + co_printk(printk_buf); +#endif /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here @@ -459,6 +464,7 @@ spin_unlock_irqrestore(&logbuf_lock, flags); goto out; } + if (!down_trylock(&console_sem)) { /* * We own the drivers. We can drop the spinlock and let