--- linux-2.6.1-rc1/arch/alpha/kernel/traps.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/alpha/kernel/traps.c 2004-01-04 22:15:46.000000000 -0800 @@ -636,6 +636,7 @@ do_entUna(void * va, unsigned long opcod lock_kernel(); printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", pc, va, opcode, reg); + dump_stack(); do_exit(SIGSEGV); got_exception: --- linux-2.6.1-rc1/arch/i386/boot/setup.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/boot/setup.S 2004-01-04 22:21:59.000000000 -0800 @@ -162,7 +162,7 @@ cmd_line_ptr: .long 0 # (Header versio # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd --- linux-2.6.1-rc1/arch/i386/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/Kconfig 2004-01-04 22:21:59.000000000 -0800 @@ -402,6 +402,54 @@ config X86_OOSTORE depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 default y +config X86_4G + bool "4 GB kernel-space and 4 GB user-space virtual memory support" + help + This option is only useful for systems that have more than 1 GB + of RAM. + + The default kernel VM layout leaves 1 GB of virtual memory for + kernel-space mappings, and 3 GB of VM for user-space applications. + This option ups both the kernel-space VM and the user-space VM to + 4 GB. + + The cost of this option is additional TLB flushes done at + system-entry points that transition from user-mode into kernel-mode. + I.e. system calls and page faults, and IRQs that interrupt user-mode + code. There's also additional overhead to kernel operations that copy + memory to/from user-space. The overhead from this is hard to tell and + depends on the workload - it can be anything from no visible overhead + to 20-30% overhead. A good rule of thumb is to count with a runtime + overhead of 20%. + + The upside is the much increased kernel-space VM, which more than + quadruples the maximum amount of RAM supported. Kernels compiled with + this option boot on 64GB of RAM and still have more than 3.1 GB of + 'lowmem' left. Another bonus is that highmem IO bouncing decreases, + if used with drivers that still use bounce-buffers. + + There's also a 33% increase in user-space VM size - database + applications might see a boost from this. + + But the cost of the TLB flushes and the runtime overhead has to be + weighed against the bonuses offered by the larger VM spaces. The + dividing line depends on the actual workload - there might be 4 GB + systems that benefit from this option. Systems with less than 4 GB + of RAM will rarely see a benefit from this option - but it's not + out of question, the exact circumstances have to be considered. + +config X86_SWITCH_PAGETABLES + def_bool X86_4G + +config X86_4G_VM_LAYOUT + def_bool X86_4G + +config X86_UACCESS_INDIRECT + def_bool X86_4G + +config X86_HIGH_ENTRY + def_bool X86_4G + config HPET_TIMER bool "HPET Timer Support" help @@ -1056,7 +1104,7 @@ config PCI_DIRECT config PCI_USE_VECTOR bool "Vector-based interrupt indexing" - depends on X86_LOCAL_APIC + depends on X86_LOCAL_APIC && X86_IO_APIC default n help This replaces the current existing IRQ-based index interrupt scheme @@ -1230,6 +1278,15 @@ config DEBUG_PAGEALLOC This results in a large slowdown, but helps to find certain types of memory corruptions. +config SPINLINE + bool "Spinlock inlining" + depends on DEBUG_KERNEL + help + This will change spinlocks from out of line to inline, making them + account cost to the callers in readprofile, rather than the lock + itself (as ".text.lock.filename"). This can be helpful for finding + the callers of locks. + config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM @@ -1246,20 +1303,208 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" help If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb.txt file. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +config KGDB_PORT + hex "hex I/O port address of the debug serial port" + depends on KGDB + default 3f8 + help + Some systems (x86 family at this writing) allow the port + address to be configured. The number entered is assumed to be + hex, don't put 0x in front of it. The standard address are: + COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx + will tell you what you have. It is good to test the serial + connection with a live system before trying to debug. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 4 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config STACK_OVERFLOW_TEST + bool "Turn on kernel stack overflow testing?" + depends on KGDB + default n + help + This option enables code in the front line interrupt handlers + to check for kernel stack overflow on interrupts and system + calls. This is part of the kgdb code on x86 systems. + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + config FRAME_POINTER bool "Compile the kernel with frame pointers" + default KGDB help If you say Y here the resulting kernel image will be slightly larger and slower, but it will give very useful debugging information. If you don't debug the kernel, you can say N, but we may not be able to solve problems without frame pointers. +config MAGIC_SYSRQ + bool + depends on KGDB_SYSRQ + default y + config X86_EXTRA_IRQS bool depends on X86_LOCAL_APIC || X86_VOYAGER --- linux-2.6.1-rc1/arch/i386/kernel/acpi/boot.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/acpi/boot.c 2004-01-04 22:15:42.000000000 -0800 @@ -41,9 +41,8 @@ #define PREFIX "ACPI: " -extern int acpi_disabled; -extern int acpi_irq; -extern int acpi_ht; +int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +int acpi_ht __initdata = 1; /* enable HT */ int acpi_lapic = 0; int acpi_ioapic = 0; @@ -250,29 +249,66 @@ acpi_parse_nmi_src ( #ifdef CONFIG_ACPI_BUS /* - * Set specified PIC IRQ to level triggered mode. + * "acpi_pic_sci=level" (current default) + * programs the PIC-mode SCI to Level Trigger. + * (NO-OP if the BIOS set Level Trigger already) + * + * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_pic_sci=edge" + * (NO-OP if the BIOS set Edge Trigger already) * * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) - * - * As the BIOS should have done this for us, - * print a warning if the IRQ wasn't already set to level. */ -void acpi_pic_set_level_irq(unsigned int irq) +static int __initdata acpi_pic_sci_trigger; /* 0: level, 1: edge */ + +void __init +acpi_pic_sci_set_trigger(unsigned int irq) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); unsigned char val = inb(port); + + printk(PREFIX "IRQ%d SCI:", irq); if (!(val & mask)) { - printk(KERN_WARNING PREFIX "IRQ %d was Edge Triggered, " - "setting to Level Triggerd\n", irq); - outb(val | mask, port); + printk(" Edge"); + + if (!acpi_pic_sci_trigger) { + printk(" set to Level"); + outb(val | mask, port); + } + } else { + printk(" Level"); + + if (acpi_pic_sci_trigger) { + printk(" set to Edge"); + outb(val | mask, port); + } } + printk(" Trigger.\n"); } + +int __init +acpi_pic_sci_setup(char *str) +{ + while (str && *str) { + if (strncmp(str, "level", 5) == 0) + acpi_pic_sci_trigger = 0; /* force level trigger */ + if (strncmp(str, "edge", 4) == 0) + acpi_pic_sci_trigger = 1; /* force edge trigger */ + str = strchr(str, ','); + if (str) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("acpi_pic_sci=", acpi_pic_sci_setup); + #endif /* CONFIG_ACPI_BUS */ @@ -327,6 +363,37 @@ static int __init acpi_parse_hpet(unsign } #endif +/* detect the location of the ACPI PM Timer */ +#ifdef CONFIG_X86_PM_TIMER +extern u32 pmtmr_ioport; + +static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt =0; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if(!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + + if (fadt->revision >= FADT2_REVISION_ID) { + /* FADT rev. 2 */ + if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) + return 0; + + pmtmr_ioport = fadt->xpm_tmr_blk.address; + } else { + /* FADT rev. 1 */ + pmtmr_ioport = fadt->V1_pm_tmr_blk; + } + if (pmtmr_ioport) + printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport); + return 0; +} +#endif + + unsigned long __init acpi_find_rsdp (void) { @@ -387,8 +454,10 @@ acpi_boot_init (void) * Initialize the ACPI boot-time table parser. */ result = acpi_table_init(); - if (result) + if (result) { + acpi_disabled = 1; return result; + } result = acpi_blacklisted(); if (result) { @@ -469,7 +538,7 @@ acpi_boot_init (void) * If MPS is present, it will handle them, * otherwise the system will stay in PIC mode */ - if (acpi_disabled || !acpi_irq) { + if (acpi_disabled || acpi_noirq) { return 1; } @@ -511,6 +580,8 @@ acpi_boot_init (void) acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */ @@ -526,5 +597,9 @@ acpi_boot_init (void) acpi_table_parse(ACPI_HPET, acpi_parse_hpet); #endif +#ifdef CONFIG_X86_PM_TIMER + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); +#endif + return 0; } --- linux-2.6.1-rc1/arch/i386/kernel/acpi/wakeup.S 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/i386/kernel/acpi/wakeup.S 2004-01-04 22:16:24.000000000 -0800 @@ -193,11 +193,6 @@ wakeup_pmode_return: # and restore the stack ... but you need gdt for this to work movl saved_context_esp, %esp - movw $0x0e00 + 'W', 0xb8018 - outl %eax, $0x80 - outl %eax, $0x80 - movw $0x0e00 + 'O', 0xb8018 - movl %cs:saved_magic, %eax cmpl $0x12345678, %eax jne bogus_magic @@ -205,9 +200,6 @@ wakeup_pmode_return: # jump to place where we left off movl saved_eip,%eax movw $0x0e00 + 'x', 0xb8018 - outl %eax, $0x80 - outl %eax, $0x80 - movw $0x0e00 + '!', 0xb801a jmp *%eax bogus_magic: --- linux-2.6.1-rc1/arch/i386/kernel/asm-offsets.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/asm-offsets.c 2004-01-04 22:21:59.000000000 -0800 @@ -4,9 +4,11 @@ * to extract and format the required data. */ +#include #include #include #include "sigframe.h" +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -28,4 +30,17 @@ void foo(void) DEFINE(RT_SIGFRAME_sigcontext, offsetof (struct rt_sigframe, uc.uc_mcontext)); + DEFINE(TI_task, offsetof (struct thread_info, task)); + DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain)); + DEFINE(TI_flags, offsetof (struct thread_info, flags)); + DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count)); + DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit)); + DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack)); + DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack)); + DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd)); + + DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0)); + DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL)); + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(task_thread_db7, offsetof (struct task_struct, thread.debugreg[7])); } --- linux-2.6.1-rc1/arch/i386/kernel/cpu/common.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/cpu/common.c 2004-01-04 22:21:59.000000000 -0800 @@ -514,12 +514,16 @@ void __init cpu_init (void) set_tss_desc(cpu,t); cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); - load_LDT(&init_mm.context); + if (cpu) + load_LDT(&init_mm.context); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; + if (cpu) + trap_init_virtual_GDT(); + /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); --- linux-2.6.1-rc1/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-01-04 22:16:26.000000000 -0800 @@ -687,11 +687,13 @@ find_psb_table(void) if (ppst[j].vid < rvo) { /* vid+rvo >= 0 */ printk(KERN_ERR BFX "0 vid exceeded with pstate %d\n", j); + kfree(ppst); return -ENODEV; } if (ppst[j].vid < maxvid+rvo) { /* vid+rvo >= maxvid */ printk(KERN_ERR BFX "maxvid exceeded with pstate %d\n", j); + kfree(ppst); return -ENODEV; } } @@ -706,7 +708,7 @@ find_psb_table(void) for (j = 0; j < numps; j++) if ((ppst[j].fid==currfid) && (ppst[j].vid==currvid)) - return (0); + return 0; printk(KERN_ERR BFX "currfid/vid do not match PST, ignoring\n"); return 0; --- linux-2.6.1-rc1/arch/i386/kernel/cpu/intel.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/kernel/cpu/intel.c 2004-01-04 22:21:59.000000000 -0800 @@ -1,5 +1,7 @@ +#include #include #include + #include #include #include @@ -8,10 +10,15 @@ #include #include #include +#include #include "cpu.h" -extern int trap_init_f00f_bug(void); +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#include +#endif #ifdef CONFIG_X86_INTEL_USERCOPY /* @@ -157,7 +164,7 @@ static void __init init_intel(struct cpu c->f00f_bug = 1; if ( !f00f_workaround_enabled ) { - trap_init_f00f_bug(); + trap_init_virtual_IDT(); printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); f00f_workaround_enabled = 1; } @@ -240,6 +247,12 @@ static void __init init_intel(struct cpu /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */ if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) clear_bit(X86_FEATURE_SEP, c->x86_capability); + /* + * FIXME: SEP is disabled for 4G/4G for now: + */ +#ifdef CONFIG_X86_HIGH_ENTRY + clear_bit(X86_FEATURE_SEP, c->x86_capability); +#endif /* Names for the Pentium II/Celeron processors detectable only by also checking the cache size. @@ -277,6 +290,7 @@ static void __init init_intel(struct cpu extern int phys_proc_id[NR_CPUS]; u32 eax, ebx, ecx, edx; + int index_lsb, index_msb, tmp; int cpu = smp_processor_id(); cpuid(1, &eax, &ebx, &ecx, &edx); @@ -285,6 +299,8 @@ static void __init init_intel(struct cpu if (smp_num_siblings == 1) { printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); } else if (smp_num_siblings > 1 ) { + index_lsb = 0; + index_msb = 31; /* * At this point we only support two siblings per * processor package. @@ -295,13 +311,19 @@ static void __init init_intel(struct cpu smp_num_siblings = 1; goto too_many_siblings; } - /* cpuid returns the value latched in the HW at reset, - * not the APIC ID register's value. For any box - * whose BIOS changes APIC IDs, like clustered APIC - * systems, we must use hard_smp_processor_id. - * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID. - */ - phys_proc_id[cpu] = hard_smp_processor_id() & ~(smp_num_siblings - 1); + tmp = smp_num_siblings; + while ((tmp & 1) == 0) { + tmp >>=1 ; + index_lsb++; + } + tmp = smp_num_siblings; + while ((tmp & 0x80000000 ) == 0) { + tmp <<=1 ; + index_msb--; + } + if (index_lsb != index_msb ) + index_msb++; + phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb); printk(KERN_INFO "CPU: Physical Processor ID: %d\n", phys_proc_id[cpu]); --- linux-2.6.1-rc1/arch/i386/kernel/dmi_scan.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/i386/kernel/dmi_scan.c 2004-01-04 22:16:26.000000000 -0800 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ EXPORT_SYMBOL(dmi_broken); int is_sony_vaio_laptop; int is_unsafe_smbus; +int es7000_plat = 0; struct dmi_header { @@ -107,15 +109,7 @@ static int __init dmi_iterate(void (*dec u8 buf[15]; u32 fp=0xF0000; -#ifdef CONFIG_SIMNOW - /* - * Skip on x86/64 with simnow. Will eventually go away - * If you see this ifdef in 2.6pre mail me ! - */ - return -1; -#endif - - while( fp < 0xFFFFF) + while (fp < 0xFFFFF) { isa_memcpy_fromio(buf, fp, 15); if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) @@ -504,6 +498,7 @@ static __init int print_if_true(struct d } +#ifdef CONFIG_ACPI_BOOT extern int acpi_disabled, acpi_force; static __init __attribute__((unused)) int acpi_disable(struct dmi_blacklist *d) @@ -518,8 +513,6 @@ static __init __attribute__((unused)) in return 0; } - -#ifdef CONFIG_ACPI_BOOT extern int acpi_ht; /* @@ -542,10 +535,8 @@ static __init __attribute__((unused)) in #ifdef CONFIG_ACPI_PCI static __init int disable_acpi_pci(struct dmi_blacklist *d) { - extern __init void pci_disable_acpi(void) ; - printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", d->ident); - pci_disable_acpi(); + acpi_noirq_set(); return 0; } #endif @@ -1011,6 +1002,7 @@ static __init void dmi_check_blacklist(v printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s); printk(KERN_NOTICE "You can enable it with acpi=force\n"); acpi_disabled = 1; + acpi_ht = 0; } } } --- linux-2.6.1-rc1/arch/i386/kernel/doublefault.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/doublefault.c 2004-01-04 22:21:59.000000000 -0800 @@ -7,12 +7,13 @@ #include #include #include +#include #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) -#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000) +#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START)) static void doublefault_fn(void) { @@ -38,8 +39,8 @@ static void doublefault_fn(void) printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", t->eax, t->ebx, t->ecx, t->edx); - printk("esi = %08lx, edi = %08lx\n", - t->esi, t->edi); + printk("esi = %08lx, edi = %08lx, ebp = %08lx\n", + t->esi, t->edi, t->ebp); } } --- linux-2.6.1-rc1/arch/i386/kernel/efi.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/efi.c 2004-01-04 22:16:27.000000000 -0800 @@ -174,7 +174,7 @@ phys_efi_get_time(efi_time_t *tm, efi_ti return status; } -int inline efi_set_rtc_mmss(unsigned long nowtime) +inline int efi_set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes; efi_status_t status; @@ -207,7 +207,7 @@ int inline efi_set_rtc_mmss(unsigned lon * services have been remapped, therefore, we'll need to call in physical * mode. Note, this call isn't used later, so mark it __init. */ -unsigned long inline __init efi_get_time(void) +inline unsigned long __init efi_get_time(void) { efi_status_t status; efi_time_t eft; --- linux-2.6.1-rc1/arch/i386/kernel/entry.S 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/kernel/entry.S 2004-01-04 22:21:59.000000000 -0800 @@ -43,11 +43,25 @@ #include #include #include +#include #include #include +#include #include #include #include "irq_vectors.h" + /* We do not recover from a stack overflow, but at least + * we know it happened and should be able to track it down. + */ +#ifdef CONFIG_STACK_OVERFLOW_TEST +#define STACK_OVERFLOW_TEST \ + testl $7680,%esp; \ + jnz 10f; \ + call stack_overflow; \ +10: +#else +#define STACK_OVERFLOW_TEST +#endif #define nr_syscalls ((syscall_table_size)/4) @@ -87,7 +101,102 @@ TSS_ESP0_OFFSET = (4 - 0x200) #define resume_kernel restore_all #endif -#define SAVE_ALL \ +#ifdef CONFIG_X86_HIGH_ENTRY + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) +/* + * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu, + * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is + * left stale, so we must check whether to repeat the real stack calculation. + */ +#define repeat_if_esp_changed \ + xorl %esp, %ebp; \ + testl $0xffffe000, %ebp; \ + jnz 0b +#else +#define repeat_if_esp_changed +#endif + +/* clobbers ebx, edx and ebp */ + +#define __SWITCH_KERNELSPACE \ + cmpl $0xff000000, %esp; \ + jb 1f; \ + \ + /* \ + * switch pagetables and load the real stack, \ + * keep the stack offset: \ + */ \ + \ + movl $swapper_pg_dir-__PAGE_OFFSET, %edx; \ + \ + /* GET_THREAD_INFO(%ebp) intermixed */ \ +0: \ + movl %esp, %ebp; \ + movl %esp, %ebx; \ + andl $0xffffe000, %ebp; \ + andl $0x00001fff, %ebx; \ + orl TI_real_stack(%ebp), %ebx; \ + repeat_if_esp_changed; \ + \ + movl %edx, %cr3; \ + movl %ebx, %esp; \ +1: + +#endif + + +#define __SWITCH_USERSPACE \ + /* interrupted any of the user return paths? */ \ + \ + movl EIP(%esp), %eax; \ + \ + cmpl $int80_ret_start_marker, %eax; \ + jb 33f; /* nope - continue with sysexit check */\ + cmpl $int80_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ +33: \ + cmpl $sysexit_ret_start_marker, %eax; \ + jb 44f; /* nope - continue with user check */ \ + cmpl $sysexit_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ + /* return to userspace? */ \ +44: \ + movl EFLAGS(%esp),%ecx; \ + movb CS(%esp),%cl; \ + testl $(VM_MASK | 3),%ecx; \ + jz 2f; \ +22: \ + /* \ + * switch to the virtual stack, then switch to \ + * the userspace pagetables. \ + */ \ + \ + GET_THREAD_INFO(%ebp); \ + movl TI_virtual_stack(%ebp), %edx; \ + movl TI_user_pgd(%ebp), %ecx; \ + \ + movl %esp, %ebx; \ + andl $0x1fff, %ebx; \ + orl %ebx, %edx; \ +int80_ret_start_marker: \ + movl %edx, %esp; \ + movl %ecx, %cr3; \ + \ + __RESTORE_ALL; \ +int80_ret_end_marker: \ +2: + +#else /* !CONFIG_X86_HIGH_ENTRY */ + +#define __SWITCH_KERNELSPACE +#define __SWITCH_USERSPACE + +#endif + +#define __SAVE_ALL \ cld; \ pushl %es; \ pushl %ds; \ @@ -102,7 +211,7 @@ TSS_ESP0_OFFSET = (4 - 0x200) movl %edx, %ds; \ movl %edx, %es; -#define RESTORE_INT_REGS \ +#define __RESTORE_INT_REGS \ popl %ebx; \ popl %ecx; \ popl %edx; \ @@ -111,29 +220,28 @@ TSS_ESP0_OFFSET = (4 - 0x200) popl %ebp; \ popl %eax -#define RESTORE_REGS \ - RESTORE_INT_REGS; \ -1: popl %ds; \ -2: popl %es; \ +#define __RESTORE_REGS \ + __RESTORE_INT_REGS; \ +111: popl %ds; \ +222: popl %es; \ .section .fixup,"ax"; \ -3: movl $0,(%esp); \ - jmp 1b; \ -4: movl $0,(%esp); \ - jmp 2b; \ +444: movl $0,(%esp); \ + jmp 111b; \ +555: movl $0,(%esp); \ + jmp 222b; \ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,3b; \ - .long 2b,4b; \ + .long 111b,444b;\ + .long 222b,555b;\ .previous - -#define RESTORE_ALL \ - RESTORE_REGS \ +#define __RESTORE_ALL \ + __RESTORE_REGS \ addl $4, %esp; \ -1: iret; \ +333: iret; \ .section .fixup,"ax"; \ -2: sti; \ +666: sti; \ movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ @@ -142,10 +250,19 @@ TSS_ESP0_OFFSET = (4 - 0x200) .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,2b; \ + .long 333b,666b;\ .previous +#define SAVE_ALL \ + __SAVE_ALL; \ + __SWITCH_KERNELSPACE; \ + STACK_OVERFLOW_TEST; + +#define RESTORE_ALL \ + __SWITCH_USERSPACE; \ + __RESTORE_ALL; +.section .entry.text,"ax" ENTRY(lcall7) pushfl # We get a different stack layout with call @@ -163,7 +280,7 @@ do_lcall: movl %edx,EIP(%ebp) # Now we move them to their "normal" places movl %ecx,CS(%ebp) # andl $-8192, %ebp # GET_THREAD_INFO - movl TI_EXEC_DOMAIN(%ebp), %edx # Get the execution domain + movl TI_exec_domain(%ebp), %edx # Get the execution domain call *4(%edx) # Call the lcall7 handler for the domain addl $4, %esp popl %eax @@ -208,7 +325,7 @@ ENTRY(resume_userspace) cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? jne work_pending @@ -216,18 +333,18 @@ ENTRY(resume_userspace) #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) - cmpl $0,TI_PRE_COUNT(%ebp) # non-zero preempt_count ? + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? jnz restore_all need_resched: - movl TI_FLAGS(%ebp), %ecx # need_resched set ? + movl TI_flags(%ebp), %ecx # need_resched set ? testb $_TIF_NEED_RESCHED, %cl jz restore_all testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ? jz restore_all - movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp) + movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp) sti call schedule - movl $0,TI_PRE_COUNT(%ebp) + movl $0,TI_preempt_count(%ebp) cli jmp need_resched #endif @@ -246,37 +363,50 @@ sysenter_past_esp: pushl $(__USER_CS) pushl $SYSENTER_RETURN -/* - * Load the potential sixth argument from user stack. - * Careful about security. - */ - cmpl $__PAGE_OFFSET-3,%ebp - jae syscall_fault -1: movl (%ebp),%ebp -.section __ex_table,"a" - .align 4 - .long 1b,syscall_fault -.previous - pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) cmpl $(nr_syscalls), %eax jae syscall_badsys - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) cli - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + + GET_THREAD_INFO(%ebp) + movl TI_virtual_stack(%ebp), %edx + movl TI_user_pgd(%ebp), %ecx + movl %esp, %ebx + andl $0x1fff, %ebx + orl %ebx, %edx +sysexit_ret_start_marker: + movl %edx, %esp + movl %ecx, %cr3 +#endif + /* + * only ebx is not restored by the userspace sysenter vsyscall + * code, it assumes it to be callee-saved. + */ + movl EBX(%esp), %ebx + /* if something modifies registers it must also disable sysexit */ + movl EIP(%esp), %edx movl OLDESP(%esp), %ecx + sti sysexit +#ifdef CONFIG_X86_SWITCH_PAGETABLES +sysexit_ret_end_marker: + nop +#endif # system call handler stub @@ -287,7 +417,7 @@ ENTRY(system_call) cmpl $(nr_syscalls), %eax jae syscall_badsys # system call tracing in operation - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry syscall_call: call *sys_call_table(,%eax,4) @@ -296,10 +426,23 @@ syscall_exit: cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work restore_all: +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS + movl EFLAGS(%esp), %eax # mix EFLAGS and CS + movb CS(%esp), %al + testl $(VM_MASK | 3), %eax + jz resume_kernelX # returning to kernel or vm86-space + + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jz resume_kernelX + + int $3 + +resume_kernelX: +#endif RESTORE_ALL # perform work that needs to be done immediately before resumption @@ -312,7 +455,7 @@ work_resched: cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done other # than syscall tracing? jz restore_all @@ -327,6 +470,22 @@ work_notifysig: # deal with pending s # vm86-space xorl %edx, %edx call do_notify_resume + +#if CONFIG_X86_HIGH_ENTRY + /* + * Reload db7 if necessary: + */ + movl TI_flags(%ebp), %ecx + testb $_TIF_DB7, %cl + jnz work_db7 + + jmp restore_all + +work_db7: + movl TI_task(%ebp), %edx; + movl task_thread_db7(%edx), %edx; + movl %edx, %db7; +#endif jmp restore_all ALIGN @@ -382,7 +541,7 @@ syscall_badsys: */ .data ENTRY(interrupt) -.text +.previous vector=0 ENTRY(irq_entries_start) @@ -392,7 +551,7 @@ ENTRY(irq_entries_start) jmp common_interrupt .data .long 1b -.text +.previous vector=vector+1 .endr @@ -433,12 +592,17 @@ error_code: movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) - movl %esp, %edx pushl %esi # push the error code - pushl %edx # push the pt_regs pointer movl $(__USER_DS), %edx movl %edx, %ds movl %edx, %es + +/* clobbers edx, ebx and ebp */ + __SWITCH_KERNELSPACE + + leal 4(%esp), %edx # prepare pt_regs + pushl %edx # push pt_regs + call *%edi addl $8, %esp jmp ret_from_exception @@ -529,7 +693,7 @@ nmi_stack_correct: pushl %edx call do_nmi addl $8, %esp - RESTORE_ALL + jmp restore_all nmi_stack_fixup: FIX_STACK(12,nmi_stack_correct, 1) @@ -606,6 +770,8 @@ ENTRY(spurious_interrupt_bug) pushl $do_spurious_interrupt_bug jmp error_code +.previous + .data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/kernel/entry_trampoline.c 2004-01-04 22:21:59.000000000 -0800 @@ -0,0 +1,75 @@ +/* + * linux/arch/i386/kernel/entry_trampoline.c + * + * (C) Copyright 2003 Ingo Molnar + * + * This file contains the needed support code for 4GB userspace + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text; + +void __init init_entry_mappings(void) +{ +#ifdef CONFIG_X86_HIGH_ENTRY + void *tramp; + + /* + * We need a high IDT and GDT for the 4G/4G split: + */ + trap_init_virtual_IDT(); + + __set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL); + __set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL); + tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0); + + printk("mapped 4G/4G trampoline to %p.\n", tramp); + BUG_ON((void *)&__start___entry_text != tramp); + /* + * Virtual kernel stack: + */ + BUG_ON(__kmap_atomic_vaddr(KM_VSTACK0) & 8191); + BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE); + BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE); + + /* + * set up the initial thread's virtual stack related + * fields: + */ + current->thread.stack_page0 = virt_to_page((char *)current->thread_info); + current->thread.stack_page1 = virt_to_page((char *)current->thread_info + PAGE_SIZE); + current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0); + + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(current->thread.stack_page0, KM_VSTACK0); + __kmap_atomic(current->thread.stack_page1, KM_VSTACK1); + +#endif + printk("current: %p\n", current); + printk("current->thread_info: %p\n", current->thread_info); + current->thread_info->real_stack = (void *)current->thread_info; + current->thread_info->user_pgd = NULL; + current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE; +} + + + +void __init entry_trampoline_setup(void) +{ + /* + * old IRQ entries set up by the boot code will still hang + * around - they are a sign of hw trouble anyway, now they'll + * produce a double fault message. + */ + trap_init_virtual_GDT(); +} --- linux-2.6.1-rc1/arch/i386/kernel/head.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/head.S 2004-01-04 22:21:59.000000000 -0800 @@ -16,6 +16,7 @@ #include #include #include +#include #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -330,7 +331,7 @@ ENTRY(stack_start) /* This is the default interrupt "handler" :-) */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt or fault at EIP %p %p %p\n" ALIGN ignore_int: cld @@ -342,9 +343,17 @@ ignore_int: movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es + pushl 16(%esp) + pushl 24(%esp) + pushl 32(%esp) + pushl 40(%esp) pushl $int_msg call printk popl %eax + popl %eax + popl %eax + popl %eax + popl %eax popl %ds popl %es popl %edx @@ -377,23 +386,27 @@ cpu_gdt_descr: .fill NR_CPUS-1,8,0 # space for the other GDT descriptors /* - * This is initialized to create an identity-mapping at 0-8M (for bootup - * purposes) and another mapping of the 0-8M area at virtual address + * This is initialized to create an identity-mapping at 0-16M (for bootup + * purposes) and another mapping of the 0-16M area at virtual address * PAGE_OFFSET. */ .org 0x1000 ENTRY(swapper_pg_dir) .long 0x00102007 .long 0x00103007 - .fill BOOT_USER_PGD_PTRS-2,4,0 - /* default: 766 entries */ + .long 0x00104007 + .long 0x00105007 + .fill BOOT_USER_PGD_PTRS-4,4,0 + /* default: 764 entries */ .long 0x00102007 .long 0x00103007 - /* default: 254 entries */ - .fill BOOT_KERNEL_PGD_PTRS-2,4,0 + .long 0x00104007 + .long 0x00105007 + /* default: 252 entries */ + .fill BOOT_KERNEL_PGD_PTRS-4,4,0 /* - * The page tables are initialized to only 8MB here - the final page + * The page tables are initialized to only 16MB here - the final page * tables are set up later depending on memory size. */ .org 0x2000 @@ -402,15 +415,21 @@ ENTRY(pg0) .org 0x3000 ENTRY(pg1) +.org 0x4000 +ENTRY(pg2) + +.org 0x5000 +ENTRY(pg3) + /* * empty_zero_page must immediately follow the page tables ! (The * initialization loop counts until empty_zero_page) */ -.org 0x4000 +.org 0x6000 ENTRY(empty_zero_page) -.org 0x5000 +.org 0x7000 /* * Real beginning of normal "text" segment @@ -419,12 +438,12 @@ ENTRY(stext) ENTRY(_stext) /* - * This starts the data section. Note that the above is all - * in the text section because it has alignment requirements - * that we cannot fulfill any other way. + * This starts the data section. */ .data +.align PAGE_SIZE_asm + /* * The Global Descriptor Table contains 28 quadwords, per-CPU. */ @@ -439,7 +458,9 @@ ENTRY(boot_gdt_table) .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ #endif - .align L1_CACHE_BYTES + +.align PAGE_SIZE_asm + ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ --- linux-2.6.1-rc1/arch/i386/kernel/i386_ksyms.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/i386_ksyms.c 2004-01-04 22:21:59.000000000 -0800 @@ -98,7 +98,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed_inter EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__udelay); @@ -112,13 +111,17 @@ EXPORT_SYMBOL_NOVERS(__get_user_4); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +#if !defined(CONFIG_X86_UACCESS_INDIRECT) EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__direct_strncpy_from_user); EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__copy_from_user_ll); EXPORT_SYMBOL(__copy_to_user_ll); EXPORT_SYMBOL(strnlen_user); +#else /* CONFIG_X86_UACCESS_INDIRECT */ +EXPORT_SYMBOL(direct_csum_partial_copy_generic); +#endif EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_free_coherent); --- linux-2.6.1-rc1/arch/i386/kernel/i387.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/i387.c 2004-01-04 22:21:59.000000000 -0800 @@ -218,6 +218,7 @@ void set_fpu_mxcsr( struct task_struct * static int convert_fxsr_to_user( struct _fpstate __user *buf, struct i387_fxsave_struct *fxsave ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpreg __user *to; struct _fpxreg *from; @@ -234,23 +235,25 @@ static int convert_fxsr_to_user( struct if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; - to = &buf->_st[0]; + to = tmp; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f+1); + to->exponent = from->exponent; } + if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8]))) + return 1; return 0; } static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpxreg *to; struct _fpreg __user *from; @@ -258,6 +261,8 @@ static int convert_fxsr_from_user( struc if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; + if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8]))) + return 1; fxsave->cwd = (unsigned short)(env[0] & 0xffff); fxsave->swd = (unsigned short)(env[1] & 0xffff); @@ -269,15 +274,14 @@ static int convert_fxsr_from_user( struc fxsave->fos = env[6]; to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; + from = tmp; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f + 1); + to->exponent = from->exponent; } return 0; } --- linux-2.6.1-rc1/arch/i386/kernel/init_task.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/init_task.c 2004-01-04 22:21:59.000000000 -0800 @@ -26,7 +26,7 @@ EXPORT_SYMBOL(init_mm); */ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; + { INIT_THREAD_INFO(init_task, init_thread_union) }; /* * Initial task structure. @@ -44,5 +44,5 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS }; --- linux-2.6.1-rc1/arch/i386/kernel/io_apic.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/io_apic.c 2004-01-04 22:15:28.000000000 -0800 @@ -1650,10 +1650,6 @@ static void __init setup_ioapic_ids_from unsigned char old_id; unsigned long flags; - if (acpi_ioapic) - /* This gets done during IOAPIC enumeration for ACPI. */ - return; - /* * This is broken; anything with a real cpu count has to * circumvent this idiocy regardless. @@ -2286,12 +2282,14 @@ void __init setup_IO_APIC(void) /* * Set up IO-APIC IRQ routing. */ - setup_ioapic_ids_from_mpc(); + if (!acpi_ioapic) + setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); - print_IO_APIC(); + if (!acpi_ioapic) + print_IO_APIC(); } /* --- linux-2.6.1-rc1/arch/i386/kernel/irq.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/irq.c 2004-01-04 17:36:35.000000000 -0800 @@ -508,6 +508,8 @@ out: irq_exit(); + kgdb_process_breakpoint(); + return 1; } --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/kernel/kgdb_stub.c 2004-01-04 17:36:35.000000000 -0800 @@ -0,0 +1,2457 @@ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (c) 2000 VERITAS Software Corporation. + * + */ +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * Updated by: David Grothe + * Updated by: Robert Walsh + * Updated by: wangdi + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Compatibility with 2.1.xx kernel by David Grothe + * + * Changes to allow auto initilization. All that is needed is that it + * be linked with the kernel and a break point (int 3) be executed. + * The header file defines BREAKPOINT to allow one to do + * this. It should also be possible, once the interrupt system is up, to + * call putDebugChar("+"). Once this is done, the remote debugger should + * get our attention by sending a ^C in a packet. George Anzinger + * + * Integrated into 2.2.5 kernel by Tigran Aivazian + * Added thread support, support for multiple processors, + * support for ia-32(x86) hardware debugging. + * Amit S. Kale ( akale@veritas.com ) + * + * Modified to support debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing an int 3. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ +#define KGDB_VERSION "<20030915.1651.33>" +#include +#include +#include /* for strcpy */ +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*Function) (void); /* pointer to a function */ + +/* Thread reference */ +typedef unsigned char threadref[8]; + +extern int tty_putDebugChar(int); /* write a single character */ +extern int tty_getDebugChar(void); /* read and return a single char */ +extern void tty_flushDebugChar(void); /* flush pending characters */ +extern int eth_putDebugChar(int); /* write a single character */ +extern int eth_getDebugChar(void); /* read and return a single char */ +extern void eth_flushDebugChar(void); /* flush pending characters */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 400 + +char *kgdb_version = KGDB_VERSION; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int debug_regs = 0; /* set to non-zero to print registers */ + +/* filled in by an external module */ +char *gdb_module_offsets; + +static const char hexchars[] = "0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES 64 +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + */ +enum regnames { _EAX, /* 0 */ + _ECX, /* 1 */ + _EDX, /* 2 */ + _EBX, /* 3 */ + _ESP, /* 4 */ + _EBP, /* 5 */ + _ESI, /* 6 */ + _EDI, /* 7 */ + _PC /* 8 also known as eip */ , + _PS /* 9 also known as eflags */ , + _CS, /* 10 */ + _SS, /* 11 */ + _DS, /* 12 */ + _ES, /* 13 */ + _FS, /* 14 */ + _GS /* 15 */ +}; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* + * Put the error code here just in case the user cares. + * Likewise, the vector number here (since GDB only gets the signal + * number through the usual means, and that's not very specific). + * The called_from is the return address so he can tell how we entered kgdb. + * This will allow him to seperate out the various possible entries. + */ +#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ + +#define PID_MAX PID_MAX_DEFAULT + +#ifdef CONFIG_SMP +void smp_send_nmi_allbutself(void); +#define IF_SMP(x) x +#undef MAX_NO_CPUS +#ifndef CONFIG_NO_KGDB_CPUS +#define CONFIG_NO_KGDB_CPUS 2 +#endif +#if CONFIG_NO_KGDB_CPUS > NR_CPUS +#define MAX_NO_CPUS NR_CPUS +#else +#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS +#endif +#define hold_init hold_on_sstep: 1, +#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) +#define NUM_CPUS num_online_cpus() +#else +#define IF_SMP(x) +#define hold_init +#undef MAX_NO_CPUS +#define MAX_NO_CPUS 1 +#define NUM_CPUS 1 +#endif +#define NOCPU (struct task_struct *)0xbad1fbad +/* *INDENT-OFF* */ +struct kgdb_info { + int used_malloc; + void *called_from; + long long entry_tsc; + int errcode; + int vector; + int print_debug_info; +#ifdef CONFIG_SMP + int hold_on_sstep; + struct { + volatile struct task_struct *task; + int pid; + int hold; + struct pt_regs *regs; + } cpus_waiting[MAX_NO_CPUS]; +#endif +} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1}; + +/* *INDENT-ON* */ + +#define used_m kgdb_info.used_malloc +/* + * This is little area we set aside to contain the stack we + * need to build to allow gdb to call functions. We use one + * per cpu to avoid locking issues. We will do all this work + * with interrupts off so that should take care of the protection + * issues. + */ +#define LOOKASIDE_SIZE 200 /* should be more than enough */ +#define MALLOC_MAX 200 /* Max malloc size */ +struct { + unsigned int esp; + int array[LOOKASIDE_SIZE]; +} fn_call_lookaside[MAX_NO_CPUS]; + +static int trap_cpu; +static unsigned int OLD_esp; + +#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE] +#define IF_BIT 0x200 +#define TF_BIT 0x100 + +#define MALLOC_ROUND 8-1 + +static char malloc_array[MALLOC_MAX]; +IF_SMP(static void to_gdb(const char *mess)); +void * +malloc(int size) +{ + + if (size <= (MALLOC_MAX - used_m)) { + int old_used = used_m; + used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); + return &malloc_array[old_used]; + } else { + return NULL; + } +} + +/* + * I/O dispatch functions... + * Based upon kgdboe, either call the ethernet + * handler or the serial one.. + */ +void +putDebugChar(int c) +{ + if (!kgdboe) { + tty_putDebugChar(c); + } else { + eth_putDebugChar(c); + } +} + +int +getDebugChar(void) +{ + if (!kgdboe) { + return tty_getDebugChar(); + } else { + return eth_getDebugChar(); + } +} + +void +flushDebugChar(void) +{ + if (!kgdboe) { + tty_flushDebugChar(); + } else { + eth_flushDebugChar(); + } +} + +/* + * Gdb calls functions by pushing agruments, including a return address + * on the stack and the adjusting EIP to point to the function. The + * whole assumption in GDB is that we are on a different stack than the + * one the "user" i.e. code that hit the break point, is on. This, of + * course is not true in the kernel. Thus various dodges are needed to + * do the call without directly messing with EIP (which we can not change + * as it is just a location and not a register. To adjust it would then + * require that we move every thing below EIP up or down as needed. This + * will not work as we may well have stack relative pointer on the stack + * (such as the pointer to regs, for example). + + * So here is what we do: + * We detect gdb attempting to store into the stack area and instead, store + * into the fn_call_lookaside.array at the same relative location as if it + * were the area ESP pointed at. We also trap ESP modifications + * and uses these to adjust fn_call_lookaside.esp. On entry + * fn_call_lookaside.esp will be set to point at the last entry in + * fn_call_lookaside.array. This allows us to check if it has changed, and + * if so, on exit, we add the registers we will use to do the move and a + * trap/ interrupt return exit sequence. We then adjust the eflags in the + * regs array (remember we now have a copy in the fn_call_lookaside.array) to + * kill the interrupt bit, AND we change EIP to point at our set up stub. + * As part of the register set up we preset the registers to point at the + * begining and end of the fn_call_lookaside.array, so all the stub needs to + * do is move words from the array to the stack until ESP= the desired value + * then do the rti. This will then transfer to the desired function with + * all the correct registers. Nifty huh? + */ +extern asmlinkage void fn_call_stub(void); +extern asmlinkage void fn_rtn_stub(void); +/* *INDENT-OFF* */ +__asm__("fn_rtn_stub:\n\t" + "movl %eax,%esp\n\t" + "fn_call_stub:\n\t" + "1:\n\t" + "addl $-4,%ebx\n\t" + "movl (%ebx), %eax\n\t" + "pushl %eax\n\t" + "cmpl %esp,%ecx\n\t" + "jne 1b\n\t" + "popl %eax\n\t" + "popl %ebx\n\t" + "popl %ecx\n\t" + "iret \n\t"); +/* *INDENT-ON* */ +#define gdb_i386vector kgdb_info.vector +#define gdb_i386errcode kgdb_info.errcode +#define waiting_cpus kgdb_info.cpus_waiting +#define remote_debug kgdb_info.print_debug_info +#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold +/* gdb locks */ + +#ifdef CONFIG_SMP +static int in_kgdb_called; +static spinlock_t waitlocks[MAX_NO_CPUS] = + {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; +/* + * The following array has the thread pointer of each of the "other" + * cpus. We make it global so it can be seen by gdb. + */ +volatile int in_kgdb_entry_log[MAX_NO_CPUS]; +volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; +/* +static spinlock_t continuelocks[MAX_NO_CPUS]; +*/ +spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; +/* waiters on our spinlock plus us */ +static atomic_t spinlock_waiters = ATOMIC_INIT(1); +static int spinlock_count = 0; +static int spinlock_cpu = 0; +/* + * Note we use nested spin locks to account for the case where a break + * point is encountered when calling a function by user direction from + * kgdb. Also there is the memory exception recursion to account for. + * Well, yes, but this lets other cpus thru too. Lets add a + * cpu id to the lock. + */ +#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ + spinlock_cpu != smp_processor_id()){\ + atomic_inc(&spinlock_waiters); \ + while (! spin_trylock(x)) {\ + in_kgdb(®s);\ + }\ + atomic_dec(&spinlock_waiters); \ + spinlock_count = 1; \ + spinlock_cpu = smp_processor_id(); \ + }else{ \ + spinlock_count++; \ + } +#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) +#else +unsigned kgdb_spinlock = 0; +#define KGDB_SPIN_LOCK(x) --*x +#define KGDB_SPIN_UNLOCK(x) ++*x +#endif + +int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug) && (checksum != xmitcsum)) { + printk + ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + + if (remote_debug) + printk("R:%s\n", buffer); + flushDebugChar(); +} + +/* send the packet in buffer. */ + +void +putpacket(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + + if (!kgdboe) { + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + + } while ((getDebugChar() & 0x7f) != '+'); + } else { + /* + * For udp, we can not transfer too much bytes once. + * We only transfer MAX_SEND_COUNT size bytes each time + */ + +#define MAX_SEND_COUNT 30 + + int send_count = 0, i = 0; + char send_buf[MAX_SEND_COUNT]; + + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + send_count = 0; + while ((ch = buffer[count])) { + if (send_count >= MAX_SEND_COUNT) { + for(i = 0; i < MAX_SEND_COUNT; i++) { + putDebugChar(send_buf[i]); + } + flushDebugChar(); + send_count = 0; + } else { + send_buf[send_count] = ch; + checksum += ch; + count ++; + send_count++; + } + } + for(i = 0; i < send_count; i++) + putDebugChar(send_buf[i]); + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + } while ((getDebugChar() & 0x7f) != '+'); + } +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static short error; + +void +debug_error(char *format, char *parm) +{ + if (remote_debug) + printk(format, parm); +} + +static void +print_regs(struct pt_regs *regs) +{ + printk("EAX=%08lx ", regs->eax); + printk("EBX=%08lx ", regs->ebx); + printk("ECX=%08lx ", regs->ecx); + printk("EDX=%08lx ", regs->edx); + printk("\n"); + printk("ESI=%08lx ", regs->esi); + printk("EDI=%08lx ", regs->edi); + printk("EBP=%08lx ", regs->ebp); + printk("ESP=%08lx ", (long) ®s->esp); + printk("\n"); + printk(" DS=%08x ", regs->xds); + printk(" ES=%08x ", regs->xes); + printk(" SS=%08x ", __KERNEL_DS); + printk(" FL=%08lx ", regs->eflags); + printk("\n"); + printk(" CS=%08x ", regs->xcs); + printk(" IP=%08lx ", regs->eip); +#if 0 + printk(" FS=%08x ", regs->fs); + printk(" GS=%08x ", regs->gs); +#endif + printk("\n"); + +} /* print_regs */ + +#define NEW_esp fn_call_lookaside[trap_cpu].esp + +static void +regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_EAX] = regs->eax; + gdb_regs[_EBX] = regs->ebx; + gdb_regs[_ECX] = regs->ecx; + gdb_regs[_EDX] = regs->edx; + gdb_regs[_ESI] = regs->esi; + gdb_regs[_EDI] = regs->edi; + gdb_regs[_EBP] = regs->ebp; + gdb_regs[_DS] = regs->xds; + gdb_regs[_ES] = regs->xes; + gdb_regs[_PS] = regs->eflags; + gdb_regs[_CS] = regs->xcs; + gdb_regs[_PC] = regs->eip; + /* Note, as we are a debugging the kernel, we will always + * trap in kernel code, this means no priviledge change, + * and so the pt_regs structure is not completely valid. In a non + * privilege change trap, only EFLAGS, CS and EIP are put on the stack, + * SS and ESP are not stacked, this means that the last 2 elements of + * pt_regs is not valid (they would normally refer to the user stack) + * also, using regs+1 is no good because you end up will a value that is + * 2 longs (8) too high. This used to cause stepping over functions + * to fail, so my fix is to use the address of regs->esp, which + * should point at the end of the stack frame. Note I have ignored + * completely exceptions that cause an error code to be stacked, such + * as double fault. Stuart Hughes, Zentropix. + * original code: gdb_regs[_ESP] = (int) (regs + 1) ; + + * this is now done on entry and moved to OLD_esp (as well as NEW_esp). + */ + gdb_regs[_ESP] = NEW_esp; + gdb_regs[_SS] = __KERNEL_DS; + gdb_regs[_FS] = 0xFFFF; + gdb_regs[_GS] = 0xFFFF; +} /* regs_to_gdb_regs */ + +static void +gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs) +{ + regs->eax = gdb_regs[_EAX]; + regs->ebx = gdb_regs[_EBX]; + regs->ecx = gdb_regs[_ECX]; + regs->edx = gdb_regs[_EDX]; + regs->esi = gdb_regs[_ESI]; + regs->edi = gdb_regs[_EDI]; + regs->ebp = gdb_regs[_EBP]; + regs->xds = gdb_regs[_DS]; + regs->xes = gdb_regs[_ES]; + regs->eflags = gdb_regs[_PS]; + regs->xcs = gdb_regs[_CS]; + regs->eip = gdb_regs[_PC]; + NEW_esp = gdb_regs[_ESP]; /* keep the value */ +#if 0 /* can't change these */ + regs->esp = gdb_regs[_ESP]; + regs->xss = gdb_regs[_SS]; + regs->fs = gdb_regs[_FS]; + regs->gs = gdb_regs[_GS]; +#endif + +} /* gdb_regs_to_regs */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +int thread_list = 0; + +void +get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs) +{ + unsigned long stack_page; + int count = 0; + IF_SMP(int i); + if (!p || p == current) { + regs_to_gdb_regs(gdb_regs, regs); + return; + } +#ifdef CONFIG_SMP + for (i = 0; i < MAX_NO_CPUS; i++) { + if (p == kgdb_info.cpus_waiting[i].task) { + regs_to_gdb_regs(gdb_regs, + kgdb_info.cpus_waiting[i].regs); + gdb_regs[_ESP] = + (int) &kgdb_info.cpus_waiting[i].regs->esp; + + return; + } + } +#endif + memset(gdb_regs, 0, NUMREGBYTES); + gdb_regs[_ESP] = p->thread.esp; + gdb_regs[_PC] = p->thread.eip; + gdb_regs[_EBP] = *(int *) gdb_regs[_ESP]; + gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4); + gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8); + +/* + * This code is to give a more informative notion of where a process + * is waiting. It is used only when the user asks for a thread info + * list. If he then switches to the thread, s/he will find the task + * is in schedule, but a back trace should show the same info we come + * up with. This code was shamelessly purloined from process.c. It was + * then enhanced to provide more registers than simply the program + * counter. + */ + + if (!thread_list) { + return; + } + + if (p->state == TASK_RUNNING) + return; + stack_page = (unsigned long) p->thread_info; + if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > 8188 + stack_page) + return; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + do { + if (gdb_regs[_EBP] < stack_page || + gdb_regs[_EBP] > 8184 + stack_page) + return; + gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4); + gdb_regs[_ESP] = gdb_regs[_EBP] + 8; + gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP]; + if (gdb_regs[_PC] < first_sched || gdb_regs[_PC] >= last_sched) + return; + } while (count++ < 16); + return; +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; +static volatile int mem_err_expected = 0; +static volatile int mem_err_cnt = 0; +static int garbage_loc = -1; + +int +get_char(char *addr) +{ + return *addr; +} + +void +set_char(char *addr, int val, int may_fault) +{ + /* + * This code traps references to the area mapped to the kernel + * stack as given by the regs and, instead, stores to the + * fn_call_lookaside[cpu].array + */ + if (may_fault && + (unsigned int) addr < OLD_esp && + ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) { + addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr); + } + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex(char *mem, char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + /* printk("%lx = ", mem) ; */ + + ch = get_char(mem++); + + /* printk("%02x\n", ch & 0xFF) ; */ + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault fetching from addr %lx\n", + (long) (mem - 1)); + *buf = 0; /* truncate buffer */ + return (buf); + } + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_err_expected = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +/* NOTE: We use the may fault flag to also indicate if the write is to + * the registers (0) or "other" memory (!=0) + */ +char * +hex2mem(char *buf, char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + set_char(mem++, ch, may_fault); + + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault storing to addr %lx\n", + (long) (mem - 1)); + return (mem); + } + } + if (may_fault) + mem_err_expected = 0; + return (mem); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define stubhex(h) hex(h) +#ifdef old_thread_list + +static int +stub_unpack_int(char *buff, int fieldlength) +{ + int nibble; + int retval = 0; + + while (fieldlength) { + nibble = stubhex(*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} +#endif +static char * +pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +#define BUF_THREAD_ID_SIZE 16 + +static char * +pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + return pkt; +} + +#ifdef old_thread_list +static char * +unpack_byte(char *buf, int *value) +{ + *value = stub_unpack_int(buf, 2); + return buf + 2; +} + +static char * +unpack_threadid(char *inbuf, threadref * id) +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + + altref = (char *) id; + + while (inbuf < limit) { + x = stubhex(*inbuf++); + y = stubhex(*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} +#endif +void +int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} +int +int_to_hex_v(unsigned char * id, int value) +{ + unsigned char *start = id; + int shift; + int ch; + + for (shift = 28; shift >= 0; shift -= 4) { + if ((ch = (value >> shift) & 0xf) || (id != start)) { + *id = hexchars[ch]; + id++; + } + } + if (id == start) + *id++ = '0'; + return id - start; +} +#ifdef old_thread_list + +static int +threadref_to_int(threadref * ref) +{ + int i, value = 0; + unsigned char *scan; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} +#endif +static int +cmp_str(char *s1, char *s2, int count) +{ + while (count--) { + if (*s1++ != *s2++) + return 0; + } + return 1; +} + +#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ +extern struct task_struct *kgdb_get_idle(int cpu); +#define idle_task(cpu) kgdb_get_idle(cpu) +#else +#define idle_task(cpu) init_tasks[cpu] +#endif + +extern int kgdb_pid_init_done; + +struct task_struct * +getthread(int pid) +{ + struct task_struct *thread; + if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { + + return idle_task(pid - PID_MAX); + } else { + /* + * find_task_by_pid is relatively safe all the time + * Other pid functions require lock downs which imply + * that we may be interrupting them (as we get here + * in the middle of most any lock down). + * Still we don't want to call until the table exists! + */ + if (kgdb_pid_init_done){ + thread = find_task_by_pid(pid); + if (thread) { + return thread; + } + } + } + return NULL; +} +/* *INDENT-OFF* */ +struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned addr; +} breakinfo[4] = { {enabled:0}, + {enabled:0}, + {enabled:0}, + {enabled:0}}; +/* *INDENT-ON* */ +unsigned hw_breakpoint_status; +void +correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned dr7; + + asm volatile ("movl %%db7, %0\n":"=r" (dr7) + :); + /* *INDENT-OFF* */ + do { + unsigned addr0, addr1, addr2, addr3; + asm volatile ("movl %%db0, %0\n" + "movl %%db1, %1\n" + "movl %%db2, %2\n" + "movl %%db3, %3\n" + :"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3) + :); + } while (0); + /* *INDENT-ON* */ + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movl %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movl %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movl %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movl %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) { + asm volatile ("movl %0, %%db7\n"::"r" (dr7)); + } +} + +int +remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 0; + return 0; +} + +int +set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].len = len; + breakinfo[breakno].addr = addr; + return 0; +} + +#ifdef CONFIG_SMP +static int in_kgdb_console = 0; + +int +in_kgdb(struct pt_regs *regs) +{ + unsigned flags; + int cpu = smp_processor_id(); + in_kgdb_called = 1; + if (!spin_is_locked(&kgdb_spinlock)) { + if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ + in_kgdb_console) { /* or we are doing slow i/o */ + return 1; + } + return 0; + } + + /* As I see it the only reason not to let all cpus spin on + * the same spin_lock is to allow selected ones to proceed. + * This would be a good thing, so we leave it this way. + * Maybe someday.... Done ! + + * in_kgdb() is called from an NMI so we don't pretend + * to have any resources, like printk() for example. + */ + + kgdb_local_irq_save(flags); /* only local here, to avoid hanging */ + /* + * log arival of this cpu + * The NMI keeps on ticking. Protect against recurring more + * than once, and ignor the cpu that has the kgdb lock + */ + in_kgdb_entry_log[cpu]++; + in_kgdb_here_log[cpu] = regs; + if (cpu == spinlock_cpu || waiting_cpus[cpu].task) + goto exit_in_kgdb; + + /* + * For protection of the initilization of the spin locks by kgdb + * it locks the kgdb spinlock before it gets the wait locks set + * up. We wait here for the wait lock to be taken. If the + * kgdb lock goes away first?? Well, it could be a slow exit + * sequence where the wait lock is removed prior to the kgdb lock + * so if kgdb gets unlocked, we just exit. + */ + + while (spin_is_locked(&kgdb_spinlock) && + !spin_is_locked(waitlocks + cpu)) ; + if (!spin_is_locked(&kgdb_spinlock)) + goto exit_in_kgdb; + + waiting_cpus[cpu].task = current; + waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); + waiting_cpus[cpu].regs = regs; + + spin_unlock_wait(waitlocks + cpu); + + /* + * log departure of this cpu + */ + waiting_cpus[cpu].task = 0; + waiting_cpus[cpu].pid = 0; + waiting_cpus[cpu].regs = 0; + correct_hw_break(); + exit_in_kgdb: + in_kgdb_here_log[cpu] = 0; + kgdb_local_irq_restore(flags); + return 1; + /* + spin_unlock(continuelocks + smp_processor_id()); + */ +} + +void +smp__in_kgdb(struct pt_regs regs) +{ + ack_APIC_irq(); + in_kgdb(®s); +} +#else +int +in_kgdb(struct pt_regs *regs) +{ + return (kgdb_spinlock); +} +#endif + +void +printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ + unsigned dr6; + int i; + switch (exceptionNo) { + case 1: /* debug exception */ + break; + case 3: /* breakpoint */ + sprintf(buffer, "Software breakpoint"); + return; + default: + sprintf(buffer, "Details not available"); + return; + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (dr6 & 0x4000) { + sprintf(buffer, "Single step"); + return; + } + for (i = 0; i < 4; ++i) { + if (dr6 & (1 << i)) { + sprintf(buffer, "Hardware breakpoint %d", i); + return; + } + } + sprintf(buffer, "Unknown trap"); + return; +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * NOTE: The INT nn instruction leaves the state of the interrupt + * enable flag UNCHANGED. That means that when this routine + * is entered via a breakpoint (INT 3) instruction from code + * that has interrupts enabled, then interrupts will STILL BE + * enabled when this routine is entered. The first thing that + * we do here is disable interrupts so as to prevent recursive + * entries and bothersome serial interrupts while we are + * trying to run the serial port in polled mode. + * + * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so + * it is always necessary to do a restore_flags before returning + * so as to let go of that lock. + */ +int +kgdb_handle_exception(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs) +{ + struct task_struct *usethread = NULL; + struct task_struct *thread_list_start = 0, *thread = NULL; + int addr, length; + int breakno, breaktype; + char *ptr; + int newPC; + threadref thref; + int threadid; + int thread_min = PID_MAX + MAX_NO_CPUS; +#ifdef old_thread_list + int maxthreads; +#endif + int nothreads; + unsigned long flags; + int gdb_regs[NUMREGBYTES / 4]; + int dr6; + IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ +#define NO_NMI 1 +#define NO_SYNC 2 +#define regs (*linux_regs) +#define NUMREGS NUMREGBYTES/4 + /* + * If the entry is not from the kernel then return to the Linux + * trap handler and let it process the interrupt normally. + */ + if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) { + printk("ignoring non-kernel exception\n"); + print_regs(®s); + return (0); + } + /* + * If we're using eth mode, set the 'mode' in the netdevice. + */ + + if (kgdboe) + netpoll_set_trap(1); + + kgdb_local_irq_save(flags); + + /* Get kgdb spinlock */ + + KGDB_SPIN_LOCK(&kgdb_spinlock); + rdtscll(kgdb_info.entry_tsc); + /* + * We depend on this spinlock and the NMI watch dog to control the + * other cpus. They will arrive at "in_kgdb()" as a result of the + * NMI and will wait there for the following spin locks to be + * released. + */ +#ifdef CONFIG_SMP + +#if 0 + if (cpu_callout_map & ~MAX_CPU_MASK) { + printk("kgdb : too many cpus, possibly not mapped" + " in contiguous space, change MAX_NO_CPUS" + " in kgdb_stub and make new kernel.\n" + " cpu_callout_map is %lx\n", cpu_callout_map); + goto exit_just_unlock; + } +#endif + if (spinlock_count == 1) { + int time, end_time, dum; + int i; + int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) + }; + if (remote_debug) { + printk("kgdb : cpu %d entry, syncing others\n", + smp_processor_id()); + } + for (i = 0; i < MAX_NO_CPUS; i++) { + /* + * Use trylock as we may already hold the lock if + * we are holding the cpu. Net result is all + * locked. + */ + spin_trylock(&waitlocks[i]); + } + for (i = 0; i < MAX_NO_CPUS; i++) + cpu_logged_in[i] = 0; + /* + * Wait for their arrival. We know the watch dog is active if + * in_kgdb() has ever been called, as it is always called on a + * watchdog tick. + */ + rdtsc(dum, time); + end_time = time + 2; /* Note: we use the High order bits! */ + i = 1; + if (num_online_cpus() > 1) { + int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; + smp_send_nmi_allbutself(); + + while (i < num_online_cpus() && time != end_time) { + int j; + for (j = 0; j < MAX_NO_CPUS; j++) { + if (waiting_cpus[j].task && + waiting_cpus[j].task != NOCPU && + !cpu_logged_in[j]) { + i++; + cpu_logged_in[j] = 1; + if (remote_debug) { + printk + ("kgdb : cpu %d arrived at kgdb\n", + j); + } + break; + } else if (!waiting_cpus[j].task && + !cpu_online(j)) { + waiting_cpus[j].task = NOCPU; + cpu_logged_in[j] = 1; + waiting_cpus[j].hold = 1; + break; + } + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + + int wait = 100000; + while (wait--) ; + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + printk + ("kgdb : cpu %d stall" + " in in_kgdb\n", + j); + i++; + cpu_logged_in[j] = 1; + waiting_cpus[j].task = + (struct task_struct + *) 1; + } + } + } + + if (in_kgdb_entry_log[smp_processor_id()] > + (me_in_kgdb + 10)) { + break; + } + + rdtsc(dum, time); + } + if (i < num_online_cpus()) { + printk + ("kgdb : time out, proceeding without sync\n"); +#if 0 + printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", + waiting_cpus[0].task != 0, + waiting_cpus[1].task != 0); + printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", + cpu_logged_in[0], cpu_logged_in[1]); + printk + ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", + in_kgdb_here_log[0] != 0, + in_kgdb_here_log[1] != 0); +#endif + entry_state = NO_SYNC; + } else { +#if 0 + int ent = + in_kgdb_entry_log[smp_processor_id()] - + me_in_kgdb; + printk("kgdb : sync after %d entries\n", ent); +#endif + } + } else { + if (remote_debug) { + printk + ("kgdb : %d cpus, but watchdog not active\n" + "proceeding without locking down other cpus\n", + num_online_cpus()); + entry_state = NO_NMI; + } + } + } +#endif + + if (remote_debug) { + unsigned long *lp = (unsigned long *) &linux_regs; + + printk("handle_exception(exceptionVector=%d, " + "signo=%d, err_code=%d, linux_regs=%p)\n", + exceptionVector, signo, err_code, linux_regs); + if (debug_regs) { + print_regs(®s); + printk("Stk: %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[0], lp[1], lp[2], lp[3], + lp[4], lp[5], lp[6], lp[7]); + printk(" %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[8], lp[9], lp[10], lp[11], + lp[12], lp[13], lp[14], lp[15]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[16], lp[17], lp[18], lp[19], + lp[20], lp[21], lp[22], lp[23]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[24], lp[25], lp[26], lp[27], + lp[28], lp[29], lp[30], lp[31]); + } + } + + /* Disable hardware debugging while we are in kgdb */ + /* Get the debug register status register */ +/* *INDENT-OFF* */ + __asm__("movl %0,%%db7" + : /* no output */ + :"r"(0)); + + asm volatile ("movl %%db6, %0\n" + :"=r" (hw_breakpoint_status) + :); + +/* *INDENT-ON* */ + switch (exceptionVector) { + case 0: /* divide error */ + case 1: /* debug exception */ + case 2: /* NMI */ + case 3: /* breakpoint */ + case 4: /* overflow */ + case 5: /* bounds check */ + case 6: /* invalid opcode */ + case 7: /* device not available */ + case 8: /* double fault (errcode) */ + case 10: /* invalid TSS (errcode) */ + case 12: /* stack fault (errcode) */ + case 16: /* floating point error */ + case 17: /* alignment check (errcode) */ + default: /* any undocumented */ + break; + case 11: /* segment not present (errcode) */ + case 13: /* general protection (errcode) */ + case 14: /* page fault (special errcode) */ + case 19: /* cache flush denied */ + if (mem_err_expected) { + /* + * This fault occured because of the + * get_char or set_char routines. These + * two routines use either eax of edx to + * indirectly reference the location in + * memory that they are working with. + * For a page fault, when we return the + * instruction will be retried, so we + * have to make sure that these + * registers point to valid memory. + */ + mem_err = 1; /* set mem error flag */ + mem_err_expected = 0; + mem_err_cnt++; /* helps in debugging */ + /* make valid address */ + regs.eax = (long) &garbage_loc; + /* make valid address */ + regs.edx = (long) &garbage_loc; + if (remote_debug) + printk("Return after memory error: " + "mem_err_cnt=%d\n", mem_err_cnt); + if (debug_regs) + print_regs(®s); + goto exit_kgdb; + } + break; + } + if (remote_debug) + printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); + + gdb_i386vector = exceptionVector; + gdb_i386errcode = err_code; + kgdb_info.called_from = __builtin_return_address(0); +#ifdef CONFIG_SMP + /* + * OK, we can now communicate, lets tell gdb about the sync. + * but only if we had a problem. + */ + switch (entry_state) { + case NO_NMI: + to_gdb("NMI not active, other cpus not stopped\n"); + break; + case NO_SYNC: + to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); + default:; + } + +#endif +/* + * Set up the gdb function call area. + */ + trap_cpu = smp_processor_id(); + OLD_esp = NEW_esp = (int) (&linux_regs->esp); + + IF_SMP(once_again:) + /* reply to host that an exception has occurred */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1 == 1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + printk("Remote debug %s\n", + remote_debug ? "on" : "off"); + break; + case 'g': /* return the value of the CPU registers */ + get_gdb_regs(usethread, ®s, gdb_regs); + mem2hex((char *) gdb_regs, + remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], + (char *) gdb_regs, NUMREGBYTES, 0); + if (!usethread || usethread == current) { + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E00"); + } + break; + + case 'P':{ /* set the value of a single CPU register - + return OK */ + /* + * For some reason, gdb wants to talk about psudo + * registers (greater than 15). These may have + * meaning for ptrace, but for us it is safe to + * ignor them. We do this by dumping them into + * _GS which we also ignor, but do have memory for. + */ + int regno; + + ptr = &remcomInBuffer[1]; + regs_to_gdb_regs(gdb_regs, ®s); + if ((!usethread || usethread == current) && + hexToInt(&ptr, ®no) && + *ptr++ == '=' && (regno >= 0)) { + regno = + (regno >= NUMREGS ? _GS : regno); + hex2mem(ptr, (char *) &gdb_regs[regno], + 4, 0); + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + break; + } + strcpy(remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && (hexToInt(&ptr, &length))) { + ptr = 0; + /* + * hex doubles the byte count + */ + if (length > (BUFMAX / 2)) + length = BUFMAX / 2; + mem2hex((char *) addr, + remcomOutBuffer, length, 1); + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } + } + + if (ptr) { + strcpy(remcomOutBuffer, "E01"); + debug_error + ("malformed read memory command: %s\n", + remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: + Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && + (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) { + hex2mem(ptr, (char *) addr, length, 1); + + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } else { + strcpy(remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) { + strcpy(remcomOutBuffer, "E02"); + debug_error + ("malformed write memory command: %s\n", + remcomInBuffer); + } + break; + case 'S': + remcomInBuffer[0] = 's'; + case 'C': + /* Csig;AA..AA where ;AA..AA is optional + * continue with signal + * Since signals are meaning less to us, delete that + * part and then fall into the 'c' code. + */ + ptr = &remcomInBuffer[1]; + length = 2; + while (*ptr && *ptr != ';') { + length++; + ptr++; + } + if (*ptr) { + do { + ptr++; + *(ptr - length++) = *ptr; + } while (*ptr); + } else { + remcomInBuffer[1] = 0; + } + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* D detach, reply OK and then continue */ + case 'c': + case 's': + case 'D': + + /* try to read optional parameter, + pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) { + if (remote_debug) + printk("Changing EIP to 0x%x\n", addr); + + regs.eip = addr; + } + + newPC = regs.eip; + + /* clear the trace bit */ + regs.eflags &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + regs.eflags |= 0x100; + + /* detach is a friendly version of continue. Note that + debugging is still enabled (e.g hit control C) + */ + if (remcomInBuffer[0] == 'D') { + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + } + + if (remote_debug) { + printk("Resuming execution\n"); + print_regs(®s); + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (!(dr6 & 0x4000)) { + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno) && + (breakinfo[breakno].type == 0)) { + /* Set restore flag */ + regs.eflags |= 0x10000; + break; + } + } + } + + if (kgdboe) + netpoll_set_trap(0); + + correct_hw_break(); + asm volatile ("movl %0, %%db6\n"::"r" (0)); + goto exit_kgdb; + + /* kill the program */ + case 'k': /* do nothing */ + break; + + /* query */ + case 'q': + nothreads = 0; + switch (remcomInBuffer[1]) { + case 'f': + threadid = 1; + thread_list = 2; + thread_list_start = (usethread ? : current); + case 's': + if (!cmp_str(&remcomInBuffer[2], + "ThreadInfo", 10)) + break; + + remcomOutBuffer[nothreads++] = 'm'; + for (; threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + nothreads += int_to_hex_v( + &remcomOutBuffer[ + nothreads], + threadid); + if (thread_min > threadid) + thread_min = threadid; + remcomOutBuffer[ + nothreads] = ','; + nothreads++; + if (nothreads > BUFMAX - 10) + break; + } + } + if (remcomOutBuffer[nothreads - 1] == 'm') { + remcomOutBuffer[nothreads - 1] = 'l'; + } else { + nothreads--; + } + remcomOutBuffer[nothreads] = 0; + break; + +#ifdef old_thread_list /* Old thread info request */ + case 'L': + /* List threads */ + thread_list = 2; + thread_list_start = (usethread ? : current); + unpack_byte(remcomInBuffer + 3, &maxthreads); + unpack_threadid(remcomInBuffer + 5, &thref); + do { + int buf_thread_limit = + (BUFMAX - 22) / BUF_THREAD_ID_SIZE; + if (maxthreads > buf_thread_limit) { + maxthreads = buf_thread_limit; + } + } while (0); + remcomOutBuffer[0] = 'q'; + remcomOutBuffer[1] = 'M'; + remcomOutBuffer[4] = '0'; + pack_threadid(remcomOutBuffer + 5, &thref); + + threadid = threadref_to_int(&thref); + for (nothreads = 0; + nothreads < maxthreads && + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(remcomOutBuffer + + 21 + + nothreads * 16, + &thref); + nothreads++; + if (thread_min > threadid) + thread_min = threadid; + } + } + + if (threadid == PID_MAX + MAX_NO_CPUS) { + remcomOutBuffer[4] = '1'; + } + pack_hex_byte(remcomOutBuffer + 2, nothreads); + remcomOutBuffer[21 + nothreads * 16] = '\0'; + break; +#endif + case 'C': + /* Current thread id */ + remcomOutBuffer[0] = 'Q'; + remcomOutBuffer[1] = 'C'; + threadid = current->pid; + if (!threadid) { + /* + * idle thread + */ + for (threadid = PID_MAX; + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + if (current == + idle_task(threadid - + PID_MAX)) + break; + } + } + int_to_threadref(&thref, threadid); + pack_threadid(remcomOutBuffer + 2, &thref); + remcomOutBuffer[18] = '\0'; + break; + + case 'E': + /* Print exception info */ + printexceptioninfo(exceptionVector, + err_code, remcomOutBuffer); + break; + case 'T':{ + char * nptr; + /* Thread extra info */ + if (!cmp_str(&remcomInBuffer[2], + "hreadExtraInfo,", 15)) { + break; + } + ptr = &remcomInBuffer[17]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + nptr = &thread->comm[0]; + length = 0; + ptr = &remcomOutBuffer[0]; + do { + length++; + ptr = pack_hex_byte(ptr, *nptr++); + } while (*nptr && length < 16); + /* + * would like that 16 to be the size of + * task_struct.comm but don't know the + * syntax.. + */ + *ptr = 0; + } + } + break; + + /* task related */ + case 'H': + switch (remcomInBuffer[1]) { + case 'g': + ptr = &remcomInBuffer[2]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (!thread) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + break; + } + /* + * Just in case I forget what this is all about, + * the "thread info" command to gdb causes it + * to ask for a thread list. It then switches + * to each thread and asks for the registers. + * For this (and only this) usage, we want to + * fudge the registers of tasks not on the run + * list (i.e. waiting) to show the routine that + * called schedule. Also, gdb, is a minimalist + * in that if the current thread is the last + * it will not re-read the info when done. + * This means that in this case we must show + * the real registers. So here is how we do it: + * Each entry we keep track of the min + * thread in the list (the last that gdb will) + * get info for. We also keep track of the + * starting thread. + * "thread_list" is cleared when switching back + * to the min thread if it is was current, or + * if it was not current, thread_list is set + * to 1. When the switch to current comes, + * if thread_list is 1, clear it, else do + * nothing. + */ + usethread = thread; + if ((thread_list == 1) && + (thread == thread_list_start)) { + thread_list = 0; + } + if (thread_list && (threadid == thread_min)) { + if (thread == thread_list_start) { + thread_list = 0; + } else { + thread_list = 1; + } + } + /* follow through */ + case 'c': + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (thread) { + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + if (thread_min > threadid) + thread_min = threadid; + } else { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + } + break; + + case 'Y': /* set up a hardware breakpoint */ + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + ptr++; + hexToInt(&ptr, &breaktype); + ptr++; + hexToInt(&ptr, &length); + ptr++; + hexToInt(&ptr, &addr); + if (set_hw_break(breakno & 0x3, + breaktype & 0x3, + length & 0x3, addr) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + case 'r': /* reboot */ + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + /*to_gdb("Rebooting\n"); */ + /* triplefault no return from here */ + { + static long no_idt[2]; + __asm__ __volatile__("lidt %0"::"m"(no_idt[0])); + BREAKPOINT; + } + + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1==1) */ + /* + * reached by goto only. + */ + exit_kgdb: + /* + * Here is where we set up to trap a gdb function call. NEW_esp + * will be changed if we are trying to do this. We handle both + * adding and subtracting, thus allowing gdb to put grung on + * the stack which it removes later. + */ + if (NEW_esp != OLD_esp) { + int *ptr = END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) + ptr -= (OLD_esp - NEW_esp) / sizeof (int); + *--ptr = linux_regs->eflags; + *--ptr = linux_regs->xcs; + *--ptr = linux_regs->eip; + *--ptr = linux_regs->ecx; + *--ptr = linux_regs->ebx; + *--ptr = linux_regs->eax; + linux_regs->ecx = NEW_esp - (sizeof (int) * 6); + linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) { + linux_regs->eip = (unsigned int) fn_call_stub; + } else { + linux_regs->eip = (unsigned int) fn_rtn_stub; + linux_regs->eax = NEW_esp; + } + linux_regs->eflags &= ~(IF_BIT | TF_BIT); + } +#ifdef CONFIG_SMP + /* + * Release gdb wait locks + * Sanity check time. Must have at least one cpu to run. Also single + * step must not be done if the current cpu is on hold. + */ + if (spinlock_count == 1) { + int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep; + int cpu_avail = 0; + int i; + + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!cpu_online(i)) + break; + if (!hold_cpu(i)) { + cpu_avail = 1; + } + } + /* + * Early in the bring up there will be NO cpus on line... + */ + if (!cpu_avail && !cpus_empty(cpu_online_map)) { + to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); + goto once_again; + } + if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) { + to_gdb + ("Current cpu must be unblocked to single step\n"); + goto once_again; + } + if (!(ss_hold)) { + int i; + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!hold_cpu(i)) { + spin_unlock(&waitlocks[i]); + } + } + } else { + spin_unlock(&waitlocks[smp_processor_id()]); + } + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + /* + * If this cpu is on hold, this is where we + * do it. Note, the NMI will pull us out of here, + * but will return as the above lock is not held. + * We will stay here till another cpu releases the lock for us. + */ + spin_unlock_wait(waitlocks + smp_processor_id()); + kgdb_local_irq_restore(flags); + return (0); + } +#if 0 +exit_just_unlock: +#endif +#endif + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + kgdb_local_irq_restore(flags); + return (0); +} + +/* this function is used to set up exception handlers for tracing and + * breakpoints. + * This function is not needed as the above line does all that is needed. + * We leave it for backward compatitability... + */ +void +set_debug_traps(void) +{ + /* + * linux_debug_hook is defined in traps.c. We store a pointer + * to our own exception handler into it. + + * But really folks, every hear of labeled common, an old Fortran + * concept. Lots of folks can reference it and it is define if + * anyone does. Only one can initialize it at link time. We do + * this with the hook. See the statement above. No need for any + * executable code and it is ready as soon as the kernel is + * loaded. Very desirable in kernel debugging. + + linux_debug_hook = handle_exception ; + */ + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. + putDebugChar ('+'); + + initialized = 1; + */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ +/* But really, just use the BREAKPOINT macro. We will handle the int stuff + */ + +#ifdef later +/* + * possibly we should not go thru the traps.c code at all? Someday. + */ +void +do_kgdb_int3(struct pt_regs *regs, long error_code) +{ + kgdb_handle_exception(3, 5, error_code, regs); + return; +} +#endif +#undef regs +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS +asmlinkage void +bad_sys_call_exit(int stuff) +{ + struct pt_regs *regs = (struct pt_regs *) &stuff; + printk("Sys call %d return with %x preempt_count\n", + (int) regs->orig_eax, preempt_count()); +} +#endif +#ifdef CONFIG_STACK_OVERFLOW_TEST +#include +asmlinkage void +stack_overflow(void) +{ +#ifdef BREAKPOINT + BREAKPOINT; +#else + printk("Kernel stack overflow, looping forever\n"); +#endif + while (1) { + } +} +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) +char gdbconbuf[BUFMAX]; + +static void +kgdb_gdb_message(const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + /* + * This takes care of NMI while spining out chars to gdb + */ + IF_SMP(in_kgdb_console = 1); + gdbconbuf[0] = 'O'; + bufptr = gdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + putpacket(gdbconbuf); + + } + IF_SMP(in_kgdb_console = 0); +} +#endif +#ifdef CONFIG_SMP +static void +to_gdb(const char *s) +{ + int count = 0; + while (s[count] && (count++ < BUFMAX)) ; + kgdb_gdb_message(s, count); +} +#endif +#ifdef CONFIG_KGDB_CONSOLE +#include +#include +#include +#include +#include + +void +kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + + if (gdb_i386vector == -1) { + /* + * We have not yet talked to gdb. What to do... + * lets break, on continue we can do the write. + * But first tell him whats up. Uh, well no can do, + * as this IS the console. Oh well... + * We do need to wait or the messages will be lost. + * Other option would be to tell the above code to + * ignore this breakpoint and do an auto return, + * but that might confuse gdb. Also this happens + * early enough in boot up that we don't have the traps + * set up yet, so... + */ + breakpoint(); + } + kgdb_gdb_message(s, count); +} + +/* + * ------------------------------------------------------------ + * Serial KGDB driver + * ------------------------------------------------------------ + */ + +static struct console kgdbcons = { + name:"kgdb", + write:kgdb_console_write, +#ifdef CONFIG_KGDB_USER_CONSOLE + device:kgdb_console_device, +#endif + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +/* + * The trick here is that this file gets linked before printk.o + * That means we get to peer at the console info in the command + * line before it does. If we are up, we register, otherwise, + * do nothing. By returning 0, we allow printk to look also. + */ +static int kgdb_console_enabled; + +int __init +kgdb_console_init(char *str) +{ + if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { + register_console(&kgdbcons); + kgdb_console_enabled = 1; + } + return 0; /* let others look at the string */ +} + +__setup("console=", kgdb_console_init); + +#ifdef CONFIG_KGDB_USER_CONSOLE +static kdev_t kgdb_console_device(struct console *c); +/* This stuff sort of works, but it knocks out telnet devices + * we are leaving it here in case we (or you) find time to figure it out + * better.. + */ + +/* + * We need a real char device as well for when the console is opened for user + * space activities. + */ + +static int +kgdb_consdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t +kgdb_consdev_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int size, ret = 0; + static char kbuf[128]; + static DECLARE_MUTEX(sem); + + /* We are not reentrant... */ + if (down_interruptible(&sem)) + return -ERESTARTSYS; + + while (count > 0) { + /* need to copy the data from user space */ + size = count; + if (size > sizeof (kbuf)) + size = sizeof (kbuf); + if (copy_from_user(kbuf, buf, size)) { + ret = -EFAULT; + break;; + } + kgdb_console_write(&kgdbcons, kbuf, size); + count -= size; + ret += size; + buf += size; + } + + up(&sem); + + return ret; +} + +struct file_operations kgdb_consdev_fops = { + open:kgdb_consdev_open, + write:kgdb_consdev_write +}; +static kdev_t +kgdb_console_device(struct console *c) +{ + return MKDEV(TTYAUX_MAJOR, 1); +} + +/* + * This routine gets called from the serial stub in the i386/lib + * This is so it is done late in bring up (just before the console open). + */ +void +kgdb_console_finit(void) +{ + if (kgdb_console_enabled) { + char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); + char *cp = cptr; + while (*cptr && *cptr != '(') + cptr++; + *cptr = 0; + unregister_chrdev(TTYAUX_MAJOR, cp); + register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); + } +} +#endif +#endif +#ifdef CONFIG_KGDB_TS +#include /* time stamp code */ +#include /* in_interrupt */ +#ifdef CONFIG_KGDB_TS_64 +#define DATA_POINTS 64 +#endif +#ifdef CONFIG_KGDB_TS_128 +#define DATA_POINTS 128 +#endif +#ifdef CONFIG_KGDB_TS_256 +#define DATA_POINTS 256 +#endif +#ifdef CONFIG_KGDB_TS_512 +#define DATA_POINTS 512 +#endif +#ifdef CONFIG_KGDB_TS_1024 +#define DATA_POINTS 1024 +#endif +#ifndef DATA_POINTS +#define DATA_POINTS 128 /* must be a power of two */ +#endif +#define INDEX_MASK (DATA_POINTS - 1) +#if (INDEX_MASK & DATA_POINTS) +#error "CONFIG_KGDB_TS_COUNT must be a power of 2" +#endif +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + int data0; + int data1; +}; +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + struct task_struct *t1; + struct task_struct *t2; +}; +struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; + +struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; +int kgdb_and_then_count; + +void +kgdb_tstamp(int line, char *source, int data0, int data1) +{ + static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; + int flags; + kgdb_local_irq_save(flags); + spin_lock(&ts_spin); + rdtscll(kgdb_and_then->at_time); +#ifdef CONFIG_SMP + kgdb_and_then->on_cpu = smp_processor_id(); +#endif + kgdb_and_then->task = current; + kgdb_and_then->from_ln = line; + kgdb_and_then->in_src = source; + kgdb_and_then->from = __builtin_return_address(0); + kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) | + (preempt_count() << 8)); + kgdb_and_then->data0 = data0; + kgdb_and_then->data1 = data1; + kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; + spin_unlock(&ts_spin); + kgdb_local_irq_restore(flags); +#ifdef CONFIG_PREEMPT + +#endif + return; +} +#endif +typedef int gdb_debug_hook(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs); +gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ + +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + BREAKPOINT; + } +} + --- linux-2.6.1-rc1/arch/i386/kernel/ldt.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/ldt.c 2004-01-04 22:21:59.000000000 -0800 @@ -2,7 +2,7 @@ * linux/kernel/ldt.c * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds - * Copyright (C) 1999 Ingo Molnar + * Copyright (C) 1999, 2003 Ingo Molnar */ #include @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -29,34 +31,31 @@ static void flush_ldt(void *null) static int alloc_ldt(mm_context_t *pc, int mincount, int reload) { - void *oldldt; - void *newldt; - int oldsize; + int oldsize, newsize, i; if (mincount <= pc->size) return 0; + /* + * LDT got larger - reallocate if necessary. + */ oldsize = pc->size; mincount = (mincount+511)&(~511); - if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) - newldt = vmalloc(mincount*LDT_ENTRY_SIZE); - else - newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); - - if (!newldt) - return -ENOMEM; - - if (oldsize) - memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); - oldldt = pc->ldt; - memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); - pc->ldt = newldt; - wmb(); + newsize = mincount*LDT_ENTRY_SIZE; + for (i = 0; i < newsize; i += PAGE_SIZE) { + int nr = i/PAGE_SIZE; + BUG_ON(i >= 64*1024); + if (!pc->ldt_pages[nr]) { + pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER); + if (!pc->ldt_pages[nr]) + return -ENOMEM; + clear_highpage(pc->ldt_pages[nr]); + } + } pc->size = mincount; - wmb(); - if (reload) { #ifdef CONFIG_SMP cpumask_t mask; + preempt_disable(); load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); @@ -67,21 +66,20 @@ static int alloc_ldt(mm_context_t *pc, i load_LDT(pc); #endif } - if (oldsize) { - if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(oldldt); - else - kfree(oldldt); - } return 0; } static inline int copy_ldt(mm_context_t *new, mm_context_t *old) { - int err = alloc_ldt(new, old->size, 0); - if (err < 0) + int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE; + + err = alloc_ldt(new, size, 0); + if (err < 0) { + new->size = 0; return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + } + for (i = 0; i < nr_pages; i++) + copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0); return 0; } @@ -96,6 +94,7 @@ int init_new_context(struct task_struct init_MUTEX(&mm->context.sem); mm->context.size = 0; + memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES); old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); @@ -107,23 +106,21 @@ int init_new_context(struct task_struct /* * No need to lock the MM as we are the last user + * Do not touch the ldt register, we are already + * in the next thread. */ void destroy_context(struct mm_struct *mm) { - if (mm->context.size) { - if (mm == current->active_mm) - clear_LDT(); - if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(mm->context.ldt); - else - kfree(mm->context.ldt); - mm->context.size = 0; - } + int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) + __free_page(mm->context.ldt_pages[i]); + mm->context.size = 0; } static int read_ldt(void __user * ptr, unsigned long bytecount) { - int err; + int err, i; unsigned long size; struct mm_struct * mm = current->mm; @@ -138,8 +135,25 @@ static int read_ldt(void __user * ptr, u size = bytecount; err = 0; - if (copy_to_user(ptr, mm->context.ldt, size)) - err = -EFAULT; + /* + * This is necessary just in case we got here straight from a + * context-switch where the ptes were set but no tlb flush + * was done yet. We rather avoid doing a TLB flush in the + * context-switch path and do it here instead. + */ + __flush_tlb_global(); + + for (i = 0; i < size; i += PAGE_SIZE) { + int nr = i / PAGE_SIZE, bytes; + char *kaddr = kmap(mm->context.ldt_pages[nr]); + + bytes = size - i; + if (bytes > PAGE_SIZE) + bytes = PAGE_SIZE; + if (copy_to_user(ptr + i, kaddr, size - i)) + err = -EFAULT; + kunmap(mm->context.ldt_pages[nr]); + } up(&mm->context.sem); if (err < 0) return err; @@ -158,7 +172,7 @@ static int read_default_ldt(void __user err = 0; address = &default_ldt[0]; - size = 5*sizeof(struct desc_struct); + size = 5*LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; @@ -200,7 +214,15 @@ static int write_ldt(void __user * ptr, goto out_unlock; } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); + /* + * No rescheduling allowed from this point to the install. + * + * We do a TLB flush for the same reason as in the read_ldt() path. + */ + preempt_disable(); + __flush_tlb_global(); + lp = (__u32 *) ((ldt_info.entry_number << 3) + + (char *) __kmap_atomic_vaddr(KM_LDT_PAGE0)); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -221,6 +243,7 @@ install: *lp = entry_1; *(lp+1) = entry_2; error = 0; + preempt_enable(); out_unlock: up(&mm->context.sem); @@ -248,3 +271,26 @@ asmlinkage int sys_modify_ldt(int func, } return ret; } + +/* + * load one particular LDT into the current CPU + */ +void load_LDT_nolock(mm_context_t *pc, int cpu) +{ + struct page **pages = pc->ldt_pages; + int count = pc->size; + int nr_pages, i; + + if (likely(!count)) { + pages = &default_ldt_page; + count = 5; + } + nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) { + __kunmap_atomic_type(KM_LDT_PAGE0 - i); + __kmap_atomic(pages[i], KM_LDT_PAGE0 - i); + } + set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count); + load_LDT_desc(); +} --- linux-2.6.1-rc1/arch/i386/kernel/Makefile 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/Makefile 2004-01-04 22:21:59.000000000 -0800 @@ -7,13 +7,14 @@ extra-y := head.o init_task.o vmlinux.ld 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 dmi_scan.o bootflag.o \ - doublefault.o + doublefault.o entry_trampoline.o obj-y += cpu/ obj-y += timers/ obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o --- linux-2.6.1-rc1/arch/i386/kernel/mpparse.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/mpparse.c 2004-01-04 22:21:59.000000000 -0800 @@ -668,7 +668,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); @@ -962,7 +962,8 @@ void __init mp_override_legacy_irq ( */ for (i = 0; i < mp_irq_entries; i++) { if ((mp_irqs[i].mpc_dstapic == intsrc.mpc_dstapic) - && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) { + && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq) + && (mp_irqs[i].mpc_irqtype == intsrc.mpc_irqtype)) { mp_irqs[i] = intsrc; found = 1; break; @@ -1081,8 +1082,14 @@ found: ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; + /* + * MPS INTI flags: + * trigger: 0=default, 1=edge, 3=level + * polarity: 0=default, 1=high, 3=low + * Per ACPI spec, default for SCI means level/low. + */ io_apic_set_pci_routing(ioapic, ioapic_pin, irq, - (flags.trigger >> 1) , (flags.polarity >> 1)); + (flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1)); } #ifdef CONFIG_ACPI_PCI @@ -1129,8 +1136,11 @@ void __init mp_parse_prt (void) continue; ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - if (!ioapic && (irq < 16)) - irq += 16; + if (es7000_plat) { + if (!ioapic && (irq < 16)) + irq += 16; + } + /* * Avoid pin reprogramming. PRTs typically include entries * with redundant pin->irq mappings (but unique PCI devices); @@ -1166,6 +1176,10 @@ void __init mp_parse_prt (void) mp_ioapic_routing[ioapic].apic_id, ioapic_pin, entry->irq); } + + print_IO_APIC(); + + return; } #endif /*CONFIG_ACPI_PCI*/ --- linux-2.6.1-rc1/arch/i386/kernel/nmi.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/nmi.c 2004-01-04 17:36:33.000000000 -0800 @@ -31,7 +31,16 @@ #include #include +#ifdef CONFIG_KGDB +#include +#ifdef CONFIG_SMP +unsigned int nmi_watchdog = NMI_IO_APIC; +#else +unsigned int nmi_watchdog = NMI_LOCAL_APIC; +#endif +#else unsigned int nmi_watchdog = NMI_NONE; +#endif static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); @@ -408,6 +417,9 @@ void touch_nmi_watchdog (void) for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } +#ifdef CONFIG_KGDB +int tune_watchdog = 5*HZ; +#endif void nmi_watchdog_tick (struct pt_regs * regs) { @@ -421,12 +433,24 @@ void nmi_watchdog_tick (struct pt_regs * sum = irq_stat[cpu].apic_timer_irqs; +#ifdef CONFIG_KGDB + if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) { + +#else if (last_irq_sums[cpu] == sum) { +#endif /* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; +#ifdef CONFIG_KGDB + if (alert_counter[cpu] == tune_watchdog) { + kgdb_handle_exception(2, SIGPWR, 0, regs); + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } +#endif if (alert_counter[cpu] == 5*nmi_hz) { spin_lock(&nmi_print_lock); /* --- linux-2.6.1-rc1/arch/i386/kernel/process.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/process.c 2004-01-04 22:21:59.000000000 -0800 @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -302,6 +303,9 @@ void flush_thread(void) struct task_struct *tsk = current; memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); +#ifdef CONFIG_X86_HIGH_ENTRY + clear_thread_flag(TIF_DB7); +#endif memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* * Forget coprocessor state.. @@ -315,9 +319,8 @@ void release_thread(struct task_struct * if (dead_task->mm) { // temporary debugging check if (dead_task->mm->context.size) { - printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + printk("WARNING: dead process %8s still has LDT? <%d>\n", dead_task->comm, - dead_task->mm->context.ldt, dead_task->mm->context.size); BUG(); } @@ -352,7 +355,17 @@ int copy_thread(int nr, unsigned long cl p->thread.esp = (unsigned long) childregs; p->thread.esp0 = (unsigned long) (childregs+1); + /* + * get the two stack pages, for the virtual stack. + * + * IMPORTANT: this code relies on the fact that the task + * structure is an 8K aligned piece of physical memory. + */ + p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info); + p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE); + p->thread.eip = (unsigned long) ret_from_fork; + p->thread_info->real_stack = p->thread_info; savesegment(fs,p->thread.fs); savesegment(gs,p->thread.gs); @@ -504,10 +517,41 @@ struct task_struct * __switch_to(struct __unlazy_fpu(prev_p); +#ifdef CONFIG_X86_HIGH_ENTRY + /* + * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is + * needed because otherwise NMIs could interrupt the + * user-return code with a virtual stack and stale TLBs.) + */ + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(next->stack_page0, KM_VSTACK0); + __kmap_atomic(next->stack_page1, KM_VSTACK1); + + /* + * NOTE: here we rely on the task being the stack as well + */ + next_p->thread_info->virtual_stack = + (void *)__kmap_atomic_vaddr(KM_VSTACK0); + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + /* + * If next was preempted on entry from userspace to kernel, + * and now it's on a different cpu, we need to adjust %esp. + * This assumes that entry.S does not copy %esp while on the + * virtual stack (with interrupts enabled): which is so, + * except within __SWITCH_KERNELSPACE itself. + */ + if (unlikely(next->esp >= TASK_SIZE)) { + next->esp &= THREAD_SIZE - 1; + next->esp |= (unsigned long) next_p->thread_info->virtual_stack; + } +#endif +#endif /* * Reload esp0, LDT and the page table pointer: */ - load_esp0(tss, next); + load_virtual_esp0(tss, next_p); /* * Load the per-thread Thread-Local Storage descriptor. --- linux-2.6.1-rc1/arch/i386/kernel/reboot.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/reboot.c 2004-01-04 22:21:59.000000000 -0800 @@ -155,12 +155,11 @@ void machine_real_restart(unsigned char CMOS_WRITE(0x00, 0x8f); spin_unlock_irqrestore(&rtc_lock, flags); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + /* + * Remap the first 16 MB of RAM (which includes the kernel image) + * at virtual address zero: + */ + setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024); /* * Use `swapper_pg_dir' as our page directory. --- linux-2.6.1-rc1/arch/i386/kernel/setup.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/setup.c 2004-01-04 22:15:28.000000000 -0800 @@ -78,13 +78,10 @@ EXPORT_SYMBOL_GPL(mmu_cr4_features); EXPORT_SYMBOL(acpi_disabled); #ifdef CONFIG_ACPI_BOOT - int acpi_irq __initdata = 1; /* enable IRQ */ - int acpi_ht __initdata = 1; /* enable HT */ +extern int __initdata acpi_ht; +int __initdata acpi_force = 0; #endif -int acpi_force __initdata = 0; - - int MCA_bus; /* for MCA, but anyone else can use it if they want */ unsigned int machine_id; @@ -573,7 +570,7 @@ static void __init parse_cmdline_early ( /* "pci=noacpi" disables ACPI interrupt routing */ else if (!memcmp(from, "pci=noacpi", 10)) { - acpi_irq = 0; + acpi_noirq_set(); } #ifdef CONFIG_X86_LOCAL_APIC --- linux-2.6.1-rc1/arch/i386/kernel/signal.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/kernel/signal.c 2004-01-04 22:21:59.000000000 -0800 @@ -128,28 +128,29 @@ sys_sigaltstack(const stack_t __user *us */ static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) +restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *__sc, int *peax) { - unsigned int err = 0; + struct sigcontext scratch; /* 88 bytes of scratch area */ /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; -#define COPY(x) err |= __get_user(regs->x, &sc->x) + if (copy_from_user(&scratch, __sc, sizeof(scratch))) + return -EFAULT; + +#define COPY(x) regs->x = scratch.x #define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ loadsegment(seg,tmp); } GET_SEG(gs); @@ -168,27 +169,23 @@ restore_sigcontext(struct pt_regs *regs, COPY_SEG_STRICT(ss); { - unsigned int tmpflags; - err |= __get_user(tmpflags, &sc->eflags); + unsigned int tmpflags = scratch.eflags; regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ } { - struct _fpstate __user * buf; - err |= __get_user(buf, &sc->fpstate); + struct _fpstate * buf = scratch.fpstate; if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); + return -EFAULT; + if (restore_i387(buf)) + return -EFAULT; } } - err |= __get_user(*peax, &sc->eax); - return err; - -badframe: - return 1; + *peax = scratch.eax; + return 0; } asmlinkage int sys_sigreturn(unsigned long __unused) @@ -266,46 +263,47 @@ badframe: */ static int -setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, +setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { - int tmp, err = 0; + struct sigcontext sc; /* 88 bytes of scratch area */ + int tmp; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->gs); + *(unsigned int *)&sc.gs = tmp; __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->fs); - - err |= __put_user(regs->xes, (unsigned int *)&sc->es); - err |= __put_user(regs->xds, (unsigned int *)&sc->ds); - err |= __put_user(regs->edi, &sc->edi); - err |= __put_user(regs->esi, &sc->esi); - err |= __put_user(regs->ebp, &sc->ebp); - err |= __put_user(regs->esp, &sc->esp); - err |= __put_user(regs->ebx, &sc->ebx); - err |= __put_user(regs->edx, &sc->edx); - err |= __put_user(regs->ecx, &sc->ecx); - err |= __put_user(regs->eax, &sc->eax); - err |= __put_user(current->thread.trap_no, &sc->trapno); - err |= __put_user(current->thread.error_code, &sc->err); - err |= __put_user(regs->eip, &sc->eip); - err |= __put_user(regs->xcs, (unsigned int *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); - err |= __put_user(regs->esp, &sc->esp_at_signal); - err |= __put_user(regs->xss, (unsigned int *)&sc->ss); + *(unsigned int *)&sc.fs = tmp; + *(unsigned int *)&sc.es = regs->xes; + *(unsigned int *)&sc.ds = regs->xds; + sc.edi = regs->edi; + sc.esi = regs->esi; + sc.ebp = regs->ebp; + sc.esp = regs->esp; + sc.ebx = regs->ebx; + sc.edx = regs->edx; + sc.ecx = regs->ecx; + sc.eax = regs->eax; + sc.trapno = current->thread.trap_no; + sc.err = current->thread.error_code; + sc.eip = regs->eip; + *(unsigned int *)&sc.cs = regs->xcs; + sc.eflags = regs->eflags; + sc.esp_at_signal = regs->esp; + *(unsigned int *)&sc.ss = regs->xss; tmp = save_i387(fpstate); if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + return 1; + sc.fpstate = tmp ? fpstate : NULL; /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(current->thread.cr2, &sc->cr2); + sc.oldmask = mask; + sc.cr2 = current->thread.cr2; - return err; + if (copy_to_user(__sc, &sc, sizeof(sc))) + return 1; + return 0; } /* @@ -443,7 +441,7 @@ static void setup_rt_frame(int sig, stru /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->esp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); --- linux-2.6.1-rc1/arch/i386/kernel/smp.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/smp.c 2004-01-04 22:21:59.000000000 -0800 @@ -327,10 +327,12 @@ asmlinkage void smp_invalidate_interrupt if (flush_mm == cpu_tlbstate[cpu].active_mm) { if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (flush_va == FLUSH_ALL) local_flush_tlb(); else __flush_tlb_one(flush_va); +#endif } else leave_mm(cpu); } @@ -396,21 +398,6 @@ static void flush_tlb_others(cpumask_t c spin_unlock(&tlbstate_lock); } -void flush_tlb_current_task(void) -{ - struct mm_struct *mm = current->mm; - cpumask_t cpu_mask; - - preempt_disable(); - cpu_mask = mm->cpu_vm_mask; - cpu_clear(smp_processor_id(), cpu_mask); - - local_flush_tlb(); - if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, FLUSH_ALL); - preempt_enable(); -} - void flush_tlb_mm (struct mm_struct * mm) { cpumask_t cpu_mask; @@ -442,7 +429,10 @@ void flush_tlb_page(struct vm_area_struc if (current->active_mm == mm) { if(current->mm) - __flush_tlb_one(va); +#ifndef CONFIG_X86_SWITCH_PAGETABLES + __flush_tlb_one(va) +#endif + ; else leave_mm(smp_processor_id()); } @@ -466,7 +456,17 @@ void flush_tlb_all(void) { on_each_cpu(do_flush_tlb_all, 0, 1, 1); } - +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing --- linux-2.6.1-rc1/arch/i386/kernel/sysenter.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/sysenter.c 2004-01-04 22:21:59.000000000 -0800 @@ -18,13 +18,18 @@ #include #include #include +#include extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void *info) { int cpu = get_cpu(); +#ifdef CONFIG_X86_HIGH_ENTRY + struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else struct tss_struct *tss = init_tss + cpu; +#endif tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; --- linux-2.6.1-rc1/arch/i386/kernel/time_hpet.c 2003-09-08 13:58:55.000000000 -0700 +++ 25/arch/i386/kernel/time_hpet.c 2004-01-04 22:16:29.000000000 -0800 @@ -91,10 +91,6 @@ int __init hpet_enable(void) !(id & HPET_ID_LEGSUP)) return -1; - if (((id & HPET_ID_VENDOR) >> HPET_ID_VENDOR_SHIFT) != - HPET_ID_VENDOR_8086) - return -1; - hpet_period = hpet_readl(HPET_PERIOD); if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD)) return -1; --- linux-2.6.1-rc1/arch/i386/kernel/timers/common.c 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/i386/kernel/timers/common.c 2004-01-04 22:15:42.000000000 -0800 @@ -137,3 +137,23 @@ bad_calibration: } #endif +/* calculate cpu_khz */ +void __init init_cpu_khz(void) +{ + if (cpu_has_tsc) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000; + __asm__("divl %2" + :"=a" (cpu_khz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); + } + } + } +} --- linux-2.6.1-rc1/arch/i386/kernel/timers/Makefile 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/i386/kernel/timers/Makefile 2004-01-04 22:15:42.000000000 -0800 @@ -6,3 +6,4 @@ obj-y := timer.o timer_none.o timer_tsc. obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o obj-$(CONFIG_HPET_TIMER) += timer_hpet.o +obj-$(CONFIG_X86_PM_TIMER) += timer_pm.o --- linux-2.6.1-rc1/arch/i386/kernel/timers/timer.c 2003-09-08 13:58:55.000000000 -0700 +++ 25/arch/i386/kernel/timers/timer.c 2004-01-04 22:15:42.000000000 -0800 @@ -19,6 +19,9 @@ static struct timer_opts* timers[] = { #ifdef CONFIG_HPET_TIMER &timer_hpet, #endif +#ifdef CONFIG_X86_PM_TIMER + &timer_pmtmr, +#endif &timer_tsc, &timer_pit, NULL, --- linux-2.6.1-rc1/arch/i386/kernel/timers/timer_cyclone.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/timers/timer_cyclone.c 2004-01-04 22:15:42.000000000 -0800 @@ -212,26 +212,7 @@ static int __init init_cyclone(char* ove } } - /* init cpu_khz. - * XXX - This should really be done elsewhere, - * and in a more generic fashion. -johnstul@us.ibm.com - */ - if (cpu_has_tsc) { - unsigned long tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000; - __asm__("divl %2" - :"=a" (cpu_khz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); - } - } - } + init_cpu_khz(); /* Everything looks good! */ return 0; --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/kernel/timers/timer_pm.c 2004-01-04 22:15:43.000000000 -0800 @@ -0,0 +1,201 @@ +/* + * (C) Dominik Brodowski 2003 + * + * Driver to use the Power Management Timer (PMTMR) available in some + * southbridges as primary timing source for the Linux kernel. + * + * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, + * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. + * + * This file is licensed under the GPL v2. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* The I/O port the PMTMR resides at. + * The location is detected during setup_arch(), + * in arch/i386/acpi/boot.c */ +u32 pmtmr_ioport = 0; + + +/* value of the Power timer at last timer interrupt */ +static u32 offset_tick; +static u32 offset_delay; + +static unsigned long long monotonic_base; +static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED; + +#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ + +static int init_pmtmr(char* override) +{ + u32 value1, value2; + unsigned int i; + + if (override[0] && strncmp(override,"pmtmr",5)) + return -ENODEV; + + if (!pmtmr_ioport) + return -ENODEV; + + /* "verify" this timing source */ + value1 = inl(pmtmr_ioport); + value1 &= ACPI_PM_MASK; + for (i=0; i < 10000; i++) { + value2 = inl(pmtmr_ioport); + value2 &= ACPI_PM_MASK; + if (value2 == value1) + continue; + if (value2 > value1) + goto pm_good; + if ((value2 < value1) && ((value2) < 0xFFF)) + goto pm_good; + printk(KERN_INFO "PM-Timer had inconsistent results: 0x%#x, 0x%#x - aborting.\n", value1, value2); + return -EINVAL; + } + printk(KERN_INFO "PM-Timer had no reasonable result: 0x%#x - aborting.\n", value1); + return -ENODEV; + +pm_good: + init_cpu_khz(); + return 0; +} + +static inline u32 cyc2us(u32 cycles) +{ + /* The Power Management Timer ticks at 3.579545 ticks per microsecond. + * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%] + * + * Even with HZ = 100, delta is at maximum 35796 ticks, so it can + * easily be multiplied with 286 (=0x11E) without having to fear + * u32 overflows. + */ + cycles *= 286; + return (cycles >> 10); +} + +/* + * this gets called during each timer interrupt + * - Called while holding the writer xtime_lock + */ +static void mark_offset_pmtmr(void) +{ + u32 lost, delta, last_offset; + static int first_run = 1; + + write_seqlock(&monotonic_lock); + + last_offset = offset_tick; + offset_tick = inl(pmtmr_ioport); + offset_tick &= ACPI_PM_MASK; /* limit it to 24 bits */ + + /* calculate tick interval */ + delta = likely(last_offset < offset_tick) ? + offset_tick - last_offset : ACPI_PM_MASK - last_offset + offset_tick; + + /* convert to usecs */ + delta = cyc2us(delta); + + /* update the monotonic base value */ + monotonic_base += delta * NSEC_PER_USEC; + write_sequnlock(&monotonic_lock); + + /* convert to ticks */ + delta += offset_delay; + lost = delta / (USEC_PER_SEC / HZ); + offset_delay = delta % (USEC_PER_SEC / HZ); + + /* compensate for lost ticks */ + if (lost >= 2) + jiffies += lost - 1; + + /* don't calculate delay for first run, + or if we've got less then a tick */ + if (first_run || (lost < 1)) { + first_run = 0; + offset_delay = 0; + } +} + + +static unsigned long long monotonic_clock_pmtmr(void) +{ + u32 last_offset, this_offset; + unsigned long long base, ret; + unsigned seq; + + + /* atomically read monotonic base & last_offset */ + do { + seq = read_seqbegin(&monotonic_lock); + last_offset = offset_tick; + base = monotonic_base; + } while (read_seqretry(&monotonic_lock, seq)); + + /* Read the pmtmr */ + this_offset = inl(pmtmr_ioport) & ACPI_PM_MASK; + + /* convert to nanoseconds */ + ret = (this_offset - last_offset) & ACPI_PM_MASK; + ret = base + (cyc2us(ret)*NSEC_PER_USEC); + return ret; +} + +/* + * copied from delay_pit + */ +static void delay_pmtmr(unsigned long loops) +{ + int d0; + __asm__ __volatile__( + "\tjmp 1f\n" + ".align 16\n" + "1:\tjmp 2f\n" + ".align 16\n" + "2:\tdecl %0\n\tjns 2b" + :"=&a" (d0) + :"0" (loops)); +} + + +/* + * get the offset (in microseconds) from the last call to mark_offset() + * - Called holding a reader xtime_lock + */ +static unsigned long get_offset_pmtmr(void) +{ + u32 now, offset, delta = 0; + + offset = offset_tick; + now = inl(pmtmr_ioport); + now &= ACPI_PM_MASK; + delta = likely(offset < now) ? now - offset : ACPI_PM_MASK - offset + now; + + return (unsigned long) offset_delay + cyc2us(delta); +} + + +/* acpi timer_opts struct */ +struct timer_opts timer_pmtmr = { + .name = "acpi_pm_timer", + .init = init_pmtmr, + .mark_offset = mark_offset_pmtmr, + .get_offset = get_offset_pmtmr, + .monotonic_clock = monotonic_clock_pmtmr, + .delay = delay_pmtmr, +}; + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dominik Brodowski "); +MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86"); --- linux-2.6.1-rc1/arch/i386/kernel/timers/timer_tsc.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/timers/timer_tsc.c 2004-01-04 22:16:03.000000000 -0800 @@ -140,7 +140,8 @@ unsigned long long sched_clock(void) #ifndef CONFIG_NUMA if (!use_tsc) #endif - return (unsigned long long)get_jiffies_64() * (1000000000 / HZ); + /* jiffies might overflow but this is not a big deal here */ + return (unsigned long long)jiffies * (1000000000 / HZ); /* Read the Time Stamp Counter */ rdtscll(this_offset); --- linux-2.6.1-rc1/arch/i386/kernel/traps.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/traps.c 2004-01-04 22:21:59.000000000 -0800 @@ -54,12 +54,8 @@ #include "mach_traps.h" -asmlinkage int system_call(void); -asmlinkage void lcall7(void); -asmlinkage void lcall27(void); - -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 }, { 0, 0 } }; +struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; +struct page *default_ldt_page; /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; @@ -91,6 +87,43 @@ asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); +#ifdef CONFIG_KGDB +extern void sysenter_entry(void); +#include +#include +extern void int3(void); +extern void debug(void); +void set_intr_gate(unsigned int n, void *addr); +static void set_intr_usr_gate(unsigned int n, void *addr); +/* + * Should be able to call this breakpoint() very early in + * bring up. Just hard code the call where needed. + * The breakpoint() code is here because set_?_gate() functions + * are local (static) to trap.c. They need be done only once, + * but it does not hurt to do them over. + */ +void breakpoint(void) +{ + init_entry_mappings(); + set_intr_usr_gate(3,&int3); /* disable ints on trap */ + set_intr_gate(1,&debug); + set_intr_gate(14,&page_fault); + + BREAKPOINT; +} +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \ + { \ + if (!user_mode(regs) ) \ + { \ + kgdb_handle_exception(trapnr, signr, error_code, regs); \ + after; \ + } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \ + } +#else +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) +#endif + + static int kstack_depth_to_print = 24; void show_trace(struct task_struct *task, unsigned long * stack) @@ -175,8 +208,9 @@ void show_registers(struct pt_regs *regs ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", - smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, + regs->eip, print_tainted(), regs->eflags); print_symbol("EIP is at %s\n", regs->eip); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", @@ -192,23 +226,27 @@ void show_registers(struct pt_regs *regs * time of the fault.. */ if (in_kernel) { + u8 *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - if(regs->eip < PAGE_OFFSET) - goto bad; - for(i=0;i<20;i++) - { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { + unsigned char c = 0xff; + + if ((user_mode(regs) && get_user(c, eip)) || + (!user_mode(regs) && __direct_get_user(c, eip))) { + printk(" Bad EIP value."); break; } - printk("%02x ", c); + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); } } printk("\n"); @@ -255,12 +293,36 @@ spinlock_t die_lock = SPIN_LOCK_UNLOCKED void die(const char * str, struct pt_regs * regs, long err) { static int die_counter; + int nl = 0; console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); handle_BUG(regs); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); + nl = 1; +#endif +#ifdef CONFIG_SMP + printk("SMP "); + nl = 1; +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); + nl = 1; +#endif + if (nl) + printk("\n"); +#ifdef CONFIG_KGDB + /* This is about the only place we want to go to kgdb even if in + * user mode. But we must go in via a trap so within kgdb we will + * always be in kernel mode. + */ + if (user_mode(regs)) + BREAKPOINT; +#endif + CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,) show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); @@ -330,6 +392,7 @@ static inline void do_trap(int trapnr, i #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -347,7 +410,9 @@ asmlinkage void do_##name(struct pt_regs #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ + return; \ } #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ @@ -394,8 +459,10 @@ gp_in_vm86: return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)){ + CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,) die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -534,10 +601,18 @@ asmlinkage void do_debug(struct pt_regs if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); - /* Mask out spurious debug traps due to lazy DR7 setting */ + /* + * Mask out spurious debug traps due to lazy DR7 setting or + * due to 4G/4G kernel mode: + */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) goto clear_dr7; + if (!user_mode(regs)) { + // restore upon return-to-userspace: + set_thread_flag(TIF_DB7); + goto clear_dr7; + } } if (regs->eflags & VM_MASK) @@ -557,8 +632,18 @@ asmlinkage void do_debug(struct pt_regs * allowing programs to debug themselves without the ptrace() * interface. */ +#ifdef CONFIG_KGDB + /* + * I think this is the only "real" case of a TF in the kernel + * that really belongs to user space. Others are + * "Ours all ours!" + */ + if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry)) + goto clear_TF_reenable; +#else if ((regs->xcs & 3) == 0) goto clear_TF_reenable; +#endif if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -570,6 +655,17 @@ asmlinkage void do_debug(struct pt_regs info.si_errno = 0; info.si_code = TRAP_BRKPT; +#ifdef CONFIG_KGDB + /* + * If this is a kernel mode trap, we need to reset db7 to allow us + * to continue sanely ALSO skip the signal delivery + */ + if ((regs->xcs & 3) == 0) + goto clear_dr7; + + /* if not kernel, allow ints but only if they were on */ + if ( regs->eflags & 0x200) local_irq_enable(); +#endif /* If this is a kernel mode trap, save the user PC on entry to * the kernel, that's what the debugger can make sense of. */ @@ -584,6 +680,7 @@ clear_dr7: __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); + CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,) return; debug_vm86: @@ -779,19 +876,53 @@ asmlinkage void math_emulate(long arg) #endif /* CONFIG_MATH_EMULATION */ -#ifdef CONFIG_X86_F00F_BUG -void __init trap_init_f00f_bug(void) +void __init trap_init_virtual_IDT(void) { - __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); - /* - * Update the IDT descriptor and reload the IDT so that - * it uses the read-only mapped virtual address. + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. */ - idt_descr.address = fix_to_virt(FIX_F00F_IDT); + __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO); + idt_descr.address = __fix_to_virt(FIX_IDT); + __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); } + +void __init trap_init_virtual_GDT(void) +{ + int cpu = smp_processor_id(); + struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu; + struct Xgt_desc_struct tmp_desc = {0, 0}; + struct tss_struct * t; + + __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory"); + +#ifdef CONFIG_X86_HIGH_ENTRY + if (!cpu) { + __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL); + __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL); + __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL); + } + + gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu; +#else + gdt_desc->address = (unsigned long)cpu_gdt_table[cpu]; +#endif + __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc)); + +#ifdef CONFIG_X86_HIGH_ENTRY + t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else + t = init_tss + cpu; #endif + set_tss_desc(cpu, t); + cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + load_TR_desc(); +} #define _set_gate(gate_addr,type,dpl,addr,seg) \ do { \ @@ -818,20 +949,26 @@ void set_intr_gate(unsigned int n, void _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } -static void __init set_trap_gate(unsigned int n, void *addr) +void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); } -static void __init set_system_gate(unsigned int n, void *addr) +void __init set_system_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); } -static void __init set_call_gate(void *a, void *addr) +void __init set_call_gate(void *a, void *addr) { _set_gate(a,12,3,addr,__KERNEL_CS); } +#ifdef CONFIG_KGDB +void set_intr_usr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,3,addr,__KERNEL_CS); +} +#endif static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) { @@ -850,11 +987,16 @@ void __init trap_init(void) #ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif + init_entry_mappings(); set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); +#ifndef CONFIG_KGDB set_system_gate(3,&int3); /* int3-5 can be called from all */ +#else + set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */ +#endif set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); --- linux-2.6.1-rc1/arch/i386/kernel/vm86.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/kernel/vm86.c 2004-01-04 22:21:59.000000000 -0800 @@ -125,7 +125,7 @@ struct pt_regs * save_v86_state(struct k tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; - load_esp0(tss, ¤t->thread); + load_virtual_esp0(tss, current); current->thread.saved_esp0 = 0; put_cpu(); @@ -305,7 +305,7 @@ static void do_sys_vm86(struct kernel_vm tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; - load_esp0(tss, &tsk->thread); + load_virtual_esp0(tss, tsk); put_cpu(); tsk->thread.screen_bitmap = info->screen_bitmap; --- linux-2.6.1-rc1/arch/i386/kernel/vmlinux.lds.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/vmlinux.lds.S 2004-01-04 22:21:59.000000000 -0800 @@ -3,6 +3,9 @@ */ #include +#include +#include +#include OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -10,7 +13,7 @@ ENTRY(startup_32) jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { @@ -19,6 +22,19 @@ SECTIONS *(.gnu.warning) } = 0x9090 +#ifdef CONFIG_X86_4G + . = ALIGN(PAGE_SIZE_asm); + __entry_tramp_start = .; + . = FIX_ENTRY_TRAMPOLINE_0_addr; + __start___entry_text = .; + .entry.text : AT (__entry_tramp_start) { *(.entry.text) } + __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text); + . = __entry_tramp_end; + . = ALIGN(PAGE_SIZE_asm); +#else + .entry.text : { *(.entry.text) } +#endif + _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ @@ -34,15 +50,12 @@ SECTIONS CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_begin = .; .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_end = .; - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } @@ -52,7 +65,7 @@ SECTIONS .data.init_task : { *(.data.init_task) } /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE_asm); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -91,7 +104,7 @@ SECTIONS from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; @@ -99,10 +112,22 @@ SECTIONS __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __init_end = .; /* freed after init ends here */ - + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_tss : { *(.data.tss) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_default_ldt : { *(.data.default_ldt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_idt : { *(.data.idt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_gdt : { *(.data.gdt) } + __bss_start = .; /* BSS */ .bss : { *(.bss) } __bss_stop = .; @@ -122,4 +147,6 @@ SECTIONS .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } + + } --- linux-2.6.1-rc1/arch/i386/kernel/vsyscall.lds 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/vsyscall.lds 2004-01-04 22:21:59.000000000 -0800 @@ -5,7 +5,7 @@ */ /* This must match . */ -VSYSCALL_BASE = 0xffffe000; +VSYSCALL_BASE = 0xffffd000; SECTIONS { --- linux-2.6.1-rc1/arch/i386/kernel/vsyscall-sysenter.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/kernel/vsyscall-sysenter.S 2004-01-04 22:21:59.000000000 -0800 @@ -7,6 +7,11 @@ .type __kernel_vsyscall,@function __kernel_vsyscall: .LSTART_vsyscall: + cmpl $192, %eax + jne 1f + int $0x80 + ret +1: push %ecx .Lpush_ecx: push %edx --- linux-2.6.1-rc1/arch/i386/lib/checksum.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/checksum.S 2004-01-04 22:21:59.000000000 -0800 @@ -280,14 +280,14 @@ unsigned int csum_partial_copy_generic ( .previous .align 4 -.globl csum_partial_copy_generic +.globl direct_csum_partial_copy_generic #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: subl $4,%esp pushl %edi pushl %esi @@ -422,7 +422,7 @@ DST( movb %cl, (%edi) ) #define ARGBASE 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: pushl %ebx pushl %edi pushl %esi --- linux-2.6.1-rc1/arch/i386/lib/dec_and_lock.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/dec_and_lock.c 2004-01-04 22:21:58.000000000 -0800 @@ -10,6 +10,7 @@ #include #include +#ifndef ATOMIC_DEC_AND_LOCK int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -38,3 +39,5 @@ slow_path: spin_unlock(lock); return 0; } +#endif + --- linux-2.6.1-rc1/arch/i386/lib/getuser.S 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/getuser.S 2004-01-04 22:21:59.000000000 -0800 @@ -9,6 +9,7 @@ * return value. */ #include +#include /* @@ -28,7 +29,7 @@ .globl __get_user_1 __get_user_1: GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 1: movzbl (%eax),%edx xorl %eax,%eax @@ -40,7 +41,7 @@ __get_user_2: addl $1,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 2: movzwl -1(%eax),%edx xorl %eax,%eax @@ -52,7 +53,7 @@ __get_user_4: addl $3,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 3: movl -3(%eax),%edx xorl %eax,%eax --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/arch/i386/lib/kgdb_serial.c 2004-01-04 17:36:35.000000000 -0800 @@ -0,0 +1,499 @@ +/* + * Serial interface GDB stub + * + * Written (hacked together) by David Grothe (dave@gcom.com) + * Modified to allow invokation early in boot see also + * kgdb.h for instructions by George Anzinger(george@mvista.com) + * Modified to handle debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + */ + +#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 +#ifdef CONFIG_KGDB_USER_CONSOLE +extern void kgdb_console_finit(void); +#endif +#define PRNT_off +#define TEST_EXISTANCE +#ifdef PRNT +#define dbprintk(s) printk s +#else +#define dbprintk(s) +#endif +#define TEST_INTERRUPT_off +#ifdef TEST_INTERRUPT +#define intprintk(s) printk s +#else +#define intprintk(s) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char gdb_buf[GDB_BUF_SIZE]; +static int gdb_buf_in_inx; +static atomic_t gdb_buf_in_cnt; +static int gdb_buf_out_inx; + +struct async_struct *gdb_async_info; +static int gdb_async_irq; + +#define outb_px(a,b) outb_p(b,a) + +static void program_uart(struct async_struct *info); +static void write_char(struct async_struct *info, int chr); +/* + * Get a byte from the hardware data buffer and return it + */ +static int +read_data_bfr(struct async_struct *info) +{ + char it = inb_p(info->port + UART_LSR); + + if (it & UART_LSR_DR) + return (inb_p(info->port + UART_RX)); + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + program_uart(info); + write_char(info, '-'); + return ('-'); + } + return (-1); + +} /* read_data_bfr */ + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + + * Locking here is a bit of a problem. We MUST not lock out communication + * if we are trying to talk to gdb about a kgdb entry. ON the other hand + * we can loose chars in the console pass thru if we don't lock. It is also + * possible that we could hold the lock or be waiting for it when kgdb + * NEEDS to talk. Since kgdb locks down the world, it does not need locks. + * We do, of course have possible issues with interrupting a uart operation, + * but we will just depend on the uart status to help keep that straight. + + */ +static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SMP +extern spinlock_t kgdb_spinlock; +#endif + +static int +read_char(struct async_struct *info) +{ + int chr; + unsigned long flags; + local_irq_save(flags); +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_lock(&uart_interrupt_lock); + } +#endif + if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ + chr = gdb_buf[gdb_buf_out_inx++]; + gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&gdb_buf_in_cnt); + } else { + chr = read_data_bfr(info); + } +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_unlock(&uart_interrupt_lock); + } +#endif + local_irq_restore(flags); + return (chr); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +write_char(struct async_struct *info, int chr) +{ + while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ; + + outb_p(chr, info->port + UART_TX); + +} /* write_char */ + +/* + * Mostly we don't need a spinlock, but since the console goes + * thru here with interrutps on, well, we need to catch those + * chars. + */ +/* + * This is the receiver interrupt routine for the GDB stub. + * It will receive a limited number of characters of input + * from the gdb host machine and save them up in a buffer. + * + * When the gdb stub routine tty_getDebugChar() is called it + * draws characters out of the buffer until it is empty and + * then reads directly from the serial port. + * + * We do not attempt to write chars from the interrupt routine + * since the stubs do all of that via tty_putDebugChar() which + * writes one byte after waiting for the interface to become + * ready. + * + * The debug stubs like to run with interrupts disabled since, + * after all, they run as a consequence of a breakpoint in + * the kernel. + * + * Perhaps someone who knows more about the tty driver than I + * care to learn can make this work for any low level serial + * driver. + */ +static irqreturn_t +gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct async_struct *info; + unsigned long flags; + + info = gdb_async_info; + if (!info || !info->tty || irq != gdb_async_irq) + return IRQ_NONE; + + local_irq_save(flags); + spin_lock(&uart_interrupt_lock); + do { + int chr = read_data_bfr(info); + intprintk(("Debug char on int: %x hex\n", chr)); + if (chr < 0) + continue; + + if (chr == 3) { /* Ctrl-C means remote interrupt */ + BREAKPOINT; + continue; + } + + if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { + /* buffer overflow tosses early char */ + read_char(info); + } + gdb_buf[gdb_buf_in_inx++] = chr; + gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); + } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI); + spin_unlock(&uart_interrupt_lock); + local_irq_restore(flags); + return IRQ_HANDLED; +} /* gdb_interrupt */ + +/* + * Just a NULL routine for testing. + */ +void +gdb_null(void) +{ +} /* gdb_null */ + +/* These structure are filled in with values defined in asm/kgdb_local.h + */ +static struct serial_state state = SB_STATE; +static struct async_struct local_info = SB_INFO; +static int ok_to_enable_ints = 0; +static void kgdb_enable_ints_now(void); + +extern char *kgdb_version; +/* + * Hook an IRQ for KGDB. + * + * This routine is called from tty_putDebugChar, below. + */ +static int ints_disabled = 1; +int +gdb_hook_interrupt(struct async_struct *info, int verb) +{ + struct serial_state *state = info->state; + unsigned long flags; + int port; +#ifdef TEST_EXISTANCE + int scratch, scratch2; +#endif + + /* The above fails if memory managment is not set up yet. + * Rather than fail the set up, just keep track of the fact + * and pick up the interrupt thing later. + */ + gdb_async_info = info; + port = gdb_async_info->port; + gdb_async_irq = state->irq; + if (verb) { + printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", + kgdb_version, + port, + gdb_async_irq, gdb_async_info->state->custom_divisor); + } + local_irq_save(flags); +#ifdef TEST_EXISTANCE + /* Existance test */ + /* Should not need all this, but just in case.... */ + + scratch = inb_p(port + UART_IER); + outb_px(port + UART_IER, 0); + outb_px(0xff, 0x080); + scratch2 = inb_p(port + UART_IER); + outb_px(port + UART_IER, scratch); + if (scratch2) { + printk + ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); + local_irq_restore(flags); + return 1; /* We failed; there's nothing here */ + } + scratch2 = inb_p(port + UART_LCR); + outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */ + outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */ + outb_px(port + UART_LCR, 0); + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = inb_p(port + UART_IIR) >> 6; + if (scratch == 1) { + printk("gdb_hook_interrupt: Undefined UART type!" + " Not a UART! \n"); + local_irq_restore(flags); + return 1; + } else { + dbprintk(("gdb_hook_interrupt: UART type " + "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); + } + scratch = inb_p(port + UART_MCR); + outb_px(port + UART_MCR, UART_MCR_LOOP | scratch); + outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A); + scratch2 = inb_p(port + UART_MSR) & 0xF0; + outb_px(port + UART_MCR, scratch); + if (scratch2 != 0x90) { + printk("gdb_hook_interrupt: " + "Loop back test failed! Not a UART!\n"); + local_irq_restore(flags); + return scratch2 + 1000; /* force 0 to fail */ + } +#endif /* test existance */ + program_uart(info); + local_irq_restore(flags); + + return (0); + +} /* gdb_hook_interrupt */ + +static void +program_uart(struct async_struct *info) +{ + int port = info->port; + + (void) inb_p(port + UART_RX); + outb_px(port + UART_IER, 0); + + (void) inb_p(port + UART_RX); /* serial driver comments say */ + (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */ + (void) inb_p(port + UART_MSR); + outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */ + outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */ + outb_px(port + UART_MCR, info->MCR); + + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ + outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + return; +} + +/* + * tty_getDebugChar + * + * This is a GDB stub routine. It waits for a character from the + * serial interface and then returns it. If there is no serial + * interface connection then it returns a bogus value which will + * almost certainly cause the system to hang. In the + */ +int kgdb_in_isr = 0; +int kgdb_in_lsr = 0; +extern spinlock_t kgdb_spinlock; + +/* Caller takes needed protections */ + +int +tty_getDebugChar(void) +{ + volatile int chr, dum, time, end_time; + + dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + /* + * This trick says if we wait a very long time and get + * no char, return the -1 and let the upper level deal + * with it. + */ + rdtsc(dum, time); + end_time = time + 2; + while (((chr = read_char(gdb_async_info)) == -1) && + (end_time - time) > 0) { + rdtsc(dum, time); + }; + /* + * This covers our butts if some other code messes with + * our uart, hay, it happens :o) + */ + if (chr == -1) + program_uart(gdb_async_info); + + dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); + return (chr); + +} /* tty_getDebugChar */ + +static int count = 3; +static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; + +static int __init +kgdb_enable_ints(void) +{ + if (kgdboe) { + return 0; + } + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 1); + } + ok_to_enable_ints = 1; + kgdb_enable_ints_now(); +#ifdef CONFIG_KGDB_USER_CONSOLE + kgdb_console_finit(); +#endif + return 0; +} + +#ifdef CONFIG_SERIAL_8250 +void shutdown_for_kgdb(struct async_struct *gdb_async_info); +#endif + +#ifdef CONFIG_DISCONTIGMEM +static inline int kgdb_mem_init_done(void) +{ + return highmem_start_page != NULL; +} +#else +static inline int kgdb_mem_init_done(void) +{ + return max_mapnr != 0; +} +#endif + +static void +kgdb_enable_ints_now(void) +{ + if (!spin_trylock(&one_at_atime)) + return; + if (!ints_disabled) + goto exit; + if (kgdb_mem_init_done() && + ints_disabled) { /* don't try till mem init */ +#ifdef CONFIG_SERIAL_8250 + /* + * The ifdef here allows the system to be configured + * without the serial driver. + * Don't make it a module, however, it will steal the port + */ + shutdown_for_kgdb(gdb_async_info); +#endif + ints_disabled = request_irq(gdb_async_info->state->irq, + gdb_interrupt, + IRQ_T(gdb_async_info), + "KGDB-stub", NULL); + intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); + } + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + exit: + spin_unlock(&one_at_atime); +} + +/* + * tty_putDebugChar + * + * This is a GDB stub routine. It waits until the interface is ready + * to transmit a char and then sends it. If there is no serial + * interface connection then it simply returns to its caller, having + * pretended to send the char. Caller takes needed protections. + */ +void +tty_putDebugChar(int chr) +{ + dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", + gdb_async_info->port, + chr, + chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + + write_char(gdb_async_info, chr); /* this routine will wait */ + count = (chr == '#') ? 0 : count + 1; + if ((count == 2)) { /* try to enable after */ + if (ints_disabled & ok_to_enable_ints) + kgdb_enable_ints_now(); /* try to enable after */ + + /* We do this a lot because, well we really want to get these + * interrupts. The serial driver will clear these bits when it + * initializes the chip. Every thing else it does is ok, + * but this. + */ + if (!ints_disabled) { + outb_px(gdb_async_info->port + UART_IER, + gdb_async_info->IER); + } + } + +} /* tty_putDebugChar */ + +/* + * This does nothing for the serial port, since it doesn't buffer. + */ + +void tty_flushDebugChar(void) +{ +} + +module_init(kgdb_enable_ints); --- linux-2.6.1-rc1/arch/i386/lib/Makefile 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/Makefile 2004-01-04 17:36:33.000000000 -0800 @@ -9,4 +9,5 @@ lib-y = checksum.o delay.o \ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o lib-$(CONFIG_DEBUG_IOVIRT) += iodebug.o --- linux-2.6.1-rc1/arch/i386/lib/usercopy.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/lib/usercopy.c 2004-01-04 22:21:59.000000000 -0800 @@ -76,7 +76,7 @@ do { \ * and returns @count. */ long -__strncpy_from_user(char *dst, const char __user *src, long count) +__direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); @@ -102,7 +102,7 @@ __strncpy_from_user(char *dst, const cha * and returns @count. */ long -strncpy_from_user(char *dst, const char __user *src, long count) +direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -147,7 +147,7 @@ do { \ * On success, this will be zero. */ unsigned long -clear_user(void __user *to, unsigned long n) +direct_clear_user(void __user *to, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) @@ -167,7 +167,7 @@ clear_user(void __user *to, unsigned lon * On success, this will be zero. */ unsigned long -__clear_user(void __user *to, unsigned long n) +__direct_clear_user(void __user *to, unsigned long n) { __do_clear_user(to, n); return n; @@ -184,7 +184,7 @@ __clear_user(void __user *to, unsigned l * On exception, returns 0. * If the string is too long, returns a value greater than @n. */ -long strnlen_user(const char __user *s, long n) +long direct_strnlen_user(const char __user *s, long n) { unsigned long mask = -__addr_ok(s); unsigned long res, tmp; @@ -575,3 +575,4 @@ unsigned long __copy_from_user_ll(void * n = __copy_user_zeroing_intel(to, (const void *) from, n); return n; } + --- linux-2.6.1-rc1/arch/i386/mach-es7000/es7000.c 2003-06-16 22:32:20.000000000 -0700 +++ 25/arch/i386/mach-es7000/es7000.c 2004-01-04 22:15:28.000000000 -0800 @@ -51,8 +51,6 @@ struct mip_reg *host_reg; int mip_port; unsigned long mip_addr, host_addr; -static int es7000_plat; - /* * Parse the OEM Table */ --- linux-2.6.1-rc1/arch/i386/mach-voyager/voyager_smp.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/i386/mach-voyager/voyager_smp.c 2004-01-04 22:16:07.000000000 -0800 @@ -130,7 +130,7 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi) { int cpu; - for_each_cpu(cpu, cpu_online_map) { + for_each_online_cpu(cpu) { if(cpuset & (1< #include #include +#include /* This sets the pointer FPU_info to point to the argument part of the stack frame of math_emulate() */ @@ -22,7 +23,7 @@ /* s is always from a cpu register, and the cpu does bounds checking * during register load --> no further bounds checks needed */ -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) --- linux-2.6.1-rc1/arch/i386/mm/extable.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/mm/extable.c 2004-01-04 22:21:59.000000000 -0800 @@ -6,6 +6,52 @@ #include #include #include +#include + +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of sections + * as well as the init section and the main kernel text section. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void fixup_sort_exception_table(void) +{ + struct exception_table_entry *p; + + /* + * Fix up the trampoline exception addresses: + */ + for (p = __start___ex_table; p < __stop___ex_table; p++) { + p->insn = (unsigned long)(void *)p->insn; + p->fixup = (unsigned long)(void *)p->fixup; + } + sort_ex_table(__start___ex_table, __stop___ex_table); +} /* Simple binary search */ const struct exception_table_entry * @@ -15,13 +61,15 @@ search_extable(const struct exception_ta { while (first <= last) { const struct exception_table_entry *mid; - long diff; mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) + /* + * careful, the distance between entries can be + * larger than 2GB: + */ + if (mid->insn == value) return mid; - else if (diff < 0) + else if (mid->insn < value) first = mid+1; else last = mid-1; --- linux-2.6.1-rc1/arch/i386/mm/fault.c 2003-12-17 21:20:01.000000000 -0800 +++ 25/arch/i386/mm/fault.c 2004-01-04 22:21:59.000000000 -0800 @@ -27,6 +27,7 @@ #include #include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -104,8 +105,17 @@ static inline unsigned long get_segment_ if (seg & (1<<2)) { /* Must lock the LDT while reading it. */ down(¤t->mm->context.sem); +#if 1 + /* horrible hack for 4/4 disabled kernels. + I'm not quite sure what the TLB flush is good for, + it's mindlessly copied from the read_ldt code */ + __flush_tlb_global(); + desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]); + desc = (void *)desc + ((seg & ~7) % PAGE_SIZE); +#else desc = current->mm->context.ldt; desc = (void *)desc + (seg & ~7); +#endif } else { /* Must disable preemption while reading the GDT. */ desc = (u32 *)&cpu_gdt_table[get_cpu()]; @@ -118,6 +128,9 @@ static inline unsigned long get_segment_ (desc[1] & 0xff000000); if (seg & (1<<2)) { +#if 1 + kunmap((void *)((unsigned long)desc & PAGE_MASK)); +#endif up(¤t->mm->context.sem); } else put_cpu(); @@ -243,6 +256,19 @@ asmlinkage void do_page_fault(struct pt_ * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ +#ifdef CONFIG_X86_4G + /* + * On 4/4 all kernels faults are either bugs, vmalloc or prefetch + */ + if (unlikely((regs->xcs & 3) == 0)) { + if (error_code & 3) + goto bad_area_nosemaphore; + + /* If it's vm86 fall through */ + if (!(regs->eflags & VM_MASK)) + goto vmalloc_fault; + } +#else if (unlikely(address >= TASK_SIZE)) { if (!(error_code & 5)) goto vmalloc_fault; @@ -252,6 +278,7 @@ asmlinkage void do_page_fault(struct pt_ */ goto bad_area_nosemaphore; } +#endif mm = tsk->mm; @@ -403,6 +430,12 @@ no_context: * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ +#ifdef CONFIG_KGDB + if (!user_mode(regs)){ + kgdb_handle_exception(14,SIGBUS, error_code, regs); + return; + } +#endif bust_spinlocks(1); --- linux-2.6.1-rc1/arch/i386/mm/init.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/i386/mm/init.c 2004-01-04 22:21:59.000000000 -0800 @@ -40,125 +40,13 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; static int do_test_wp_bit(void); -/* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - if (pmd_table != pmd_offset(pgd, 0)) - BUG(); -#else - pmd_table = pmd_offset(pgd, 0); -#endif - - return pmd_table; -} - -/* - * Create a page table and place a pointer to it in a middle page - * directory entry. - */ -static pte_t * __init one_page_table_init(pmd_t *pmd) -{ - if (pmd_none(*pmd)) { - pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); - if (page_table != pte_offset_kernel(pmd, 0)) - BUG(); - - return page_table; - } - - return pte_offset_kernel(pmd, 0); -} - -/* - * This function initializes a certain range of kernel virtual memory - * with new bootmem page tables, everywhere page tables are missing in - * the given range. - */ - -/* - * NOTE: The pagetables are allocated contiguous on the physical space - * so we can cache the place of the first one and move around without - * checking the pgd every time. - */ -static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - int pgd_idx, pmd_idx; - unsigned long vaddr; - - vaddr = start; - pgd_idx = pgd_index(vaddr); - pmd_idx = pmd_index(vaddr); - pgd = pgd_base + pgd_idx; - - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - if (pgd_none(*pgd)) - one_md_table_init(pgd); - - pmd = pmd_offset(pgd, vaddr); - for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { - if (pmd_none(*pmd)) - one_page_table_init(pmd); - - vaddr += PMD_SIZE; - } - pmd_idx = 0; - } -} - -/* - * This maps the physical memory to kernel virtual address space, a total - * of max_low_pfn pages, by creating page tables starting from address - * PAGE_OFFSET. - */ -static void __init kernel_physical_mapping_init(pgd_t *pgd_base) -{ - unsigned long pfn; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int pgd_idx, pmd_idx, pte_ofs; - - pgd_idx = pgd_index(PAGE_OFFSET); - pgd = pgd_base + pgd_idx; - pfn = 0; - - for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - if (pfn >= max_low_pfn) - continue; - for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { - /* Map with big pages if possible, otherwise create normal page tables. */ - if (cpu_has_pse) { - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; - } else { - pte = one_page_table_init(pmd); - - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); - } - } - } -} - static inline int page_kills_ppro(unsigned long pagenr) { if (pagenr >= 0x70000 && pagenr <= 0x7003F) @@ -206,11 +94,8 @@ static inline int page_is_ram(unsigned l return 0; } -#ifdef CONFIG_HIGHMEM pte_t *kmap_pte; -pgprot_t kmap_prot; -EXPORT_SYMBOL(kmap_prot); EXPORT_SYMBOL(kmap_pte); #define kmap_get_fixmap_pte(vaddr) \ @@ -218,29 +103,7 @@ EXPORT_SYMBOL(kmap_pte); void __init kmap_init(void) { - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; -} - -void __init permanent_kmaps_init(pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long vaddr; - - vaddr = PKMAP_BASE; - page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + pgd_index(vaddr); - pmd = pmd_offset(pgd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; + kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); } void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) @@ -255,6 +118,8 @@ void __init one_highpage_init(struct pag SetPageReserved(page); } +#ifdef CONFIG_HIGHMEM + #ifndef CONFIG_DISCONTIGMEM void __init set_highmem_pages_init(int bad_ppro) { @@ -266,12 +131,9 @@ void __init set_highmem_pages_init(int b #else extern void set_highmem_pages_init(int); #endif /* !CONFIG_DISCONTIGMEM */ - #else -#define kmap_init() do { } while (0) -#define permanent_kmaps_init(pgd_base) do { } while (0) -#define set_highmem_pages_init(bad_ppro) do { } while (0) -#endif /* CONFIG_HIGHMEM */ +# define set_highmem_pages_init(bad_ppro) do { } while (0) +#endif unsigned long __PAGE_KERNEL = _PAGE_KERNEL; @@ -281,30 +143,125 @@ unsigned long __PAGE_KERNEL = _PAGE_KERN extern void __init remap_numa_kva(void); #endif -static void __init pagetable_init (void) +static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_base + pgd_index(address); + pmd = pmd_offset(pgd, address); + if (!pmd_present(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); + } +} + +static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) { unsigned long vaddr; - pgd_t *pgd_base = swapper_pg_dir; + for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE) + prepare_pagetables(pgd_base, vaddr); +} + +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) +{ + unsigned long vaddr; + pgd_t *pgd; + int i, j, k; + pmd_t *pmd; + pte_t *pte, *pte_base; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + if (cpu_has_pse) { + unsigned long __pe; + + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start; + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) + __pe += _PAGE_GLOBAL; + __PAGE_KERNEL |= _PAGE_GLOBAL; +#endif + } + set_pmd(pmd, __pmd(__pe)); + continue; + } + if (!pmd_present(*pmd)) + pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + else + pte_base = (pte_t *) page_address(pmd_page(*pmd)); + pte = pte_base; + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + *pte = mk_pte_phys(vaddr-start, PAGE_KERNEL); + } + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); + } + } +} + +static void __init pagetable_init (void) +{ + unsigned long vaddr, end; + pgd_t *pgd_base; #ifdef CONFIG_X86_PAE int i; - /* Init entries of the first-level page table to the zero page */ - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #endif - /* Enable PSE if available */ - if (cpu_has_pse) { - set_in_cr4(X86_CR4_PSE); - } + /* + * This can be zero as well - no problem, in that case we exit + * the loops anyway due to the PTRS_PER_* conditions. + */ + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); - /* Enable PGE if available */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); - __PAGE_KERNEL |= _PAGE_GLOBAL; + pgd_base = swapper_pg_dir; +#ifdef CONFIG_X86_PAE + /* + * It causes too many problems if there's no proper pmd set up + * for all 4 entries of the PGD - so we allocate all of them. + * PAE systems will not miss this extra 4-8K anyway ... + */ + for (i = 0; i < PTRS_PER_PGD; i++) { + pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1)); } +#endif + /* + * Set up lowmem-sized identity mappings at PAGE_OFFSET: + */ + setup_identity_mappings(pgd_base, PAGE_OFFSET, end); - kernel_physical_mapping_init(pgd_base); + /* + * Add flat-mode identity-mappings - SMP needs it when + * starting up on an AP from real-mode. (In the non-PAE + * case we already have these mappings through head.S.) + * All user-space mappings are explicitly cleared after + * SMP startup. + */ +#if CONFIG_SMP && CONFIG_X86_PAE + setup_identity_mappings(pgd_base, 0, 16*1024*1024); +#endif remap_numa_kva(); /* @@ -312,38 +269,64 @@ static void __init pagetable_init (void) * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - page_table_range_init(vaddr, 0, pgd_base); + fixrange_init(vaddr, 0, pgd_base); - permanent_kmaps_init(pgd_base); +#if CONFIG_HIGHMEM + { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + + pgd = swapper_pg_dir + pgd_index(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + pkmap_page_table = pte; + } #endif } -void zap_low_mappings (void) +/* + * Clear kernel pagetables in a PMD_SIZE-aligned range. + */ +static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { - int i; + unsigned long vaddr; + pgd_t *pgd; + pmd_t *pmd; + int i, j; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + pmd_clear(pmd); + } + } + flush_tlb_all(); +} + +void __init zap_low_mappings(void) +{ + printk("zapping low mappings.\n"); /* * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. */ - for (i = 0; i < USER_PTRS_PER_PGD; i++) -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - flush_tlb_all(); + clear_mappings(swapper_pg_dir, 0, 16*1024*1024); } #ifndef CONFIG_DISCONTIGMEM @@ -441,6 +424,7 @@ extern void set_max_mapnr_init(void); #endif /* !CONFIG_DISCONTIGMEM */ static struct kcore_list kcore_mem, kcore_vmalloc; +extern void fixup_sort_exception_table(void); void __init mem_init(void) { @@ -449,6 +433,8 @@ void __init mem_init(void) int tmp; int bad_ppro; + fixup_sort_exception_table(); + #ifndef CONFIG_DISCONTIGMEM if (!mem_map) BUG(); @@ -524,13 +510,18 @@ void __init mem_init(void) #ifndef CONFIG_SMP zap_low_mappings(); #endif + entry_trampoline_setup(); + default_ldt_page = virt_to_page(default_ldt); + load_LDT(&init_mm.context); } -kmem_cache_t *pgd_cache; -kmem_cache_t *pmd_cache; +kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; void __init pgtable_cache_init(void) { + void (*ctor)(void *, kmem_cache_t *, unsigned long); + void (*dtor)(void *, kmem_cache_t *, unsigned long); + if (PTRS_PER_PMD > 1) { pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), @@ -540,13 +531,36 @@ void __init pgtable_cache_init(void) NULL); if (!pmd_cache) panic("pgtable_cache_init(): cannot create pmd cache"); + + if (TASK_SIZE > PAGE_OFFSET) { + kpmd_cache = kmem_cache_create("kpmd", + PTRS_PER_PMD*sizeof(pmd_t), + 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, + kpmd_ctor, + NULL); + if (!kpmd_cache) + panic("pgtable_cache_init(): " + "cannot create kpmd cache"); + } } + + if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET) + ctor = pgd_ctor; + else + ctor = NULL; + + if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET) + dtor = pgd_dtor; + else + dtor = NULL; + pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD*sizeof(pgd_t), 0, SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, - pgd_ctor, - PTRS_PER_PMD == 1 ? pgd_dtor : NULL); + ctor, + dtor); if (!pgd_cache) panic("pgtable_cache_init(): Cannot create pgd cache"); } --- linux-2.6.1-rc1/arch/i386/mm/pgtable.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/i386/mm/pgtable.c 2004-01-04 22:21:59.000000000 -0800 @@ -21,6 +21,7 @@ #include #include #include +#include void show_mem(void) { @@ -157,11 +158,20 @@ void pmd_ctor(void *pmd, kmem_cache_t *c memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); } +void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags) +{ + pmd_t *kpmd, *pmd; + kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1], + (PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE); + pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS); + + memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t)); + memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t)); +} + /* - * List of all pgd's needed for non-PAE so it can invalidate entries - * in both cached and uncached pgd's; not needed for PAE since the - * kernel pmd is shared. If PAE were not to share the pmd a similar - * tactic would be needed. This is essentially codepath-based locking + * List of all pgd's needed so it can invalidate entries in both cached + * and uncached pgd's. This is essentially codepath-based locking * against pageattr.c; it is the unique case in which a valid change * of kernel pagetables can't be lazily synchronized by vmalloc faults. * vmalloc faults work because attached pagetables are never freed. @@ -170,30 +180,60 @@ void pmd_ctor(void *pmd, kmem_cache_t *c * could be used. The locking scheme was chosen on the basis of * manfred's recommendations and having no core impact whatsoever. * -- wli + * + * The entire issue goes away when XKVA is configured. */ spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(pgd_list); -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +/* + * This is not that hard to figure out. + * (a) PTRS_PER_PMD == 1 means non-PAE. + * (b) PTRS_PER_PMD > 1 means PAE. + * (c) TASK_SIZE > PAGE_OFFSET means XKVA. + * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA. + * + * Do *NOT* back out the preconstruction like the patch I'm cleaning + * up after this very instant did, or at all, for that matter. + * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET. + * -- wli + */ +void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused) { + pgd_t *pgd = (pgd_t *)__pgd; unsigned long flags; - if (PTRS_PER_PMD == 1) - spin_lock_irqsave(&pgd_lock, flags); + if (PTRS_PER_PMD == 1) { + if (TASK_SIZE <= PAGE_OFFSET) + spin_lock_irqsave(&pgd_lock, flags); + else + memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS], + &swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS], + NR_SHARED_PMDS * sizeof(pgd_t)); + } - memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + if (TASK_SIZE <= PAGE_OFFSET) + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); if (PTRS_PER_PMD > 1) return; - list_add(&virt_to_page(pgd)->lru, &pgd_list); - spin_unlock_irqrestore(&pgd_lock, flags); - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + if (TASK_SIZE > PAGE_OFFSET) + memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t)); + else { + list_add(&virt_to_page(pgd)->lru, &pgd_list); + spin_unlock_irqrestore(&pgd_lock, flags); + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + } } -/* never called when PTRS_PER_PMD > 1 */ +/* + * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET + * for with PAE we would list_del() multiple times, and for non-PAE + * with XKVA all the AGP pgd shootdown code is unnecessary. + */ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ @@ -203,6 +243,12 @@ void pgd_dtor(void *pgd, kmem_cache_t *c spin_unlock_irqrestore(&pgd_lock, flags); } +/* + * See the comments above pgd_ctor() wrt. preconstruction. + * Do *NOT* memcpy() here. If you do, you back out important + * anti- cache pollution code. + * + */ pgd_t *pgd_alloc(struct mm_struct *mm) { int i; @@ -211,15 +257,33 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (PTRS_PER_PMD == 1 || !pgd) return pgd; + /* + * In the 4G userspace case alias the top 16 MB virtual + * memory range into the user mappings as well (these + * include the trampoline and CPU data structures). + */ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { - pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + kmem_cache_t *cache; + pmd_t *pmd; + + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + pmd = kmem_cache_alloc(cache, GFP_KERNEL); if (!pmd) goto out_oom; set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd)))); } - return pgd; + return pgd; out_oom: + /* + * we don't have to handle the kpmd_cache here, since it's the + * last allocation, and has either nothing to free or when it + * succeeds the whole operation succeeds. + */ for (i--; i >= 0; i--) kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); kmem_cache_free(pgd_cache, pgd); @@ -230,10 +294,29 @@ void pgd_free(pgd_t *pgd) { int i; - /* in the PAE case user pgd entries are overwritten before usage */ - if (PTRS_PER_PMD > 1) - for (i = 0; i < USER_PTRS_PER_PGD; ++i) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); /* in the non-PAE case, clear_page_tables() clears user pgd entries */ + if (PTRS_PER_PMD == 1) + goto out_free; + + /* in the PAE case user pgd entries are overwritten before usage */ + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + kmem_cache_t *cache; + pmd_t *pmd = __va(pgd_val(pgd[i]) - 1); + + /* + * only userspace pmd's are cleared for us + * by mm/memory.c; it's a slab cache invariant + * that we must separate the kernel pmd slab + * all times, else we'll have bad pmd's. + */ + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + kmem_cache_free(cache, pmd); + } +out_free: kmem_cache_free(pgd_cache, pgd); } + --- linux-2.6.1-rc1/arch/i386/pci/acpi.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/i386/pci/acpi.c 2004-01-04 22:15:28.000000000 -0800 @@ -18,7 +18,7 @@ static int __init pci_acpi_init(void) if (pcibios_scanned) return 0; - if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { + if (!acpi_noirq) { if (!acpi_pci_irq_init()) { printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n"); @@ -31,15 +31,4 @@ static int __init pci_acpi_init(void) return 0; } - -/* - * pci_disable_acpi() - * act like pci=noacpi seen on command line - * called by DMI blacklist code - */ -__init void pci_disable_acpi(void) -{ - pci_probe |= PCI_NO_ACPI_ROUTING; -} - subsys_initcall(pci_acpi_init); --- linux-2.6.1-rc1/arch/i386/pci/common.c 2003-09-08 13:58:55.000000000 -0700 +++ 25/arch/i386/pci/common.c 2004-01-04 22:15:28.000000000 -0800 @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -197,12 +198,10 @@ char * __devinit pcibios_setup(char *st return NULL; } #endif -#ifdef CONFIG_ACPI_PCI else if (!strcmp(str, "noacpi")) { - pci_probe |= PCI_NO_ACPI_ROUTING; + acpi_noirq_set(); return NULL; } -#endif #ifndef CONFIG_X86_VISWS else if (!strcmp(str, "usepirqmask")) { pci_probe |= PCI_USE_PIRQ_MASK; --- linux-2.6.1-rc1/arch/i386/pci/fixup.c 2003-08-08 22:55:10.000000000 -0700 +++ 25/arch/i386/pci/fixup.c 2004-01-04 22:16:06.000000000 -0800 @@ -187,6 +187,22 @@ static void __devinit pci_fixup_transpar dev->transparent = 1; } +/* + * Halt Disconnect and Stop Grant Disconnect (bit 4 at offset 0x6F) + * must be disabled when APIC is used (or lockups will happen). + */ +static void __devinit pci_fixup_nforce2_disconnect(struct pci_dev *d) +{ + u8 t; + + pci_read_config_byte(d, 0x6F, &t); + if (t & 0x10) { + printk(KERN_INFO "PCI: disabling nForce2 Halt Disconnect" + " and Stop Grant Disconnect\n"); + pci_write_config_byte(d, 0x6F, (t & 0xef)); + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, @@ -205,5 +221,6 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2_disconnect }, { 0 } }; --- linux-2.6.1-rc1/arch/i386/pci/pci.h 2003-06-22 12:04:43.000000000 -0700 +++ 25/arch/i386/pci/pci.h 2004-01-04 22:15:28.000000000 -0800 @@ -22,7 +22,6 @@ #define PCI_ASSIGN_ROMS 0x1000 #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 -#define PCI_NO_ACPI_ROUTING 0x8000 extern unsigned int pci_probe; --- linux-2.6.1-rc1/arch/ia64/defconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/defconfig 2004-01-04 17:36:23.000000000 -0800 @@ -6,6 +6,10 @@ # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +# CONFIG_STANDALONE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y # # General setup @@ -15,9 +19,16 @@ CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=16 +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y CONFIG_FUTEX=y CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support @@ -33,6 +44,7 @@ CONFIG_KMOD=y # Processor type and features # CONFIG_IA64=y +CONFIG_64BIT=y CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_TIME_INTERPOLATION=y @@ -57,9 +69,7 @@ CONFIG_VIRTUAL_MEM_MAP=y CONFIG_IA64_MCA=y CONFIG_PM=y CONFIG_IOSAPIC=y -CONFIG_KCORE_ELF=y CONFIG_FORCE_MAX_ZONEORDER=18 -CONFIG_HUGETLB_PAGE=y # CONFIG_HUGETLB_PAGE_SIZE_4GB is not set # CONFIG_HUGETLB_PAGE_SIZE_1GB is not set # CONFIG_HUGETLB_PAGE_SIZE_256MB is not set @@ -68,11 +78,12 @@ CONFIG_HUGETLB_PAGE_SIZE_64MB=y # CONFIG_HUGETLB_PAGE_SIZE_4MB is not set # CONFIG_HUGETLB_PAGE_SIZE_1MB is not set # CONFIG_HUGETLB_PAGE_SIZE_256KB is not set -CONFIG_IA64_PAL_IDLE=y +# CONFIG_IA64_PAL_IDLE is not set CONFIG_SMP=y # CONFIG_PREEMPT is not set CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y +CONFIG_HAVE_DEC_LOCK=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y CONFIG_EFI=y @@ -82,7 +93,7 @@ CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y # -# ACPI Support +# ACPI (Advanced Configuration and Power Interface) Support # CONFIG_ACPI_BOOT=y CONFIG_ACPI_BUTTON=y @@ -94,6 +105,7 @@ CONFIG_ACPI_BUS=y CONFIG_ACPI_POWER=y CONFIG_ACPI_PCI=y CONFIG_ACPI_SYSTEM=y +# CONFIG_ACPI_RELAXED_AML is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y CONFIG_PCI_LEGACY_PROC=y @@ -139,12 +151,72 @@ CONFIG_HOTPLUG=y # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m +CONFIG_IDE_TASK_IOCTL=y +CONFIG_IDE_TASKFILE_IO=y + +# +# IDE chipset support/bugfixes +# +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_IDEDMA_PCI_WIP is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_HD is not set + +# # IEEE 1394 (FireWire) support (EXPERIMENTAL) # # CONFIG_IEEE1394 is not set @@ -157,7 +229,15 @@ CONFIG_BLK_DEV_INITRD=y # # Multi-device support (RAID and LVM) # -# CONFIG_MD is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_IOCTL_V4=y # # Fusion MPT device support @@ -169,9 +249,10 @@ CONFIG_FUSION_MAX_SGE=40 # CONFIG_FUSION_CTL is not set # -# SCSI support +# SCSI device support # CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y # # SCSI support type (disk, tape, CD-ROM) @@ -200,9 +281,9 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_AIC7XXX is not set CONFIG_SCSI_AIC7XXX_OLD=y # CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set CONFIG_SCSI_MEGARAID=y +# CONFIG_SCSI_SATA is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set @@ -210,6 +291,7 @@ CONFIG_SCSI_MEGARAID=y # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set CONFIG_SCSI_SYM53C8XX_2=y @@ -238,8 +320,6 @@ CONFIG_NET=y CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK_DEV is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -257,6 +337,16 @@ CONFIG_IP_MULTICAST=y # CONFIG_INET_IPCOMP is not set # +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# # IP: Netfilter Configuration # # CONFIG_IP_NF_CONNTRACK is not set @@ -264,10 +354,9 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_NF_IPTABLES is not set CONFIG_IP_NF_ARPTABLES=y # CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARP_MANGLE is not set # CONFIG_IP_NF_COMPAT_IPCHAINS is not set # CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_XFRM_USER is not set # # SCTP Configuration (EXPERIMENTAL) @@ -276,9 +365,9 @@ CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set -# CONFIG_LLC is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_NET_DIVERT is not set @@ -306,7 +395,6 @@ CONFIG_DUMMY=y CONFIG_BONDING=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set # # Ethernet (10 or 100Mbit) @@ -339,7 +427,6 @@ CONFIG_EEPRO100=y # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # @@ -353,8 +440,9 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set -CONFIG_TIGON3=m +CONFIG_TIGON3=y # # Ethernet (10000 Mbit) @@ -371,10 +459,10 @@ CONFIG_TIGON3=m # CONFIG_NET_RADIO is not set # -# Token Ring devices (depends on LLC=y) +# Token Ring devices # +# CONFIG_TR is not set # CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set # @@ -388,14 +476,19 @@ CONFIG_TIGON3=m # CONFIG_HAMRADIO is not set # -# ISDN subsystem +# IrDA (infrared) support # -# CONFIG_ISDN_BOOL is not set +# CONFIG_IRDA is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Bluetooth support # -# CONFIG_CD_NO_IDESCSI is not set +# CONFIG_BT is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN_BOOL is not set # # Input device support @@ -406,7 +499,7 @@ CONFIG_INPUT=y # Userland interfaces # CONFIG_INPUT_MOUSEDEV=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_PSAUX=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_INPUT_JOYDEV=y @@ -449,6 +542,7 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_ACPI=y CONFIG_SERIAL_8250_HCDP=y +CONFIG_SERIAL_8250_NR_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set # @@ -465,7 +559,11 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_I2C is not set # -# I2C Hardware Sensors Mainboard support +# I2C Algorithms +# + +# +# I2C Hardware Bus support # # @@ -509,8 +607,8 @@ CONFIG_DRM=y # CONFIG_DRM_R128 is not set CONFIG_DRM_RADEON=m # CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set # CONFIG_RAW_DRIVER is not set -# CONFIG_HANGCHECK_TIMER is not set # # Multimedia devices @@ -565,11 +663,13 @@ CONFIG_VFAT_FS=y # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y # @@ -594,6 +694,7 @@ CONFIG_RAMFS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y CONFIG_NFSD=y CONFIG_NFSD_V3=y # CONFIG_NFSD_V4 is not set @@ -630,11 +731,11 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_EFI_PARTITION=y -CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=y @@ -843,7 +944,6 @@ CONFIG_USB_HIDDEV=y # # USB Network adaptors # -# CONFIG_USB_AX8817X is not set # CONFIG_USB_CATC is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_PEGASUS is not set @@ -865,36 +965,40 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_GADGET is not set # -# Bluetooth support +# Library routines # -# CONFIG_BT is not set +CONFIG_CRC32=y # -# Library routines +# Profiling support # -CONFIG_CRC32=y +# CONFIG_PROFILING is not set # # Kernel hacking # -# CONFIG_IA64_GRANULE_16MB is not set -CONFIG_IA64_GRANULE_64MB=y +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y -CONFIG_KALLSYMS=y CONFIG_IA64_PRINT_HAZARDS=y # CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_IA64_EARLY_PRINTK is not set +CONFIG_IA64_EARLY_PRINTK=y +CONFIG_IA64_EARLY_PRINTK_UART=y +CONFIG_IA64_EARLY_PRINTK_UART_BASE=0xff5e0000 +CONFIG_IA64_EARLY_PRINTK_VGA=y # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set +CONFIG_DEBUG_INFO=y # # Security options --- linux-2.6.1-rc1/arch/ia64/hp/sim/boot/fw-emu.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/ia64/hp/sim/boot/fw-emu.c 2004-01-04 17:36:23.000000000 -0800 @@ -108,7 +108,7 @@ extern void pal_emulator_static (void); #define BUS_NUMBER(addr) (0x0000000000FF0000 & (addr)) static efi_status_t -efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) +fw_efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) { #if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC) struct { @@ -310,7 +310,7 @@ sys_fw_init (const char *args, int argle efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE; efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION; efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr); - efi_runtime->get_time = __pa(&efi_get_time); + efi_runtime->get_time = __pa(&fw_efi_get_time); efi_runtime->set_time = __pa(&efi_unimplemented); efi_runtime->get_wakeup_time = __pa(&efi_unimplemented); efi_runtime->set_wakeup_time = __pa(&efi_unimplemented); --- linux-2.6.1-rc1/arch/ia64/ia32/ia32_entry.S 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/ia64/ia32/ia32_entry.S 2004-01-04 17:36:23.000000000 -0800 @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -141,27 +142,35 @@ GLOBAL_ENTRY(ia32_trace_syscall) adds r2=IA64_PT_REGS_R8_OFFSET+16,sp ;; st8 [r2]=r3 // initialize return code to -ENOSYS - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args - // Need to reload arguments (they may be changed by the tracing process) - adds r2=IA64_PT_REGS_R9_OFFSET+16,sp // r2 = &pt_regs.r9 + br.call.sptk.few rp=syscall_trace // give parent a chance to catch syscall args +.ret2: // Need to reload arguments (they may be changed by the tracing process) + adds r2=IA64_PT_REGS_R1_OFFSET+16,sp // r2 = &pt_regs.r1 adds r3=IA64_PT_REGS_R13_OFFSET+16,sp // r3 = &pt_regs.r13 + mov r15=IA32_NR_syscalls + ;; + ld4 r8=[r2],IA64_PT_REGS_R9_OFFSET-IA64_PT_REGS_R1_OFFSET + movl r16=ia32_syscall_table ;; ld4 r33=[r2],8 // r9 == ecx ld4 r37=[r3],16 // r13 == ebp + cmp.ltu.unc p6,p7=r8,r15 ;; ld4 r34=[r2],8 // r10 == edx ld4 r36=[r3],8 // r15 == edi +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number + ;; + ld8 r16=[r16] ;; ld4 r32=[r2],8 // r11 == ebx + mov b6=r16 ld4 r35=[r3],8 // r14 == esi - ;; -.ret2: br.call.sptk.few rp=b6 // do the syscall + br.call.sptk.few rp=b6 // do the syscall .ia32_strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8.spill [r2]=r8 // store return value in slot for r8 - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value + br.call.sptk.few rp=syscall_trace // give parent a chance to catch return value .ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame br.cond.sptk.many ia64_leave_kernel END(ia32_trace_syscall) @@ -199,7 +208,7 @@ END(sys32_fork) .align 8 .globl ia32_syscall_table ia32_syscall_table: - data8 sys32_ni_syscall /* 0 - old "setup(" system call*/ + data8 sys_ni_syscall /* 0 - old "setup(" system call*/ data8 sys_exit data8 sys32_fork data8 sys_read @@ -216,25 +225,25 @@ ia32_syscall_table: data8 sys_mknod data8 sys_chmod /* 15 */ data8 sys_lchown /* 16-bit version */ - data8 sys32_ni_syscall /* old break syscall holder */ - data8 sys32_ni_syscall + data8 sys_ni_syscall /* old break syscall holder */ + data8 sys_ni_syscall data8 sys32_lseek data8 sys_getpid /* 20 */ data8 sys_mount data8 sys_oldumount data8 sys_setuid /* 16-bit version */ data8 sys_getuid /* 16-bit version */ - data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ + data8 sys_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm - data8 sys32_ni_syscall + data8 sys_ni_syscall data8 sys32_pause data8 compat_sys_utime /* 30 */ - data8 sys32_ni_syscall /* old stty syscall holder */ - data8 sys32_ni_syscall /* old gtty syscall holder */ + data8 sys_ni_syscall /* old stty syscall holder */ + data8 sys_ni_syscall /* old gtty syscall holder */ data8 sys_access data8 sys_nice - data8 sys32_ni_syscall /* 35 */ /* old ftime syscall holder */ + data8 sys_ni_syscall /* 35 */ /* old ftime syscall holder */ data8 sys_sync data8 sys_kill data8 sys_rename @@ -243,7 +252,7 @@ ia32_syscall_table: data8 sys_dup data8 sys32_pipe data8 compat_sys_times - data8 sys32_ni_syscall /* old prof syscall holder */ + data8 sys_ni_syscall /* old prof syscall holder */ data8 sys32_brk /* 45 */ data8 sys_setgid /* 16-bit version */ data8 sys_getgid /* 16-bit version */ @@ -252,13 +261,13 @@ ia32_syscall_table: data8 sys_getegid /* 16-bit version */ /* 50 */ data8 sys_acct data8 sys_umount /* recycled never used phys( */ - data8 sys32_ni_syscall /* old lock syscall holder */ + data8 sys_ni_syscall /* old lock syscall holder */ data8 compat_sys_ioctl data8 compat_sys_fcntl /* 55 */ - data8 sys32_ni_syscall /* old mpx syscall holder */ + data8 sys_ni_syscall /* old mpx syscall holder */ data8 sys_setpgid - data8 sys32_ni_syscall /* old ulimit syscall holder */ - data8 sys32_ni_syscall + data8 sys_ni_syscall /* old ulimit syscall holder */ + data8 sys_ni_syscall data8 sys_umask /* 60 */ data8 sys_chroot data8 sys_ustat @@ -267,8 +276,8 @@ ia32_syscall_table: data8 sys_getpgrp /* 65 */ data8 sys_setsid data8 sys32_sigaction - data8 sys32_ni_syscall - data8 sys32_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall data8 sys_setreuid /* 16-bit version */ /* 70 */ data8 sys_setregid /* 16-bit version */ data8 sys32_sigsuspend @@ -283,7 +292,7 @@ ia32_syscall_table: data8 sys32_setgroups16 data8 sys32_old_select data8 sys_symlink - data8 sys32_ni_syscall + data8 sys_ni_syscall data8 sys_readlink /* 85 */ data8 sys_uselib data8 sys_swapon @@ -297,7 +306,7 @@ ia32_syscall_table: data8 sys_fchown /* 16-bit version */ /* 95 */ data8 sys_getpriority data8 sys_setpriority - data8 sys32_ni_syscall /* old profil syscall holder */ + data8 sys_ni_syscall /* old profil syscall holder */ data8 compat_sys_statfs data8 compat_sys_fstatfs /* 100 */ data8 sys32_ioperm @@ -308,11 +317,11 @@ ia32_syscall_table: data8 compat_sys_newstat data8 compat_sys_newlstat data8 compat_sys_newfstat - data8 sys32_ni_syscall + data8 sys_ni_syscall data8 sys32_iopl /* 110 */ data8 sys_vhangup - data8 sys32_ni_syscall /* used to be sys_idle */ - data8 sys32_ni_syscall + data8 sys_ni_syscall /* used to be sys_idle */ + data8 sys_ni_syscall data8 compat_sys_wait4 data8 sys_swapoff /* 115 */ data8 sys32_sysinfo @@ -323,20 +332,20 @@ ia32_syscall_table: data8 sys_setdomainname data8 sys32_newuname data8 sys32_modify_ldt - data8 sys32_ni_syscall /* adjtimex */ + data8 sys_ni_syscall /* adjtimex */ data8 sys32_mprotect /* 125 */ data8 compat_sys_sigprocmask - data8 sys32_ni_syscall /* create_module */ - data8 sys32_ni_syscall /* init_module */ - data8 sys32_ni_syscall /* delete_module */ - data8 sys32_ni_syscall /* get_kernel_syms */ /* 130 */ + data8 sys_ni_syscall /* create_module */ + data8 sys_ni_syscall /* init_module */ + data8 sys_ni_syscall /* delete_module */ + data8 sys_ni_syscall /* get_kernel_syms */ /* 130 */ data8 sys_quotactl data8 sys_getpgid data8 sys_fchdir - data8 sys32_ni_syscall /* sys_bdflush */ + data8 sys_ni_syscall /* sys_bdflush */ data8 sys_sysfs /* 135 */ data8 sys32_personality - data8 sys32_ni_syscall /* for afs_syscall */ + data8 sys_ni_syscall /* for afs_syscall */ data8 sys_setfsuid /* 16-bit version */ data8 sys_setfsgid /* 16-bit version */ data8 sys_llseek /* 140 */ @@ -365,10 +374,10 @@ ia32_syscall_table: data8 sys_mremap data8 sys_setresuid /* 16-bit version */ data8 sys32_getresuid16 /* 16-bit version */ /* 165 */ - data8 sys32_ni_syscall /* vm86 */ - data8 sys32_ni_syscall /* sys_query_module */ + data8 sys_ni_syscall /* vm86 */ + data8 sys_ni_syscall /* sys_query_module */ data8 sys_poll - data8 sys32_ni_syscall /* nfsservctl */ + data8 sys_ni_syscall /* nfsservctl */ data8 sys_setresgid /* 170 */ data8 sys32_getresgid16 data8 sys_prctl @@ -387,8 +396,8 @@ ia32_syscall_table: data8 sys_capset /* 185 */ data8 sys32_sigaltstack data8 sys32_sendfile - data8 sys32_ni_syscall /* streams1 */ - data8 sys32_ni_syscall /* streams2 */ + data8 sys_ni_syscall /* streams1 */ + data8 sys_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ data8 compat_sys_getrlimit data8 sys32_mmap2 @@ -425,54 +434,55 @@ ia32_syscall_table: data8 sys_ni_syscall /* reserved for Security */ data8 sys_gettid data8 sys_readahead /* 225 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 230 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 235 */ - data8 sys_ni_syscall - data8 sys_ni_syscall + data8 sys_setxattr + data8 sys_lsetxattr + data8 sys_fsetxattr + data8 sys_getxattr + data8 sys_lgetxattr /* 230 */ + data8 sys_fgetxattr + data8 sys_listxattr + data8 sys_llistxattr + data8 sys_flistxattr + data8 sys_removexattr /* 235 */ + data8 sys_lremovexattr + data8 sys_fremovexattr data8 sys_tkill - data8 sys_ni_syscall + data8 sys_sendfile64 data8 compat_sys_futex /* 240 */ data8 compat_sys_sched_setaffinity data8 compat_sys_sched_getaffinity data8 sys32_set_thread_area data8 sys32_get_thread_area - data8 sys_ni_syscall /* 245 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 250 */ + data8 compat_sys_io_setup /* 245 */ + data8 sys_io_destroy + data8 compat_sys_io_getevents + data8 compat_sys_io_submit + data8 sys_io_cancel + data8 sys_fadvise64 /* 250 */ data8 sys_ni_syscall data8 sys_exit_group - data8 sys_ni_syscall + data8 sys_lookup_dcookie data8 sys_epoll_create data8 sys32_epoll_ctl /* 255 */ data8 sys32_epoll_wait data8 sys_remap_file_pages data8 sys_set_tid_address - data8 sys_ni_syscall - data8 sys_ni_syscall /* 260 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 265 */ - data8 sys_ni_syscall - data8 sys_ni_syscall + data8 sys32_timer_create + data8 compat_timer_settime /* 260 */ + data8 compat_timer_gettime + data8 sys_timer_getoverrun + data8 sys_timer_delete + data8 compat_clock_settime + data8 compat_clock_gettime /* 265 */ + data8 compat_clock_getres + data8 compat_clock_nanosleep data8 sys_statfs64 data8 sys_fstatfs64 - data8 sys_ni_syscall - - /* - * CAUTION: If any system calls are added beyond this point - * then the check in `arch/ia64/kernel/ivt.S' will have - * to be modified also. You've been warned. - */ + data8 sys_tgkill /* 270 */ + data8 compat_sys_utimes + data8 sys32_fadvise64_64 + data8 sys_ni_syscall + data8 sys_ni_syscall + + // guard against failures to increase IA32_NR_syscalls + .org ia32_syscall_table + 8*IA32_NR_syscalls --- linux-2.6.1-rc1/arch/ia64/ia32/ia32priv.h 2003-10-25 14:45:44.000000000 -0700 +++ 25/arch/ia64/ia32/ia32priv.h 2004-01-04 17:36:23.000000000 -0800 @@ -199,6 +199,8 @@ typedef union sigval32 { unsigned int sival_ptr; } sigval_t32; +#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3) + typedef struct siginfo32 { int si_signo; int si_errno; @@ -251,6 +253,19 @@ typedef struct siginfo32 { } _sifields; } siginfo_t32; +typedef struct sigevent32 { + sigval_t32 sigev_value; + int sigev_signo; + int sigev_notify; + union { + int _pad[SIGEV_PAD_SIZE32]; + struct { + u32 _function; + u32 _attribute; /* really pthread_attr_t */ + } _sigev_thread; + } _sigev_un; +} sigevent_t32; + struct old_linux32_dirent { u32 d_ino; u32 d_offset; --- linux-2.6.1-rc1/arch/ia64/ia32/sys_ia32.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/ia32/sys_ia32.c 2004-01-04 17:36:23.000000000 -0800 @@ -2164,19 +2164,6 @@ sys32_ptrace (int request, pid_t pid, un return ret; } -asmlinkage long sys_ni_syscall(void); - -asmlinkage long -sys32_ni_syscall (int dummy0, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, - int dummy6, int dummy7, int stack) -{ - struct pt_regs *regs = (struct pt_regs *)&stack; - - printk(KERN_WARNING "IA32 syscall #%d issued, maybe we should implement it\n", - (int)regs->r1); - return(sys_ni_syscall()); -} - /* * The IA64 maps 4 I/O ports for each 4K page */ @@ -2925,6 +2912,54 @@ sys32_get_thread_area (struct ia32_user_ return 0; } +extern asmlinkage long +sys_timer_create(clockid_t which_clock, struct sigevent *timer_event_spec, + timer_t * created_timer_id); + +asmlinkage long +sys32_timer_create(u32 clock, struct sigevent32 *se32, timer_t *timer_id) +{ + struct sigevent se; + mm_segment_t oldfs; + timer_t t; + long err; + + if (se32 == NULL) + return sys_timer_create(clock, NULL, timer_id); + + memset(&se, 0, sizeof(struct sigevent)); + if (get_user(se.sigev_value.sival_int, &se32->sigev_value.sival_int) || + __get_user(se.sigev_signo, &se32->sigev_signo) || + __get_user(se.sigev_notify, &se32->sigev_notify) || + __copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad, + sizeof(se._sigev_un._pad))) + return -EFAULT; + + if (!access_ok(VERIFY_WRITE,timer_id,sizeof(timer_t))) + return -EFAULT; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_timer_create(clock, &se, &t); + set_fs(oldfs); + + if (!err) + err = __put_user (t, timer_id); + + return err; +} + +extern long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice); + +long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, + __u32 len_low, __u32 len_high, int advice) +{ + return sys_fadvise64_64(fd, + (((u64)offset_high)<<32) | offset_low, + (((u64)len_high)<<32) | len_low, + advice); +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ struct ncp_mount_data32 { --- linux-2.6.1-rc1/arch/ia64/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/Kconfig 2004-01-04 22:21:58.000000000 -0800 @@ -667,6 +667,13 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + endmenu source "security/Kconfig" --- linux-2.6.1-rc1/arch/ia64/kernel/entry.h 2003-07-10 18:50:30.000000000 -0700 +++ 25/arch/ia64/kernel/entry.h 2004-01-04 17:36:23.000000000 -0800 @@ -4,7 +4,7 @@ * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! */ -#define pLvSys p1 /* set 1 if leave from syscall; otherwise, set 0*/ +#define pLvSys p1 /* set 1 if leave from syscall; otherwise, set 0 */ #define pKStk p2 /* will leave_{kernel,syscall} return to kernel-stacks? */ #define pUStk p3 /* will leave_{kernel,syscall} return to user-stacks? */ #define pSys p4 /* are we processing a (synchronous) system call? */ --- linux-2.6.1-rc1/arch/ia64/kernel/entry.S 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/ia64/kernel/entry.S 2004-01-04 17:36:23.000000000 -0800 @@ -484,33 +484,10 @@ GLOBAL_ENTRY(clone) END(clone) /* - * We invoke syscall_trace through this intermediate function to - * ensure that the syscall input arguments are not clobbered. We - * also use it to preserve b6, which contains the syscall entry point. - */ -GLOBAL_ENTRY(invoke_syscall_trace) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) - alloc loc1=ar.pfs,8,3,0,0 - mov loc0=rp - .body - mov loc2=b6 - ;; - br.call.sptk.many rp=syscall_trace -.ret3: mov rp=loc0 - mov ar.pfs=loc1 - mov b6=loc2 - br.ret.sptk.many rp -END(invoke_syscall_trace) - - /* * Invoke a system call, but do some tracing before and after the call. * We MUST preserve the current register frame throughout this routine * because some system calls (such as ia64_execve) directly * manipulate ar.pfs. - * - * Input: - * r15 = syscall number - * b6 = syscall entry point */ .global ia64_strace_leave_kernel @@ -522,21 +499,38 @@ GLOBAL_ENTRY(ia64_trace_syscall) */ nop.m 0 nop.i 0 - br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args + br.call.sptk.many rp=syscall_trace // give parent a chance to catch syscall args } -.ret6: br.call.sptk.many rp=b6 // do the syscall -strace_check_retval: + // the syscall number may have changed, so re-load it and re-calculate the + // syscall entry-point: + adds r15=PT(R15)+16,sp // r15 = &pt_regs.r15 (syscall #) + ;; + ld8 r15=[r15] + mov r3=NR_syscalls - 1 + ;; + adds r15=-1024,r15 + movl r16=sys_call_table + ;; + shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) + cmp.leu p6,p7=r15,r3 + ;; +(p6) ld8 r20=[r20] // load address of syscall entry point +(p7) movl r20=sys_ni_syscall + ;; + mov b6=r20 + br.call.sptk.many rp=b6 // do the syscall +.strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 mov r10=0 (p6) br.cond.sptk strace_error // syscall failed -> ;; // avoid RAW on r10 -strace_save_retval: +.strace_save_retval: .mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: - br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value + br.call.sptk.many rp=syscall_trace // give parent a chance to catch return value .rety: br.cond.sptk ia64_leave_syscall strace_error: @@ -548,7 +542,7 @@ strace_error: ;; (p6) mov r10=-1 (p6) mov r8=r9 - br.cond.sptk strace_save_retval + br.cond.sptk .strace_save_retval END(ia64_trace_syscall) GLOBAL_ENTRY(ia64_ret_from_clone) @@ -573,7 +567,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ;; mov r8=0 tbit.nz p6,p0=r2,TIF_SYSCALL_TRACE -(p6) br.cond.spnt strace_check_retval +(p6) br.cond.spnt .strace_check_retval ;; // added stop bits to prevent r8 dependency END(ia64_ret_from_clone) // fall through @@ -726,6 +720,7 @@ GLOBAL_ENTRY(ia64_leave_syscall) mov b6=r22 // restore b6 shr.u r18=r19,16 // get byte size of existing "dirty" partition (pKStk) br.cond.dpnt.many skip_rbs_switch +(pNonSys) br.cond.dpnt.many dont_preserve_current_frame br.cond.sptk.many rbs_switch END(ia64_leave_syscall) @@ -1334,9 +1329,9 @@ sys_call_table: data8 sys_syslog data8 sys_setitimer data8 sys_getitimer - data8 ia64_ni_syscall // 1120 /* was: ia64_oldstat */ - data8 ia64_ni_syscall /* was: ia64_oldlstat */ - data8 ia64_ni_syscall /* was: ia64_oldfstat */ + data8 sys_ni_syscall // 1120 /* was: ia64_oldstat */ + data8 sys_ni_syscall /* was: ia64_oldlstat */ + data8 sys_ni_syscall /* was: ia64_oldfstat */ data8 sys_vhangup data8 sys_lchown data8 sys_remap_file_pages // 1125 @@ -1346,16 +1341,16 @@ sys_call_table: data8 sys_setdomainname data8 sys_newuname // 1130 data8 sys_adjtimex - data8 ia64_ni_syscall /* was: ia64_create_module */ + data8 sys_ni_syscall /* was: ia64_create_module */ data8 sys_init_module data8 sys_delete_module - data8 ia64_ni_syscall // 1135 /* was: sys_get_kernel_syms */ - data8 ia64_ni_syscall /* was: sys_query_module */ + data8 sys_ni_syscall // 1135 /* was: sys_get_kernel_syms */ + data8 sys_ni_syscall /* was: sys_query_module */ data8 sys_quotactl data8 sys_bdflush data8 sys_sysfs data8 sys_personality // 1140 - data8 ia64_ni_syscall // sys_afs_syscall + data8 sys_ni_syscall // sys_afs_syscall data8 sys_setfsuid data8 sys_setfsgid data8 sys_getdents @@ -1473,26 +1468,26 @@ sys_call_table: data8 sys_clock_nanosleep data8 sys_fstatfs64 data8 sys_statfs64 - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1260 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1265 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1270 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1275 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall // 1260 + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall // 1265 + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall // 1270 + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall // 1275 + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls --- linux-2.6.1-rc1/arch/ia64/kernel/ivt.S 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/kernel/ivt.S 2004-01-04 17:36:23.000000000 -0800 @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -705,13 +706,14 @@ ENTRY(break_fault) movl r2=ia64_ret_from_syscall ;; shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) - cmp.geu p0,p7=r3,r15 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? + cmp.leu p6,p7=r15,r3 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? mov rp=r2 // set the real return addr ;; -(p7) add r20=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall +(p6) ld8 r20=[r20] // load address of syscall entry point +(p7) movl r20=sys_ni_syscall + add r2=TI_FLAGS+IA64_TASK_SIZE,r13 ;; - ld8 r20=[r20] // load address of syscall entry point ld4 r2=[r2] // r2 = current_thread_info()->flags ;; tbit.z p8,p0=r2,TIF_SYSCALL_TRACE @@ -1513,7 +1515,7 @@ ENTRY(dispatch_to_ia32_handler) alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; ld4 r8=[r14],8 // r8 == eax (syscall number) - mov r15=270 // number of entries in ia32 system call table + mov r15=IA32_NR_syscalls ;; cmp.ltu.unc p6,p7=r8,r15 ld4 out1=[r14],8 // r9 == ecx --- linux-2.6.1-rc1/arch/ia64/kernel/perfmon.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ia64/kernel/perfmon.c 2004-01-04 17:36:43.000000000 -0800 @@ -2157,6 +2157,7 @@ pfm_alloc_fd(struct file **cfile) d_add(file->f_dentry, inode); file->f_vfsmnt = mntget(pfmfs_mnt); + file->f_mapping = inode->i_mapping; file->f_op = &pfm_file_ops; file->f_mode = FMODE_READ; --- linux-2.6.1-rc1/arch/ia64/kernel/perfmon_default_smpl.c 2003-10-25 14:45:44.000000000 -0700 +++ 25/arch/ia64/kernel/perfmon_default_smpl.c 2004-01-04 17:36:23.000000000 -0800 @@ -114,7 +114,7 @@ default_handler(struct task_struct *task pfm_default_smpl_hdr_t *hdr; pfm_default_smpl_entry_t *ent; void *cur, *last; - unsigned long *e; + unsigned long *e, entry_size; unsigned int npmds, i; unsigned char ovfl_pmd; unsigned char ovfl_notify; @@ -131,8 +131,7 @@ default_handler(struct task_struct *task ovfl_notify = arg->ovfl_notify; /* - * check for space against largest possibly entry. - * We may waste space at the end of the buffer. + * precheck for sanity */ if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; @@ -142,6 +141,8 @@ default_handler(struct task_struct *task prefetch(arg->smpl_pmds_values); + entry_size = sizeof(*ent) + (npmds << 3); + /* position for first pmd */ e = (unsigned long *)(ent+1); @@ -191,7 +192,13 @@ default_handler(struct task_struct *task /* * update position for next entry */ - hdr->hdr_cur_offs += sizeof(*ent) + (npmds << 3); + hdr->hdr_cur_offs += entry_size; + cur += entry_size; + + /* + * post check to avoid losing the last sample + */ + if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; /* * keep same ovfl_pmds, ovfl_notify --- linux-2.6.1-rc1/arch/ia64/kernel/ptrace.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/arch/ia64/kernel/ptrace.c 2004-01-04 17:36:23.000000000 -0800 @@ -29,6 +29,11 @@ #include #endif +#include "entry.h" + +#define p4 (1UL << 4) /* for pSys (see entry.h) */ +#define p5 (1UL << 5) /* for pNonSys (see entry.h) */ + /* * Bits in the PSR that we allow ptrace() to change: * be, up, ac, mfl, mfh (the user mask; five bits total) @@ -51,6 +56,14 @@ # define dprintk(format...) #endif +/* Return TRUE if PT was created due to kernel-entry via a system-call. */ + +static inline int +in_syscall (struct pt_regs *pt) +{ + return (long) pt->cr_ifs >= 0; +} + /* * Collect the NaT bits for r1-r31 from scratch_unat and return a NaT * bitset where bit i is set iff the NaT bit of register i is set. @@ -272,7 +285,7 @@ put_rnat (struct task_struct *task, stru ubspstore = (unsigned long *) pt->ar_bspstore; urbs_kargs = urbs_end; - if ((long)pt->cr_ifs >= 0) { + if (in_syscall(pt)) { /* * If entered via syscall, don't allow user to set rnat bits * for syscall args. @@ -331,6 +344,13 @@ put_rnat (struct task_struct *task, stru *rnat1_kaddr = ((*rnat1_kaddr & ~m) | (rnat1 & m)); } +static inline int +on_kernel_rbs (unsigned long addr, unsigned long bspstore, unsigned long urbs_end) +{ + return (addr >= bspstore + && addr <= (unsigned long) ia64_rse_rnat_addr((unsigned long *) urbs_end)); +} + /* * Read a word from the user-level backing store of task CHILD. ADDR is the user-level * address to read the word from, VAL a pointer to the return value, and USER_BSP gives @@ -355,7 +375,7 @@ ia64_peek (struct task_struct *child, st child_regs = ia64_task_regs(child); bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(urbs_end)) { + if (on_kernel_rbs(addr, (unsigned long) bspstore, (unsigned long) urbs_end)) { /* * Attempt to read the RBS in an area that's actually on the kernel RBS => * read the corresponding bits in the kernel RBS. @@ -406,7 +426,7 @@ ia64_poke (struct task_struct *child, st child_regs = ia64_task_regs(child); bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(urbs_end)) { + if (on_kernel_rbs(addr, (unsigned long) bspstore, (unsigned long) urbs_end)) { /* * Attempt to write the RBS in an area that's actually on the kernel RBS * => write the corresponding bits in the kernel RBS. @@ -443,7 +463,7 @@ ia64_get_user_rbs_end (struct task_struc ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); cfm = pt->cr_ifs & ~(1UL << 63); - if ((long) pt->cr_ifs >= 0) { + if (in_syscall(pt)) { /* * If bit 63 of cr.ifs is cleared, the kernel was entered via a system * call and we need to recover the CFM that existed on entry to the @@ -483,134 +503,80 @@ ia64_sync_user_rbs (struct task_struct * return 0; } -/* - * Simulate user-level "flushrs". Note: we can't just add pt->loadrs>>16 to - * pt->ar_bspstore because the kernel backing store and the user-level backing store may - * have different alignments (and therefore a different number of intervening rnat slots). - */ -static void -user_flushrs (struct task_struct *task, struct pt_regs *pt) -{ - unsigned long *krbs; - long ndirty; - - krbs = (unsigned long *) task + IA64_RBS_OFFSET/8; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - - pt->ar_bspstore = (unsigned long) ia64_rse_skip_regs((unsigned long *) pt->ar_bspstore, - ndirty); - pt->loadrs = 0; -} - -static inline void -sync_user_rbs_one_thread (struct task_struct *p, int make_writable) +static inline int +thread_matches (struct task_struct *thread, unsigned long addr) { - struct switch_stack *sw; - unsigned long urbs_end; - struct pt_regs *pt; - - sw = (struct switch_stack *) (p->thread.ksp + 16); - pt = ia64_task_regs(p); - urbs_end = ia64_get_user_rbs_end(p, pt, NULL); - ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end); - if (make_writable) - user_flushrs(p, pt); -} - -struct task_list { - struct task_list *next; - struct task_struct *task; -}; + unsigned long thread_rbs_end; + struct pt_regs *thread_regs; -#ifdef CONFIG_SMP - -static inline void -collect_task (struct task_list **listp, struct task_struct *p, int make_writable) -{ - struct task_list *e; - - e = kmalloc(sizeof(*e), GFP_KERNEL); - if (!e) - /* oops, can't collect more: finish at least what we collected so far... */ - return; - - get_task_struct(p); - e->task = p; - e->next = *listp; - *listp = e; -} + if (ptrace_check_attach(thread, 0) < 0) + /* + * If the thread is not in an attachable state, we'll ignore it. + * The net effect is that if ADDR happens to overlap with the + * portion of the thread's register backing store that is + * currently residing on the thread's kernel stack, then ptrace() + * may end up accessing a stale value. But if the thread isn't + * stopped, that's a problem anyhow, so we're doing as well as we + * can... + */ + return 0; -static inline struct task_list * -finish_task (struct task_list *list, int make_writable) -{ - struct task_list *next = list->next; + thread_regs = ia64_task_regs(thread); + thread_rbs_end = ia64_get_user_rbs_end(thread, thread_regs, NULL); + if (!on_kernel_rbs(addr, thread_regs->ar_bspstore, thread_rbs_end)) + return 0; - sync_user_rbs_one_thread(list->task, make_writable); - put_task_struct(list->task); - kfree(list); - return next; + return 1; /* looks like we've got a winner */ } -#else -# define collect_task(list, p, make_writable) sync_user_rbs_one_thread(p, make_writable) -# define finish_task(list, make_writable) (NULL) -#endif - /* - * Synchronize the RSE backing store of CHILD and all tasks that share the address space - * with it. CHILD_URBS_END is the address of the end of the register backing store of - * CHILD. If MAKE_WRITABLE is set, a user-level "flushrs" is simulated such that the VM - * can be written via ptrace() and the tasks will pick up the newly written values. It - * would be OK to unconditionally simulate a "flushrs", but this would be more intrusive - * than strictly necessary (e.g., it would make it impossible to obtain the original value - * of ar.bspstore). + * GDB apparently wants to be able to read the register-backing store of any thread when + * attached to a given process. If we are peeking or poking an address that happens to + * reside in the kernel-backing store of another thread, we need to attach to that thread, + * because otherwise we end up accessing stale data. + * + * task_list_lock must be read-locked before calling this routine! */ -static void -threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable) +static struct task_struct * +find_thread_for_addr (struct task_struct *child, unsigned long addr) { - struct switch_stack *sw; struct task_struct *g, *p; struct mm_struct *mm; - struct pt_regs *pt; - long multi_threaded; + int mm_users; - task_lock(child); - { - mm = child->mm; - multi_threaded = mm && (atomic_read(&mm->mm_users) > 1); - } - task_unlock(child); + if (!(mm = get_task_mm(child))) + return child; - if (!multi_threaded) { - sw = (struct switch_stack *) (child->thread.ksp + 16); - pt = ia64_task_regs(child); - ia64_sync_user_rbs(child, sw, pt->ar_bspstore, child_urbs_end); - if (make_writable) - user_flushrs(child, pt); - } else { - /* - * Note: we can't call ia64_sync_user_rbs() while holding the - * tasklist_lock because that may cause a dead-lock: ia64_sync_user_rbs() - * may indirectly call tlb_flush_all(), which triggers an IPI. - * Furthermore, tasklist_lock is acquired by fork() with interrupts - * disabled, so with the right timing, the IPI never completes, hence - * tasklist_lock never gets released, hence fork() never completes... - */ - struct task_list *list = NULL; + mm_users = atomic_read(&mm->mm_users) - 1; /* -1 because of our get_task_mm()... */ + if (mm_users <= 1) + goto out; /* not multi-threaded */ - read_lock(&tasklist_lock); - { - do_each_thread(g, p) { - if (p->mm == mm && p->state != TASK_RUNNING) - collect_task(&list, p, make_writable); - } while_each_thread(g, p); + /* + * First, traverse the child's thread-list. Good for scalability with + * NPTL-threads. + */ + p = child; + do { + if (thread_matches(p, addr)) { + child = p; + goto out; } - read_unlock(&tasklist_lock); + if (mm_users-- <= 1) + goto out; + } while ((p = next_thread(p)) != child); - while (list) - list = finish_task(list, make_writable); - } - child->thread.flags |= IA64_THREAD_KRBS_SYNCED; /* set the flag in the child thread only */ + do_each_thread(g, p) { + if (child->mm != mm) + continue; + + if (thread_matches(p, addr)) { + child = p; + goto out; + } + } while_each_thread(g, p); + out: + mmput(mm); + return child; } /* @@ -668,12 +634,40 @@ access_fr (struct unw_frame_info *info, return ret; } +/* + * Change the machine-state of CHILD such that it will return via the normal + * kernel exit-path, rather than the syscall-exit path. + */ +static void +convert_to_non_syscall (struct task_struct *child, struct pt_regs *pt, unsigned long cfm) +{ + struct unw_frame_info info, prev_info; + unsigned long ip, pr; + + unw_init_from_blocked_task(&info, child); + while (1) { + prev_info = info; + if (unw_unwind(&info) < 0) + return; + if (unw_get_rp(&info, &ip) < 0) + return; + if (ip < FIXADDR_USER_END) + break; + } + + unw_get_pr(&prev_info, &pr); + pr &= ~pSys; + pr |= pNonSys; + unw_set_pr(&prev_info, pr); + + pt->cr_ifs = (1UL << 63) | cfm; +} + static int access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { - unsigned long *ptr, regnum, urbs_end, rnat_addr; + unsigned long *ptr, regnum, urbs_end, rnat_addr, cfm; struct switch_stack *sw; - struct unw_frame_info info; struct pt_regs *pt; pt = ia64_task_regs(child); @@ -778,13 +772,30 @@ access_uarea (struct task_struct *child, * By convention, we use PT_AR_BSP to refer to the end of the user-level * backing store. Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof) to get * the real value of ar.bsp at the time the kernel was entered. + * + * Furthermore, when changing the contents of PT_AR_BSP (or + * PT_CFM) we MUST copy any users-level stacked registers that are + * stored on the kernel stack back to user-space because + * otherwise, we might end up clobbering kernel stacked registers. + * Also, if this happens while the task is blocked in a system + * call, which convert the state such that the non-system-call + * exit path is used. This ensures that the proper state will be + * picked up when resuming execution. However, it *also* means + * that once we write PT_AR_BSP/PT_CFM, it won't be possible to + * modify the syscall arguments of the pending system call any + * longer. This shouldn't be an issue because modifying + * PT_AR_BSP/PT_CFM generally implies that we're either abandoning + * the pending system call or that we defer it's re-execution + * (e.g., due to GDB doing an inferior function call). */ - urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); if (write_access) { if (*data != urbs_end) { if (ia64_sync_user_rbs(child, sw, pt->ar_bspstore, urbs_end) < 0) return -1; + if (in_syscall(pt)) + convert_to_non_syscall(child, pt, cfm); /* simulate user-level write of ar.bsp: */ pt->loadrs = 0; pt->ar_bspstore = *data; @@ -794,27 +805,19 @@ access_uarea (struct task_struct *child, return 0; case PT_CFM: - if ((long) pt->cr_ifs < 0) { - if (write_access) + urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); + if (write_access) { + if (((cfm ^ *data) & 0x3fffffffffU) != 0) { + if (ia64_sync_user_rbs(child, sw, + pt->ar_bspstore, urbs_end) < 0) + return -1; + if (in_syscall(pt)) + convert_to_non_syscall(child, pt, cfm); pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL) | (*data & 0x3fffffffffUL)); - else - *data = pt->cr_ifs & 0x3fffffffffUL; - } else { - /* kernel was entered through a system call */ - unsigned long cfm; - - unw_init_from_blocked_task(&info, child); - if (unw_unwind_to_user(&info) < 0) - return -1; - - unw_get_cfm(&info, &cfm); - if (write_access) - unw_set_cfm(&info, ((cfm & ~0x3fffffffffU) - | (*data & 0x3fffffffffUL))); - else - *data = cfm; - } + } + } else + *data = cfm; return 0; case PT_CR_IPSR: @@ -1240,9 +1243,6 @@ ptrace_disable (struct task_struct *chil /* make sure the single step/take-branch tra bits are not set: */ child_psr->ss = 0; child_psr->tb = 0; - - /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ - child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; } asmlinkage long @@ -1250,7 +1250,7 @@ sys_ptrace (long request, pid_t pid, uns long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt, *regs = (struct pt_regs *) &stack; - unsigned long urbs_end; + unsigned long urbs_end, peek_or_poke; struct task_struct *child; struct switch_stack *sw; long ret; @@ -1269,12 +1269,17 @@ sys_ptrace (long request, pid_t pid, uns goto out; } + peek_or_poke = (request == PTRACE_PEEKTEXT || request == PTRACE_PEEKDATA + || request == PTRACE_POKETEXT || request == PTRACE_POKEDATA); ret = -ESRCH; read_lock(&tasklist_lock); { child = find_task_by_pid(pid); - if (child) + if (child) { + if (peek_or_poke) + child = find_thread_for_addr(child, addr); get_task_struct(child); + } } read_unlock(&tasklist_lock); if (!child) @@ -1299,10 +1304,6 @@ sys_ptrace (long request, pid_t pid, uns case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ urbs_end = ia64_get_user_rbs_end(child, pt, NULL); - - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) - threads_sync_user_rbs(child, urbs_end, 0); - ret = ia64_peek(child, sw, urbs_end, addr, &data); if (ret == 0) { ret = data; @@ -1313,9 +1314,6 @@ sys_ptrace (long request, pid_t pid, uns case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ urbs_end = ia64_get_user_rbs_end(child, pt, NULL); - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) - threads_sync_user_rbs(child, urbs_end, 1); - ret = ia64_poke(child, sw, urbs_end, addr, data); goto out_tsk; @@ -1359,9 +1357,6 @@ sys_ptrace (long request, pid_t pid, uns ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; - /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ - child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; - wake_up_process(child); ret = 0; goto out_tsk; @@ -1380,9 +1375,6 @@ sys_ptrace (long request, pid_t pid, uns ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; - /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ - child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; - wake_up_process(child); ret = 0; goto out_tsk; @@ -1401,9 +1393,6 @@ sys_ptrace (long request, pid_t pid, uns } child->exit_code = data; - /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ - child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; - /* give it a chance to run. */ wake_up_process(child); ret = 0; @@ -1432,7 +1421,9 @@ sys_ptrace (long request, pid_t pid, uns return ret; } -void +/* "asmlinkage" so the input arguments are preserved... */ + +asmlinkage void syscall_trace (void) { if (!test_thread_flag(TIF_SYSCALL_TRACE)) --- linux-2.6.1-rc1/arch/ia64/kernel/signal.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/ia64/kernel/signal.c 2004-01-04 17:36:23.000000000 -0800 @@ -538,31 +538,41 @@ ia64_do_signal (sigset_t *oldset, struct if (!oldset) oldset = ¤t->blocked; - if (IS_IA32_PROCESS(&scr->pt)) { - if (in_syscall) { - if (errno >= 0) - restart = 0; - else - errno = -errno; - } - } else if ((long) scr->pt.r10 != -1) - /* - * A system calls has to be restarted only if one of the error codes - * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned. If r10 - * isn't -1 then r8 doesn't hold an error code and we don't need to - * restart the syscall, so we can clear the "restart" flag here. - */ - restart = 0; - + /* + * This only loops in the rare cases of handle_signal() failing, in which case we + * need to push through a forced SIGSEGV. + */ while (1) { int signr = get_signal_to_deliver(&info, &scr->pt, NULL); + /* + * get_signal_to_deliver() may have run a debugger (via notify_parent()) + * and the debugger may have modified the state (e.g., to arrange for an + * inferior call), thus it's important to check for restarting _after_ + * get_signal_to_deliver(). + */ + if (IS_IA32_PROCESS(&scr->pt)) { + if (in_syscall) { + if (errno >= 0) + restart = 0; + else + errno = -errno; + } + } else if ((long) scr->pt.r10 != -1) + /* + * A system calls has to be restarted only if one of the error codes + * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned. If r10 + * isn't -1 then r8 doesn't hold an error code and we don't need to + * restart the syscall, so we can clear the "restart" flag here. + */ + restart = 0; + if (signr <= 0) break; ka = ¤t->sighand->action[signr - 1]; - if (restart) { + if (unlikely(restart)) { switch (errno) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: @@ -582,6 +592,7 @@ ia64_do_signal (sigset_t *oldset, struct scr->pt.cr_iip -= 2; } else ia64_decrement_ip(&scr->pt); + restart = 0; /* don't restart twice if handle_signal() fails... */ } } --- linux-2.6.1-rc1/arch/ia64/kernel/traps.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/ia64/kernel/traps.c 2004-01-04 17:36:23.000000000 -0800 @@ -216,21 +216,6 @@ ia64_bad_break (unsigned long break_num, } /* - * Unimplemented system calls. This is called only for stuff that - * we're supposed to implement but haven't done so yet. Everything - * else goes to sys_ni_syscall. - * - * XXX Remove this for v2.6.1. - */ -asmlinkage long -ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7, - unsigned long stack) -{ - return -ENOSYS; -} - -/* * disabled_fph_fault() is called when a user-level process attempts to access f32..f127 * and it doesn't own the fp-high register partition. When this happens, we save the * current fph partition in the task_struct of the fpu-owner (if necessary) and then load --- linux-2.6.1-rc1/arch/m68k/amiga/amisound.c 2003-06-14 12:18:51.000000000 -0700 +++ 25/arch/m68k/amiga/amisound.c 2004-01-04 22:16:12.000000000 -0800 @@ -44,7 +44,7 @@ static unsigned long clock_constant; void __init amiga_init_sound(void) { - static struct resource beep_res = { "Beep" }; + static struct resource beep_res = { .name = "Beep" }; snd_data = amiga_chip_alloc_res(sizeof(sine_data), &beep_res); if (!snd_data) { --- linux-2.6.1-rc1/arch/m68k/amiga/chipram.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/m68k/amiga/chipram.c 2004-01-04 22:16:18.000000000 -0800 @@ -19,7 +19,9 @@ unsigned long amiga_chip_size; -static struct resource chipram_res = { "Chip RAM", CHIP_PHYSADDR }; +static struct resource chipram_res = { + .name = "Chip RAM", .start = CHIP_PHYSADDR +}; static unsigned long chipavail; --- linux-2.6.1-rc1/arch/m68k/amiga/config.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/m68k/amiga/config.c 2004-01-04 22:16:18.000000000 -0800 @@ -121,14 +121,22 @@ static struct console amiga_console_driv static struct { struct resource _ciab, _ciaa, _custom, _kickstart; } mb_resources = { - ._ciab = { "CIA B", 0x00bfd000, 0x00bfdfff }, - ._ciaa = { "CIA A", 0x00bfe000, 0x00bfefff }, - ._custom = { "Custom I/O", 0x00dff000, 0x00dfffff }, - ._kickstart = { "Kickstart ROM", 0x00f80000, 0x00ffffff } + ._ciab = { + .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff + }, + ._ciaa = { + .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff + }, + ._custom = { + .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff + }, + ._kickstart = { + .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff + } }; static struct resource rtc_resource = { - NULL, 0x00dc0000, 0x00dcffff + .start = 0x00dc0000, .end = 0x00dcffff }; static struct resource ram_resource[NUM_MEMINFO]; @@ -495,7 +503,7 @@ static void __init amiga_sched_init(irqr struct pt_regs *)) { static struct resource sched_res = { - "timer", 0x00bfd400, 0x00bfd5ff, + .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, }; jiffy_ticks = (amiga_eclock+HZ/2)/HZ; @@ -798,12 +806,12 @@ static void amiga_mem_console_write(stru static void amiga_savekmsg_init(void) { - static struct resource debug_res = { "Debug" }; + static struct resource debug_res = { .name = "Debug" }; savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); savekmsg->magic1 = SAVEKMSG_MAGIC1; savekmsg->magic2 = SAVEKMSG_MAGIC2; - savekmsg->magicptr = virt_to_phys(savekmsg); + savekmsg->magicptr = ZTWO_PADDR(savekmsg); savekmsg->size = 0; } --- linux-2.6.1-rc1/arch/m68k/atari/hades-pci.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/m68k/atari/hades-pci.c 2004-01-04 22:16:12.000000000 -0800 @@ -40,13 +40,20 @@ static const char pci_mem_name[] = "PCI static const char pci_io_name[] = "PCI I/O space"; static const char pci_config_name[] = "PCI config space"; -static struct resource config_space = { pci_config_name, HADES_CONFIG_BASE, - HADES_CONFIG_BASE + HADES_CONFIG_SIZE - 1 }; -static struct resource io_space = { pci_io_name, HADES_IO_BASE, HADES_IO_BASE + - HADES_IO_SIZE - 1 }; +static struct resource config_space = { + .name = pci_config_name, + .start = HADES_CONFIG_BASE, + .end = HADES_CONFIG_BASE + HADES_CONFIG_SIZE - 1 +}; +static struct resource io_space = { + .name = pci_io_name, + .start = HADES_IO_BASE, + .end = HADES_IO_BASE + HADES_IO_SIZE - 1 +}; -static const unsigned long pci_conf_base_phys[] = { 0xA0080000, 0xA0040000, - 0xA0020000, 0xA0010000 }; +static const unsigned long pci_conf_base_phys[] = { + 0xA0080000, 0xA0040000, 0xA0020000, 0xA0010000 +}; static unsigned long pci_conf_base_virt[N_SLOTS]; static unsigned long pci_io_base_virt; --- linux-2.6.1-rc1/arch/m68k/bvme6000/rtc.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/m68k/bvme6000/rtc.c 2004-01-04 22:16:12.000000000 -0800 @@ -164,11 +164,10 @@ static struct file_operations rtc_fops = .release = rtc_release, }; -static struct miscdevice rtc_dev= -{ - RTC_MINOR, - "rtc", - &rtc_fops +static struct miscdevice rtc_dev = { + .minor = RTC_MINOR, + .name = "rtc", + .fops = &rtc_fops }; int __init rtc_DP8570A_init(void) --- linux-2.6.1-rc1/arch/m68k/kernel/head.S 2003-06-14 12:18:51.000000000 -0700 +++ 25/arch/m68k/kernel/head.S 2004-01-04 22:16:11.000000000 -0800 @@ -23,7 +23,7 @@ ** 98/04/25 Phil Blundell: added HP300 support ** 1998/08/30 David Kilzer: Added support for font_desc structures ** for linux-2.1.115 -** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01) +** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01) ** ** This file is subject to the terms and conditions of the GNU General Public ** License. See the file README.legal in the main directory of this archive @@ -100,14 +100,14 @@ * * While this essentially describes the function in the abstract, you'll * find more indepth description of other parameters at the implementation site. - * + * * mmu_get_root_table_entry * ------------------------ * mmu_get_ptr_table_entry * ----------------------- * mmu_get_page_table_entry * ------------------------ - * + * * These routines are used by other mmu routines to get a pointer into * a table, if necessary a new table is allocated. These routines are working * basically like pmd_alloc() and pte_alloc() in . The root @@ -273,6 +273,7 @@ */ #define CONSOLE +#define CONSOLE_PENGUIN /* * Macintosh serial debug support; outputs boot info to the printer @@ -310,8 +311,8 @@ .globl mvme_bdid #endif #ifdef CONFIG_Q40 -.globl q40_mem_cptr -#endif +.globl q40_mem_cptr +#endif #ifdef CONFIG_HP300 .globl hp300_phys_ram_base #endif @@ -422,7 +423,7 @@ PAGE_INDEX_SHIFT = 12 L(\name): linkw %a6,#-\stack moveml \saveregs,%sp@- -.set stackstart,-\stack +.set stackstart,-\stack .macro func_return_\name moveml %sp@+,\saveregs @@ -483,6 +484,12 @@ func_define set_leds func_define serial_putc,1 func_define console_putc,1 +func_define console_init +func_define console_put_stats +func_define console_put_penguin +func_define console_plot_pixel,3 +func_define console_scroll + .macro putc ch #if defined(CONSOLE) || defined(SERIAL_DEBUG) pea \ch @@ -586,7 +593,7 @@ ENTRY(_stext) .long MACH_MVME16x, MVME16x_BOOTI_VERSION .long MACH_BVME6000, BVME6000_BOOTI_VERSION .long MACH_MAC, MAC_BOOTI_VERSION - .long MACH_Q40, Q40_BOOTI_VERSION + .long MACH_Q40, Q40_BOOTI_VERSION .long 0 1: jra __start @@ -604,8 +611,8 @@ ENTRY(__start) address (apparently 0xff002000 in practice) which is not good if we need to be able to map this to VA 0x1000. We could do it with pagetables but a better solution seems to be to relocate the kernel in physical memory - before we start. - + before we start. + So, we copy the entire kernel image (code+data+bss) down to the 16MB boundary that marks the start of RAM. This is slightly tricky because we must not overwrite the copying code itself. :-) */ @@ -650,7 +657,7 @@ Lcopystart: movel %d6,%a0 addl #Lstart1,%a0 jmp %a0@ -Lcopyend: +Lcopyend: Lstart1: moveb #0x3f,%d7 @@ -960,11 +967,11 @@ L(gvtdone): #ifdef CONFIG_MAC is_not_mac(L(nocon)) #ifdef CONSOLE - jbsr L(console_init) + console_init #ifdef CONSOLE_PENGUIN - jbsr L(console_put_penguin) + console_put_penguin #endif /* CONSOLE_PENGUIN */ - jbsr L(console_put_stats) + console_put_stats #endif /* CONSOLE */ L(nocon): #endif /* CONFIG_MAC */ @@ -1108,12 +1115,12 @@ L(mmu_init_not_atari): mmu_map_tt #0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W mmu_map_tt #1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S - + jbra L(mmu_init_done) - -L(notq40): -#endif - + +L(notq40): +#endif + #ifdef CONFIG_HP300 is_not_hp300(L(nothp300)) @@ -1130,18 +1137,18 @@ L(nothp300): #ifdef CONFIG_MVME147 - is_not_mvme147(L(not147)) + is_not_mvme147(L(not147)) - /* - * On MVME147 we have already created kernel page tables for - * 4MB of RAM at address 0, so now need to do a transparent - * mapping of the top of memory space. Make it 0.5GByte for now, - * so we can access on-board i/o areas. - */ + /* + * On MVME147 we have already created kernel page tables for + * 4MB of RAM at address 0, so now need to do a transparent + * mapping of the top of memory space. Make it 0.5GByte for now, + * so we can access on-board i/o areas. + */ - mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030 + mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030 - jbra L(mmu_init_done) + jbra L(mmu_init_done) L(not147): #endif /* CONFIG_MVME147 */ @@ -1226,10 +1233,6 @@ L(mmu_init_mac): putc 'F' - lea %pc@(L(mac_videobase)),%a0 - lea %pc@(L(console_video_virtual)),%a1 - movel %a0@,%a1@ - is_not_040_or_060(1f) moveq #_PAGE_NOCACHE_S,%d3 @@ -1243,14 +1246,14 @@ L(mmu_init_mac): */ movel #VIDEOMEMMASK,%d0 - andl L(mac_videobase),%d0 + andl %pc@(L(mac_videobase)),%d0 mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3 - /* The ROM starts at 4000 0000 */ + /* ROM from 4000 0000 to 4200 0000 (only for mac_reset()) */ mmu_map_eq #0x40000000,#0x02000000,%d3 - /* IO devices */ + /* IO devices (incl. serial port) from 5000 0000 to 5300 0000 */ mmu_map_eq #0x50000000,#0x03000000,%d3 - /* NuBus slot space */ + /* Nubus slot space (video at 0xF0000000, rom at 0xF0F80000) */ mmu_map_tt #1,#0xf8000000,#0x08000000,%d3 jbra L(mmu_init_done) @@ -1284,7 +1287,7 @@ L(mmu_init_not_mac): andl #PAGE_TABLE_SIZE-1, %d0 mmu_get_page_table_entry %a0,%d0 - /* this is where the prom page table lives */ + /* this is where the prom page table lives */ movel 0xfefe00d4, %a1 movel %a1@, %a1 @@ -1295,11 +1298,11 @@ L(mmu_init_not_mac): movel %d3,%a0@+ addl #0x1000,%d3 movel %d3,%a0@+ - - dbra %d1,1b - + + dbra %d1,1b + /* setup tt1 for I/O */ - mmu_map_tt #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S + mmu_map_tt #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S jbra L(mmu_init_done) L(notsun3x): @@ -1310,8 +1313,8 @@ L(notsun3x): putc 'P' mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 - -L(notapollo): + +L(notapollo): jbra L(mmu_init_done) #endif @@ -1342,7 +1345,7 @@ L(mmu_fixup): #endif /* first fix the page at the start of the kernel, that - * contains also kernel_pg_dir. + * contains also kernel_pg_dir. */ movel %pc@(L(phys_kernel_start)),%d0 subl #PAGE_OFFSET,%d0 @@ -1462,9 +1465,15 @@ L(mmu_fixup_done): andl L(mac_videobase),%d0 addl #VIDEOMEMBASE,%d0 movel %d0,L(mac_videobase) +#if defined(CONSOLE) + movel %pc@(L(phys_kernel_start)),%d0 + subl #PAGE_OFFSET,%d0 + subl %d0,L(console_font) + subl %d0,L(console_font_data) +#endif #ifdef MAC_SERIAL_DEBUG orl #0x50000000,L(mac_sccbase) -#endif +#endif 1: #endif @@ -1486,20 +1495,20 @@ L(mmu_fixup_done): is_not_sun3x(1f) /* enable copro */ - oriw #0x4000,0x61000000 + oriw #0x4000,0x61000000 1: #endif #ifdef CONFIG_APOLLO is_not_apollo(1f) - /* + /* * Fix up the iobase before printing - */ - movel #0x80000000,L(iobase) + */ + movel #0x80000000,L(iobase) 1: #endif - + putc 'I' leds 0x10 @@ -1889,7 +1898,7 @@ mmu_030_print: movel %a4,%d5 addil #PAGESIZE<<13,%d5 movel %a0@+,%d6 - btst #1,%d6 /* is it a ptr? */ + btst #1,%d6 /* is it a table ptr? */ jbne 31f /* yes */ btst #0,%d6 /* is it early terminating? */ jbeq 1f /* no */ @@ -1906,9 +1915,9 @@ mmu_030_print: movel %a4,%d5 addil #PAGESIZE<<6,%d5 movel %a1@+,%d6 - btst #1,%d6 - jbne 33f - btst #0,%d6 + btst #1,%d6 /* is it a table ptr? */ + jbne 33f /* yes */ + btst #0,%d6 /* is it a page descriptor? */ jbeq 1f /* no */ jbsr mmu_030_print_helper jbra 37f @@ -2981,7 +2990,7 @@ L(serial_init_not_mac): - check for '%LX$' signature in SRAM */ lea %pc@(q40_mem_cptr),%a1 move.l #0xff020010,%a1@ /* must be inited - also used by debug=mem */ - move.l #0xff020000,%a1 + move.l #0xff020000,%a1 cmp.b #'%',%a1@ bne 2f /*nodbg*/ addq.w #4,%a1 @@ -2996,10 +3005,10 @@ L(serial_init_not_mac): /* signature OK */ lea %pc@(L(q40_do_debug)),%a1 tas %a1@ -/*nodbg: q40_do_debug is 0 by default*/ -2: -#endif - +/*nodbg: q40_do_debug is 0 by default*/ +2: +#endif + #ifdef CONFIG_APOLLO /* We count on the PROM initializing SIO1 */ #endif @@ -3152,7 +3161,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1 moveml %sp@+,%d0-%d7/%a2-%a6 jbra L(serial_putc_done) 2: -#endif CONFIG_MVME16x +#endif /* CONFIG_MVME16x */ #ifdef CONFIG_BVME6000 is_not_bvme6000(2f) @@ -3167,15 +3176,15 @@ func_start serial_putc,%d0/%d1/%a0/%a1 #endif #ifdef CONFIG_SUN3X - is_not_sun3x(2f) + is_not_sun3x(2f) movel %d0,-(%sp) movel 0xFEFE0018,%a1 jbsr (%a1) addq #4,%sp jbra L(serial_putc_done) -2: +2: #endif - + #ifdef CONFIG_Q40 is_not_q40(2f) tst.l %pc@(L(q40_do_debug)) /* only debug if requested */ @@ -3186,16 +3195,16 @@ func_start serial_putc,%d0/%d1/%a0/%a1 addq.l #4,%a0 move.l %a0,%a1@ jbra L(serial_putc_done) -2: -#endif +2: +#endif #ifdef CONFIG_APOLLO is_not_apollo(2f) movl %pc@(L(iobase)),%a1 - moveb %d0,%a1@(LTHRB0) + moveb %d0,%a1@(LTHRB0) 1: moveb %a1@(LSRB0),%d0 - andb #0x4,%d0 - beq 1b + andb #0x4,%d0 + beq 1b 2: #endif @@ -3212,7 +3221,7 @@ func_start puts,%d0/%a0 1: #ifdef CONSOLE console_putc %d0 -#endif +#endif #ifdef SERIAL_DEBUG serial_putc %d0 #endif @@ -3241,7 +3250,7 @@ func_start putn,%d0-%d2 2: #ifdef CONSOLE console_putc %d2 -#endif +#endif #ifdef SERIAL_DEBUG serial_putc %d2 #endif @@ -3290,7 +3299,7 @@ func_start set_leds,%d0/%a0 moveb %d0,%a0@(0x1ffff) jra 2f #endif -1: +1: #ifdef CONFIG_APOLLO movel %pc@(L(iobase)),%a0 lsll #8,%d0 @@ -3313,7 +3322,7 @@ func_return set_leds #define Lconsole_struct_left_edge 16 #define Lconsole_struct_penguin_putc 20 -L(console_init): +func_start console_init,%a0-%a4/%d0-%d7 /* * Some of the register usage that follows * a0 = pointer to boot_info @@ -3327,30 +3336,27 @@ L(console_init): * d5 = number of bytes per scan line * d6 = number of bytes on the entire screen */ - moveml %a0-%a4/%d0-%d7,%sp@- lea %pc@(L(console_globals)),%a2 - lea %pc@(L(mac_videobase)),%a0 - movel %a0@,%a1 - lea %pc@(L(mac_rowbytes)),%a0 - movel %a0@,%d5 - lea %pc@(L(mac_dimensions)),%a0 - movel %a0@,%d3 /* -> low byte */ + movel %pc@(L(mac_videobase)),%a1 + movel %pc@(L(mac_rowbytes)),%d5 + movel %pc@(L(mac_dimensions)),%d3 /* -> low byte */ movel %d3,%d4 swap %d4 /* -> high byte */ andl #0xffff,%d3 /* d3 = screen width in pixels */ andl #0xffff,%d4 /* d4 = screen height in pixels */ movel %d5,%d6 - subl #20,%d6 +| subl #20,%d6 mulul %d4,%d6 /* scan line bytes x num scan lines */ divul #8,%d6 /* we'll clear 8 bytes at a time */ + moveq #-1,%d0 /* Mac_black */ subq #1,%d6 -console_clear_loop: - movel #0xffffffff,%a1@+ /* Mac_black */ - movel #0xffffffff,%a1@+ /* Mac_black */ - dbra %d6,console_clear_loop +L(console_clear_loop): + movel %d0,%a1@+ + movel %d0,%a1@+ + dbra %d6,L(console_clear_loop) /* Calculate font size */ @@ -3368,12 +3374,17 @@ console_clear_loop: /* * At this point we make a shift in register usage - * a1 = address of Lconsole_font pointer + * a1 = address of console_font pointer */ lea %pc@(L(console_font)),%a1 - movel %a0,%a1@ /* store pointer to struct font_desc in Lconsole_font */ + movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in console_font */ tstl %a0 jeq 1f + lea %pc@(L(console_font_data)),%a4 + movel %a0@(FONT_DESC_DATA),%d0 + subl #L(console_font),%a1 + addl %a1,%d0 + movel %d0,%a4@ /* * Calculate global maxs @@ -3382,11 +3393,11 @@ console_clear_loop: * 6 x 11 also supported */ /* ASSERT: a0 = contents of Lconsole_font */ - movel %d3,%d0 /* screen width in pixels */ - divul %a0@(FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ + movel %d3,%d0 /* screen width in pixels */ + divul %a0@(FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ - movel %d4,%d1 /* screen height in pixels */ - divul %a0@(FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ + movel %d4,%d1 /* screen height in pixels */ + divul %a0@(FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ movel %d0,%a2@(Lconsole_struct_num_columns) movel %d1,%a2@(Lconsole_struct_num_rows) @@ -3401,17 +3412,15 @@ console_clear_loop: /* * Initialization is complete */ -1: moveml %sp@+,%a0-%a4/%d0-%d7 - rts +1: +func_return console_init -L(console_put_stats): +func_start console_put_stats,%a0/%d7 /* * Some of the register usage that follows * a0 = pointer to boot_info * d7 = value of boot_info fields */ - moveml %a0/%d7,%sp@- - puts "\nMacLinux\n\n" #ifdef SERIAL_DEBUG @@ -3433,58 +3442,57 @@ L(console_put_stats): #ifdef MAC_SERIAL_DEBUG putn %pc@(L(mac_sccbase)) putc '\n' -#endif +#endif # if defined(MMU_PRINT) jbsr mmu_print_machine_cpu_types # endif /* MMU_PRINT */ #endif /* SERIAL_DEBUG */ - moveml %sp@+,%a0/%d7 - rts +func_return console_put_stats #ifdef CONSOLE_PENGUIN -L(console_put_penguin): +func_start console_put_penguin,%a0-%a1/%d0-%d7 /* * Get 'that_penguin' onto the screen in the upper right corner * penguin is 64 x 74 pixels, align against right edge of screen */ - moveml %a0-%a1/%d0-%d7,%sp@- - lea %pc@(L(mac_dimensions)),%a0 movel %a0@,%d0 andil #0xffff,%d0 subil #64,%d0 /* snug up against the right edge */ clrl %d1 /* start at the top */ movel #73,%d7 - lea %pc@(that_penguin),%a1 -console_penguin_row: + lea %pc@(L(that_penguin)),%a1 +L(console_penguin_row): movel #31,%d6 -console_penguin_pixel_pair: +L(console_penguin_pixel_pair): moveb %a1@,%d2 lsrb #4,%d2 - jbsr console_plot_pixel + console_plot_pixel %d0,%d1,%d2 addq #1,%d0 moveb %a1@+,%d2 - jbsr console_plot_pixel + console_plot_pixel %d0,%d1,%d2 addq #1,%d0 - dbra %d6,console_penguin_pixel_pair + dbra %d6,L(console_penguin_pixel_pair) subil #64,%d0 addq #1,%d1 - dbra %d7,console_penguin_row + dbra %d7,L(console_penguin_row) - moveml %sp@+,%a0-%a1/%d0-%d7 - rts -#endif +func_return console_put_penguin -console_scroll: - moveml %a0-%a4/%d0-%d7,%sp@- +/* include penguin bitmap */ +L(that_penguin): +#include "../mac/mac_penguin.S" +#endif /* * Calculate source and destination addresses * output a1 = dest * a2 = source */ + +func_start console_scroll,%a0-%a4/%d0-%d7 lea %pc@(L(mac_videobase)),%a0 movel %a0@,%a1 movel %a1,%a2 @@ -3517,7 +3525,7 @@ console_scroll: divul #32,%d6 /* we'll move 8 longs at a time */ subq #1,%d6 -console_scroll_loop: +L(console_scroll_loop): movel %a2@+,%a1@+ movel %a2@+,%a1@+ movel %a2@+,%a1@+ @@ -3526,7 +3534,7 @@ console_scroll_loop: movel %a2@+,%a1@+ movel %a2@+,%a1@+ movel %a2@+,%a1@+ - dbra %d6,console_scroll_loop + dbra %d6,L(console_scroll_loop) lea %pc@(L(mac_rowbytes)),%a0 movel %a0@,%d6 @@ -3536,7 +3544,7 @@ console_scroll_loop: subq #1,%d6 moveq #-1,%d0 -console_scroll_clear_loop: +L(console_scroll_clear_loop): movel %d0,%a1@+ movel %d0,%a1@+ movel %d0,%a1@+ @@ -3545,17 +3553,17 @@ console_scroll_clear_loop: movel %d0,%a1@+ movel %d0,%a1@+ movel %d0,%a1@+ - dbra %d6,console_scroll_clear_loop + dbra %d6,L(console_scroll_clear_loop) -1: moveml %sp@+,%a0-%a4/%d0-%d7 - rts +1: +func_return console_scroll func_start console_putc,%a0/%a1/%d0-%d7 - is_not_mac(console_exit) + is_not_mac(L(console_exit)) tstl %pc@(L(console_font)) - jeq console_exit + jeq L(console_exit) /* Output character in d7 on console. */ @@ -3569,7 +3577,7 @@ func_start console_putc,%a0/%a1/%d0-%d7 lea %pc@(L(console_globals)),%a0 cmpib #10,%d7 - jne console_not_lf + jne L(console_not_lf) movel %a0@(Lconsole_struct_cur_row),%d0 addil #1,%d0 movel %d0,%a0@(Lconsole_struct_cur_row) @@ -3578,22 +3586,22 @@ func_start console_putc,%a0/%a1/%d0-%d7 jcs 1f subil #1,%d0 movel %d0,%a0@(Lconsole_struct_cur_row) - jbsr console_scroll + console_scroll 1: - jra console_exit + jra L(console_exit) -console_not_lf: +L(console_not_lf): cmpib #13,%d7 - jne console_not_cr + jne L(console_not_cr) clrl %a0@(Lconsole_struct_cur_column) - jra console_exit + jra L(console_exit) -console_not_cr: +L(console_not_cr): cmpib #1,%d7 - jne console_not_home + jne L(console_not_home) clrl %a0@(Lconsole_struct_cur_row) clrl %a0@(Lconsole_struct_cur_column) - jra console_exit + jra L(console_exit) /* * At this point we know that the %d7 character is going to be @@ -3604,9 +3612,9 @@ console_not_cr: * d1 = cursor row to draw the character * d7 = character number */ -console_not_home: +L(console_not_home): movel %a0@(Lconsole_struct_cur_column),%d0 - addil #1,%a0@(Lconsole_struct_cur_column) + addql #1,%a0@(Lconsole_struct_cur_column) movel %a0@(Lconsole_struct_num_columns),%d1 cmpl %d1,%d0 jcs 1f @@ -3616,10 +3624,10 @@ console_not_home: /* * At this point we make a shift in register usage - * a0 = address of pointer to font data (font_desc) + * a0 = address of pointer to font data (fbcon_font_desc) */ movel %pc@(L(console_font)),%a0 - movel %a0@(FONT_DESC_DATA),%a1 /* Load font_desc.data into a1 */ + movel %pc@(L(console_font_data)),%a1 /* Load fbcon_font_desc.data into a1 */ andl #0x000000ff,%d7 /* ASSERT: a0 = contents of Lconsole_font */ mulul %a0@(FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */ @@ -3637,32 +3645,30 @@ console_not_home: /* ASSERT: a0 = contents of Lconsole_font */ mulul %a0@(FONT_DESC_WIDTH),%d0 mulul %a0@(FONT_DESC_HEIGHT),%d1 - movel %a0@(FONT_DESC_HEIGHT),%d7 /* Load font_desc.height into d7 */ + movel %a0@(FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */ subq #1,%d7 -console_read_char_scanline: +L(console_read_char_scanline): moveb %a1@+,%d3 /* ASSERT: a0 = contents of Lconsole_font */ - movel %a0@(FONT_DESC_WIDTH),%d6 /* Load font_desc.width into d6 */ + movel %a0@(FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */ subql #1,%d6 -console_do_font_scanline: +L(console_do_font_scanline): lslb #1,%d3 scsb %d2 /* convert 1 bit into a byte */ - jbsr console_plot_pixel + console_plot_pixel %d0,%d1,%d2 addq #1,%d0 - dbra %d6,console_do_font_scanline + dbra %d6,L(console_do_font_scanline) /* ASSERT: a0 = contents of Lconsole_font */ subl %a0@(FONT_DESC_WIDTH),%d0 addq #1,%d1 - dbra %d7,console_read_char_scanline - -console_exit: + dbra %d7,L(console_read_char_scanline) +L(console_exit): func_return console_putc -console_plot_pixel: /* * Input: * d0 = x coordinate @@ -3670,14 +3676,14 @@ console_plot_pixel: * d2 = (bit 0) 1/0 for white/black (!) * All registers are preserved */ - moveml %a0-%a1/%d0-%d4,%sp@- +func_start console_plot_pixel,%a0-%a1/%d0-%d4 - lea %pc@(L(mac_videobase)),%a0 - movel %a0@,%a1 - lea %pc@(L(mac_videodepth)),%a0 - movel %a0@,%d3 - lea %pc@(L(mac_rowbytes)),%a0 - mulul %a0@,%d1 + movel %pc@(L(mac_videobase)),%a1 + movel %pc@(L(mac_videodepth)),%d3 + movel ARG1,%d0 + movel ARG2,%d1 + mulul %pc@(L(mac_rowbytes)),%d1 + movel ARG3,%d2 /* * Register usage: @@ -3686,13 +3692,10 @@ console_plot_pixel: * d2 = black or white (0/1) * d3 = video depth * d4 = temp of x (d0) for many bit depths - * d5 = unused - * d6 = unused - * d7 = unused */ -test_1bit: +L(test_1bit): cmpb #1,%d3 - jbne test_2bit + jbne L(test_2bit) movel %d0,%d4 /* we need the low order 3 bits! */ divul #8,%d0 addal %d0,%a1 @@ -3700,16 +3703,16 @@ test_1bit: andb #7,%d4 eorb #7,%d4 /* reverse the x-coordinate w/ screen-bit # */ andb #1,%d2 - jbne white_1 + jbne L(white_1) bsetb %d4,%a1@ - jbra console_plot_pixel_exit -white_1: + jbra L(console_plot_pixel_exit) +L(white_1): bclrb %d4,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_2bit: +L(test_2bit): cmpb #2,%d3 - jbne test_4bit + jbne L(test_4bit) movel %d0,%d4 /* we need the low order 2 bits! */ divul #4,%d0 addal %d0,%a1 @@ -3718,20 +3721,20 @@ test_2bit: eorb #3,%d4 /* reverse the x-coordinate w/ screen-bit # */ lsll #1,%d4 /* ! */ andb #1,%d2 - jbne white_2 + jbne L(white_2) bsetb %d4,%a1@ addq #1,%d4 bsetb %d4,%a1@ - jbra console_plot_pixel_exit -white_2: + jbra L(console_plot_pixel_exit) +L(white_2): bclrb %d4,%a1@ addq #1,%d4 bclrb %d4,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_4bit: +L(test_4bit): cmpb #4,%d3 - jbne test_8bit + jbne L(test_8bit) movel %d0,%d4 /* we need the low order bit! */ divul #2,%d0 addal %d0,%a1 @@ -3740,7 +3743,7 @@ test_4bit: eorb #1,%d4 lsll #2,%d4 /* ! */ andb #1,%d2 - jbne white_4 + jbne L(white_4) bsetb %d4,%a1@ addq #1,%d4 bsetb %d4,%a1@ @@ -3748,8 +3751,8 @@ test_4bit: bsetb %d4,%a1@ addq #1,%d4 bsetb %d4,%a1@ - jbra console_plot_pixel_exit -white_4: + jbra L(console_plot_pixel_exit) +L(white_4): bclrb %d4,%a1@ addq #1,%d4 bclrb %d4,%a1@ @@ -3757,38 +3760,37 @@ white_4: bclrb %d4,%a1@ addq #1,%d4 bclrb %d4,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_8bit: +L(test_8bit): cmpb #8,%d3 - jbne test_16bit + jbne L(test_16bit) addal %d0,%a1 addal %d1,%a1 andb #1,%d2 - jbne white_8 + jbne L(white_8) moveb #0xff,%a1@ - jbra console_plot_pixel_exit -white_8: + jbra L(console_plot_pixel_exit) +L(white_8): clrb %a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_16bit: +L(test_16bit): cmpb #16,%d3 - jbne console_plot_pixel_exit + jbne L(console_plot_pixel_exit) addal %d0,%a1 addal %d0,%a1 addal %d1,%a1 andb #1,%d2 - jbne white_16 + jbne L(white_16) clrw %a1@ - jbra console_plot_pixel_exit -white_16: + jbra L(console_plot_pixel_exit) +L(white_16): movew #0x0fff,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -console_plot_pixel_exit: - moveml %sp@+,%a0-%a1/%d0-%d4 - rts +L(console_plot_pixel_exit): +func_return console_plot_pixel #endif /* CONSOLE */ #if 0 @@ -3838,11 +3840,6 @@ L(iobase): .long 0 #endif -#ifdef CONFIG_MAC -L(console_video_virtual): - .long 0 -#endif /* CONFIG_MAC */ - #if defined(CONSOLE) L(console_globals): .long 0 /* cursor column */ @@ -3853,6 +3850,8 @@ L(console_globals): .long 0 /* mac putc */ L(console_font): .long 0 /* pointer to console font (struct font_desc) */ +L(console_font_data): + .long 0 /* pointer to console font data */ #endif /* CONSOLE */ #if defined(MMU_PRINT) @@ -3941,7 +3940,7 @@ mvme_bdid: #endif #if defined(CONFIG_Q40) q40_mem_cptr: - .long 0 -L(q40_do_debug): - .long 0 + .long 0 +L(q40_do_debug): + .long 0 #endif --- linux-2.6.1-rc1/arch/m68k/kernel/traps.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/m68k/kernel/traps.c 2004-01-04 22:16:19.000000000 -0800 @@ -447,7 +447,7 @@ extern int mmu_emu_handle_fault (unsigne /* sun3 version of bus_error030 */ -extern inline void bus_error030 (struct frame *fp) +static inline void bus_error030 (struct frame *fp) { unsigned char buserr_type = sun3_get_buserr (); unsigned long addr, errorcode; @@ -583,12 +583,9 @@ static inline void bus_error030 (struct unsigned short mmusr; unsigned long addr, errorcode; unsigned short ssw = fp->un.fmtb.ssw; - int user_space_fault = 1; #if DEBUG unsigned long desc; -#endif -#if DEBUG printk ("pid = %x ", current->pid); printk ("SSW=%#06x ", ssw); @@ -605,128 +602,116 @@ static inline void bus_error030 (struct space_names[ssw & DFC], fp->ptregs.pc); #endif - if (fp->ptregs.sr & PS_S) { - /* kernel fault must be a data fault to user space */ - if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { - /* instruction fault or kernel data fault! */ - if (ssw & (FC | FB)) - printk ("Instruction fault at %#010lx\n", - fp->ptregs.pc); - if (ssw & DF) { - printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", - fp->un.fmtb.daddr, - space_names[ssw & DFC], fp->ptregs.pc); - } - printk ("BAD KERNEL BUSERR\n"); - die_if_kernel("Oops",&fp->ptregs,0); - force_sig(SIGKILL, current); - return; - } - } else { - /* user fault */ - if (!(ssw & (FC | FB)) && !(ssw & DF)) - /* not an instruction fault or data fault! BAD */ - panic ("USER BUSERR w/o instruction or data fault"); - user_space_fault = 1; -#if DEBUG - printk("User space bus-error\n"); -#endif - } - /* ++andreas: If a data fault and an instruction fault happen at the same time map in both pages. */ /* First handle the data fault, if any. */ - if (ssw & DF) - { - addr = fp->un.fmtb.daddr; + if (ssw & DF) { + addr = fp->un.fmtb.daddr; - mmusr = MMU_I; - if (user_space_fault) { #if DEBUG - asm volatile ("ptestr #1,%2@,#7,%0\n\t" - "pmove %/psr,%1@" - : "=a&" (desc) - : "a" (&temp), "a" (addr)); + asm volatile ("ptestr %3,%2@,#7,%0\n\t" + "pmove %%psr,%1@" + : "=a&" (desc) + : "a" (&temp), "a" (addr), "d" (ssw)); #else - asm volatile ("ptestr #1,%1@,#7\n\t" - "pmove %/psr,%0@" - : : "a" (&temp), "a" (addr)); -#endif - mmusr = temp; - } - -#if DEBUG - printk ("mmusr is %#x for addr %#lx in task %p\n", - mmusr, addr, current); - printk ("descriptor address is %#lx, contents %#lx\n", - __va(desc), *(unsigned long *)__va(desc)); + asm volatile ("ptestr %2,%1@,#7\n\t" + "pmove %%psr,%0@" + : : "a" (&temp), "a" (addr), "d" (ssw)); #endif + mmusr = temp; - errorcode = (mmusr & MMU_I) ? 0 : 1; - if (!(ssw & RW) || (ssw & RM)) - errorcode |= 2; - - if (mmusr & (MMU_I | MMU_WP)) { - /* Don't try to do anything further if an exception was - handled. */ - if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) +#if DEBUG + printk("mmusr is %#x for addr %#lx in task %p\n", + mmusr, addr, current); + printk("descriptor address is %#lx, contents %#lx\n", + __va(desc), *(unsigned long *)__va(desc)); +#endif + + errorcode = (mmusr & MMU_I) ? 0 : 1; + if (!(ssw & RW) || (ssw & RM)) + errorcode |= 2; + + if (mmusr & (MMU_I | MMU_WP)) { + if (ssw & 4) { + printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); + goto buserr; + } + /* Don't try to do anything further if an exception was + handled. */ + if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) + return; + } else if (!(mmusr & MMU_I)) { + /* propably a 020 cas fault */ + if (!(ssw & RM)) + printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); + } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { + printk("invalid %s access at %#lx from pc %#lx\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc); + die_if_kernel("Oops",&fp->ptregs,mmusr); + force_sig(SIGSEGV, current); return; - } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { - printk ("invalid %s access at %#lx from pc %#lx\n", - !(ssw & RW) ? "write" : "read", addr, - fp->ptregs.pc); - die_if_kernel("Oops",&fp->ptregs,mmusr); - force_sig(SIGSEGV, current); - return; - } else { + } else { #if 0 - static volatile long tlong; + static volatile long tlong; #endif - printk ("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", - !(ssw & RW) ? "write" : "read", addr, - fp->ptregs.pc, ssw); - asm volatile ("ptestr #1,%1@,#0\n\t" - "pmove %/psr,%0@" - : /* no outputs */ - : "a" (&temp), "a" (addr)); - mmusr = temp; + printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc, ssw); + asm volatile ("ptestr #1,%1@,#0\n\t" + "pmove %%psr,%0@" + : /* no outputs */ + : "a" (&temp), "a" (addr)); + mmusr = temp; - printk ("level 0 mmusr is %#x\n", mmusr); + printk ("level 0 mmusr is %#x\n", mmusr); #if 0 - asm volatile ("pmove %/tt0,%0@" - : /* no outputs */ - : "a" (&tlong)); - printk ("tt0 is %#lx, ", tlong); - asm volatile ("pmove %/tt1,%0@" - : /* no outputs */ - : "a" (&tlong)); - printk ("tt1 is %#lx\n", tlong); + asm volatile ("pmove %%tt0,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk("tt0 is %#lx, ", tlong); + asm volatile ("pmove %%tt1,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk("tt1 is %#lx\n", tlong); #endif #if DEBUG - printk("Unknown SIGSEGV - 1\n"); + printk("Unknown SIGSEGV - 1\n"); #endif - die_if_kernel("Oops",&fp->ptregs,mmusr); - force_sig(SIGSEGV, current); - return; - } - - /* setup an ATC entry for the access about to be retried */ - if (!(ssw & RW)) - asm volatile ("ploadw %1,%0@" : /* no outputs */ - : "a" (addr), "d" (ssw)); - else - asm volatile ("ploadr %1,%0@" : /* no outputs */ - : "a" (addr), "d" (ssw)); - } + die_if_kernel("Oops",&fp->ptregs,mmusr); + force_sig(SIGSEGV, current); + return; + } + + /* setup an ATC entry for the access about to be retried */ + if (!(ssw & RW) || (ssw & RM)) + asm volatile ("ploadw %1,%0@" : /* no outputs */ + : "a" (addr), "d" (ssw)); + else + asm volatile ("ploadr %1,%0@" : /* no outputs */ + : "a" (addr), "d" (ssw)); + } /* Now handle the instruction fault. */ if (!(ssw & (FC|FB))) return; + if (fp->ptregs.sr & PS_S) { + printk("Instruction fault at %#010lx\n", + fp->ptregs.pc); + buserr: + printk ("BAD KERNEL BUSERR\n"); + die_if_kernel("Oops",&fp->ptregs,0); + force_sig(SIGKILL, current); + return; + } + /* get the fault address */ if (fp->ptregs.format == 10) addr = fp->ptregs.pc + 4; @@ -740,21 +725,18 @@ static inline void bus_error030 (struct should still create the ATC entry. */ goto create_atc_entry; - mmusr = MMU_I; - if (user_space_fault) { #if DEBUG - asm volatile ("ptestr #1,%2@,#7,%0\n\t" - "pmove %/psr,%1@" - : "=a&" (desc) - : "a" (&temp), "a" (addr)); + asm volatile ("ptestr #1,%2@,#7,%0\n\t" + "pmove %%psr,%1@" + : "=a&" (desc) + : "a" (&temp), "a" (addr)); #else - asm volatile ("ptestr #1,%1@,#7\n\t" - "pmove %/psr,%0@" - : : "a" (&temp), "a" (addr)); + asm volatile ("ptestr #1,%1@,#7\n\t" + "pmove %%psr,%0@" + : : "a" (&temp), "a" (addr)); #endif - mmusr = temp; - } - + mmusr = temp; + #ifdef DEBUG printk ("mmusr is %#x for addr %#lx in task %p\n", mmusr, addr, current); --- linux-2.6.1-rc1/arch/m68k/mac/config.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/m68k/mac/config.c 2004-01-04 22:16:13.000000000 -0800 @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -267,6 +268,7 @@ void __init config_mac(void) */ struct mac_model *macintosh_config; +EXPORT_SYMBOL(macintosh_config); static struct mac_model mac_data_table[]= { --- linux-2.6.1-rc1/arch/m68k/mac/misc.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/arch/m68k/mac/misc.c 2004-01-04 22:16:15.000000000 -0800 @@ -39,6 +39,7 @@ extern struct mac_booter_data mac_bi_data; static void (*rom_reset)(void); +#ifdef CONFIG_ADB /* * Return the current time as the number of seconds since January 1, 1904. */ @@ -103,6 +104,7 @@ static void adb_write_pram(int offset, _ (offset >> 8) & 0xFF, offset & 0xFF, data); } +#endif /* CONFIG_ADB */ /* * VIA PRAM/RTC access routines @@ -356,7 +358,11 @@ void mac_pram_read(int offset, __u8 *buf macintosh_config->adb_type == MAC_ADB_PB1 || macintosh_config->adb_type == MAC_ADB_PB2 || macintosh_config->adb_type == MAC_ADB_CUDA) { +#ifdef CONFIG_ADB func = adb_read_pram; +#else + return; +#endif } else { func = via_read_pram; } @@ -374,7 +380,11 @@ void mac_pram_write(int offset, __u8 *bu macintosh_config->adb_type == MAC_ADB_PB1 || macintosh_config->adb_type == MAC_ADB_PB2 || macintosh_config->adb_type == MAC_ADB_CUDA) { +#ifdef CONFIG_ADB func = adb_write_pram; +#else + return; +#endif } else { func = via_write_pram; } @@ -580,12 +590,16 @@ int mac_hwclk(int op, struct rtc_time *t if (!op) { /* read */ if (macintosh_config->adb_type == MAC_ADB_II) { now = via_read_time(); - } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + } else +#ifdef CONFIG_ADB + if ((macintosh_config->adb_type == MAC_ADB_IISI) || (macintosh_config->adb_type == MAC_ADB_PB1) || (macintosh_config->adb_type == MAC_ADB_PB2) || (macintosh_config->adb_type == MAC_ADB_CUDA)) { now = adb_read_time(); - } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + } else +#endif + if (macintosh_config->adb_type == MAC_ADB_IOP) { now = via_read_time(); } else { now = 0; --- linux-2.6.1-rc1/arch/m68k/math-emu/fp_arith.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/arch/m68k/math-emu/fp_arith.c 2004-01-04 22:16:13.000000000 -0800 @@ -19,12 +19,13 @@ const struct fp_ext fp_QNaN = { - 0, 0, 0x7fff, { ~0 } + .exp = 0x7fff, + .mant = { .m64 = ~0 } }; const struct fp_ext fp_Inf = { - 0, 0, 0x7fff, { 0 } + .exp = 0x7fff, }; /* let's start with the easy ones */ --- linux-2.6.1-rc1/arch/m68k/math-emu/fp_log.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/arch/m68k/math-emu/fp_log.c 2004-01-04 22:16:13.000000000 -0800 @@ -19,7 +19,7 @@ static const struct fp_ext fp_one = { - 0, 0, 0x3fff, { 0 } + .exp = 0x3fff, }; extern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src); --- linux-2.6.1-rc1/arch/m68k/math-emu/multi_arith.h 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/m68k/math-emu/multi_arith.h 2004-01-04 22:16:19.000000000 -0800 @@ -38,17 +38,14 @@ enum { /* Convenience functions to stuff various integer values into int128s */ -extern inline void zero128(int128 a) +static inline void zero128(int128 a) { a[LSW128] = a[NLSW128] = a[NMSW128] = a[MSW128] = 0; } /* Human-readable word order in the arguments */ -extern inline void set128(unsigned int i3, - unsigned int i2, - unsigned int i1, - unsigned int i0, - int128 a) +static inline void set128(unsigned int i3, unsigned int i2, unsigned int i1, + unsigned int i0, int128 a) { a[LSW128] = i0; a[NLSW128] = i1; @@ -57,21 +54,19 @@ extern inline void set128(unsigned int i } /* Convenience functions (for testing as well) */ -extern inline void int64_to_128(unsigned long long src, - int128 dest) +static inline void int64_to_128(unsigned long long src, int128 dest) { dest[LSW128] = (unsigned int) src; dest[NLSW128] = src >> 32; dest[NMSW128] = dest[MSW128] = 0; } -extern inline void int128_to_64(const int128 src, - unsigned long long *dest) +static inline void int128_to_64(const int128 src, unsigned long long *dest) { *dest = src[LSW128] | (long long) src[NLSW128] << 32; } -extern inline void put_i128(const int128 a) +static inline void put_i128(const int128 a) { printk("%08x %08x %08x %08x\n", a[MSW128], a[NMSW128], a[NLSW128], a[LSW128]); @@ -82,7 +77,7 @@ extern inline void put_i128(const int128 Note that these are only good for 0 < count < 32. */ -extern inline void _lsl128(unsigned int count, int128 a) +static inline void _lsl128(unsigned int count, int128 a) { a[MSW128] = (a[MSW128] << count) | (a[NMSW128] >> (32 - count)); a[NMSW128] = (a[NMSW128] << count) | (a[NLSW128] >> (32 - count)); @@ -90,7 +85,7 @@ extern inline void _lsl128(unsigned int a[LSW128] <<= count; } -extern inline void _lsr128(unsigned int count, int128 a) +static inline void _lsr128(unsigned int count, int128 a) { a[LSW128] = (a[LSW128] >> count) | (a[NLSW128] << (32 - count)); a[NLSW128] = (a[NLSW128] >> count) | (a[NMSW128] << (32 - count)); @@ -100,7 +95,7 @@ extern inline void _lsr128(unsigned int /* Should be faster, one would hope */ -extern inline void lslone128(int128 a) +static inline void lslone128(int128 a) { asm volatile ("lsl.l #1,%0\n" "roxl.l #1,%1\n" @@ -118,7 +113,7 @@ extern inline void lslone128(int128 a) "3"(a[MSW128])); } -extern inline void lsrone128(int128 a) +static inline void lsrone128(int128 a) { asm volatile ("lsr.l #1,%0\n" "roxr.l #1,%1\n" @@ -140,7 +135,7 @@ extern inline void lsrone128(int128 a) These bit-shift to a multiple of 32, then move whole longwords. */ -extern inline void lsl128(unsigned int count, int128 a) +static inline void lsl128(unsigned int count, int128 a) { int wordcount, i; @@ -159,7 +154,7 @@ extern inline void lsl128(unsigned int c } } -extern inline void lsr128(unsigned int count, int128 a) +static inline void lsr128(unsigned int count, int128 a) { int wordcount, i; @@ -177,18 +172,18 @@ extern inline void lsr128(unsigned int c } } -extern inline int orl128(int a, int128 b) +static inline int orl128(int a, int128 b) { b[LSW128] |= a; } -extern inline int btsthi128(const int128 a) +static inline int btsthi128(const int128 a) { return a[MSW128] & 0x80000000; } /* test bits (numbered from 0 = LSB) up to and including "top" */ -extern inline int bftestlo128(int top, const int128 a) +static inline int bftestlo128(int top, const int128 a) { int r = 0; @@ -206,7 +201,7 @@ extern inline int bftestlo128(int top, c /* Aargh. We need these because GCC is broken */ /* FIXME: do them in assembly, for goodness' sake! */ -extern inline void mask64(int pos, unsigned long long *mask) +static inline void mask64(int pos, unsigned long long *mask) { *mask = 0; @@ -218,7 +213,7 @@ extern inline void mask64(int pos, unsig HI_WORD(*mask) = (1 << (pos - 32)) - 1; } -extern inline void bset64(int pos, unsigned long long *dest) +static inline void bset64(int pos, unsigned long long *dest) { /* This conditional will be optimized away. Thanks, GCC! */ if (pos < 32) @@ -229,7 +224,7 @@ extern inline void bset64(int pos, unsig (HI_WORD(*dest)):"id"(pos - 32)); } -extern inline int btst64(int pos, unsigned long long dest) +static inline int btst64(int pos, unsigned long long dest) { if (pos < 32) return (0 != (LO_WORD(dest) & (1 << pos))); @@ -237,7 +232,7 @@ extern inline int btst64(int pos, unsign return (0 != (HI_WORD(dest) & (1 << (pos - 32)))); } -extern inline void lsl64(int count, unsigned long long *dest) +static inline void lsl64(int count, unsigned long long *dest) { if (count < 32) { HI_WORD(*dest) = (HI_WORD(*dest) << count) @@ -250,7 +245,7 @@ extern inline void lsl64(int count, unsi LO_WORD(*dest) = 0; } -extern inline void lsr64(int count, unsigned long long *dest) +static inline void lsr64(int count, unsigned long long *dest) { if (count < 32) { LO_WORD(*dest) = (LO_WORD(*dest) >> count) @@ -264,7 +259,7 @@ extern inline void lsr64(int count, unsi } #endif -extern inline void fp_denormalize(struct fp_ext *reg, unsigned int cnt) +static inline void fp_denormalize(struct fp_ext *reg, unsigned int cnt) { reg->exp += cnt; @@ -306,7 +301,7 @@ extern inline void fp_denormalize(struct } } -extern inline int fp_overnormalize(struct fp_ext *reg) +static inline int fp_overnormalize(struct fp_ext *reg) { int shift; @@ -324,7 +319,7 @@ extern inline int fp_overnormalize(struc return shift; } -extern inline int fp_addmant(struct fp_ext *dest, struct fp_ext *src) +static inline int fp_addmant(struct fp_ext *dest, struct fp_ext *src) { int carry; @@ -340,7 +335,7 @@ extern inline int fp_addmant(struct fp_e return carry; } -extern inline int fp_addcarry(struct fp_ext *reg) +static inline int fp_addcarry(struct fp_ext *reg) { if (++reg->exp == 0x7fff) { if (reg->mant.m64) @@ -357,7 +352,8 @@ extern inline int fp_addcarry(struct fp_ return 1; } -extern inline void fp_submant(struct fp_ext *dest, struct fp_ext *src1, struct fp_ext *src2) +static inline void fp_submant(struct fp_ext *dest, struct fp_ext *src1, + struct fp_ext *src2) { /* we assume here, gcc only insert move and a clr instr */ asm volatile ("sub.b %1,%0" : "=d,g" (dest->lowmant) @@ -407,7 +403,8 @@ extern inline void fp_submant(struct fp_ carry; \ }) -extern inline void fp_multiplymant(union fp_mant128 *dest, struct fp_ext *src1, struct fp_ext *src2) +static inline void fp_multiplymant(union fp_mant128 *dest, struct fp_ext *src1, + struct fp_ext *src2) { union fp_mant64 temp; @@ -421,7 +418,8 @@ extern inline void fp_multiplymant(union fp_addx96(dest, temp); } -extern inline void fp_dividemant(union fp_mant128 *dest, struct fp_ext *src, struct fp_ext *div) +static inline void fp_dividemant(union fp_mant128 *dest, struct fp_ext *src, + struct fp_ext *div) { union fp_mant128 tmp; union fp_mant64 tmp64; @@ -484,7 +482,7 @@ extern inline void fp_dividemant(union f } #if 0 -extern inline unsigned int fp_fls128(union fp_mant128 *src) +static inline unsigned int fp_fls128(union fp_mant128 *src) { unsigned long data; unsigned int res, off; @@ -504,7 +502,7 @@ extern inline unsigned int fp_fls128(uni return res + off; } -extern inline void fp_shiftmant128(union fp_mant128 *src, int shift) +static inline void fp_shiftmant128(union fp_mant128 *src, int shift) { unsigned long sticky; @@ -594,7 +592,8 @@ extern inline void fp_shiftmant128(union } #endif -extern inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src, int shift) +static inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src, + int shift) { unsigned long tmp; @@ -639,7 +638,7 @@ extern inline void fp_putmant128(struct } #if 0 /* old code... */ -extern inline int fls(unsigned int a) +static inline int fls(unsigned int a) { int r; @@ -649,7 +648,7 @@ extern inline int fls(unsigned int a) } /* fls = "find last set" (cf. ffs(3)) */ -extern inline int fls128(const int128 a) +static inline int fls128(const int128 a) { if (a[MSW128]) return fls(a[MSW128]); @@ -668,12 +667,12 @@ extern inline int fls128(const int128 a) return -1; } -extern inline int zerop128(const int128 a) +static inline int zerop128(const int128 a) { return !(a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]); } -extern inline int nonzerop128(const int128 a) +static inline int nonzerop128(const int128 a) { return (a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]); } @@ -681,7 +680,7 @@ extern inline int nonzerop128(const int1 /* Addition and subtraction */ /* Do these in "pure" assembly, because "extended" asm is unmanageable here */ -extern inline void add128(const int128 a, int128 b) +static inline void add128(const int128 a, int128 b) { /* rotating carry flags */ unsigned int carry[2]; @@ -699,7 +698,7 @@ extern inline void add128(const int128 a } /* Note: assembler semantics: "b -= a" */ -extern inline void sub128(const int128 a, int128 b) +static inline void sub128(const int128 a, int128 b) { /* rotating borrow flags */ unsigned int borrow[2]; @@ -717,9 +716,7 @@ extern inline void sub128(const int128 a } /* Poor man's 64-bit expanding multiply */ -extern inline void mul64(unsigned long long a, - unsigned long long b, - int128 c) +static inline void mul64(unsigned long long a, unsigned long long b, int128 c) { unsigned long long acc; int128 acc128; @@ -756,7 +753,7 @@ extern inline void mul64(unsigned long l } /* Note: unsigned */ -extern inline int cmp128(int128 a, int128 b) +static inline int cmp128(int128 a, int128 b) { if (a[MSW128] < b[MSW128]) return -1; --- linux-2.6.1-rc1/arch/m68k/mm/hwtest.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/arch/m68k/mm/hwtest.c 2004-01-04 22:16:13.000000000 -0800 @@ -23,6 +23,8 @@ * a temporary VBR and a vector table for the duration of the test. */ +#include + int hwreg_present( volatile void *regp ) { int ret = 0; @@ -47,6 +49,7 @@ int hwreg_present( volatile void *regp ) return( ret ); } +EXPORT_SYMBOL(hwreg_present); /* Basically the same, but writes a value into a word register, protected * by a bus error handler. Returns 1 if successful, 0 otherwise. @@ -78,4 +81,5 @@ int hwreg_write( volatile void *regp, un return( ret ); } +EXPORT_SYMBOL(hwreg_write); --- linux-2.6.1-rc1/arch/m68k/mm/motorola.c 2003-07-27 12:14:38.000000000 -0700 +++ 25/arch/m68k/mm/motorola.c 2004-01-04 22:16:13.000000000 -0800 @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -40,6 +41,7 @@ * For 68040, this is _PAGE_CACHE040 (cachable, copyback) */ unsigned long mm_cachebits = 0; +EXPORT_SYMBOL(mm_cachebits); #endif static pte_t * __init kernel_page_table(void) --- linux-2.6.1-rc1/arch/m68k/mvme16x/rtc.c 2003-06-14 12:18:52.000000000 -0700 +++ 25/arch/m68k/mvme16x/rtc.c 2004-01-04 22:16:13.000000000 -0800 @@ -155,9 +155,9 @@ static struct file_operations rtc_fops = static struct miscdevice rtc_dev= { - RTC_MINOR, - "rtc", - &rtc_fops + .minor = RTC_MINOR, + .name = "rtc", + .fops = &rtc_fops }; int __init rtc_MK48T08_init(void) --- linux-2.6.1-rc1/arch/m68k/q40/q40ints.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/m68k/q40/q40ints.c 2004-01-04 22:16:14.000000000 -0800 @@ -281,21 +281,17 @@ static struct IRQ_TABLE iirqs[]={ {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD}, {0,0}}; #endif -static struct IRQ_TABLE eirqs[]={ - {Q40_IRQ3_MASK,3}, /* ser 1 */ - {Q40_IRQ4_MASK,4}, /* ser 2 */ - {Q40_IRQ14_MASK,14}, /* IDE 1 */ - {Q40_IRQ15_MASK,15}, /* IDE 2 */ - {Q40_IRQ6_MASK,6}, /* floppy, handled elsewhere */ - {Q40_IRQ7_MASK,7}, /* par */ - - {Q40_IRQ5_MASK,5}, - {Q40_IRQ10_MASK,10}, - - - - - {0,0}}; +static struct IRQ_TABLE eirqs[] = { + { .mask = Q40_IRQ3_MASK, .irq = 3 }, /* ser 1 */ + { .mask = Q40_IRQ4_MASK, .irq = 4 }, /* ser 2 */ + { .mask = Q40_IRQ14_MASK, .irq = 14 }, /* IDE 1 */ + { .mask = Q40_IRQ15_MASK, .irq = 15 }, /* IDE 2 */ + { .mask = Q40_IRQ6_MASK, .irq = 6 }, /* floppy, handled elsewhere */ + { .mask = Q40_IRQ7_MASK, .irq = 7 }, /* par */ + { .mask = Q40_IRQ5_MASK, .irq = 5 }, + { .mask = Q40_IRQ10_MASK, .irq = 10 }, + {0,0} +}; /* complain only this many times about spurious ints : */ static int ccleirq=60; /* ISA dev IRQ's*/ --- linux-2.6.1-rc1/arch/m68k/sun3/idprom.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/arch/m68k/sun3/idprom.c 2004-01-04 22:16:14.000000000 -0800 @@ -24,34 +24,34 @@ static struct idprom idprom_buffer; */ struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { /* First, Sun3's */ -{ "Sun 3/160 Series", (SM_SUN3 | SM_3_160) }, -{ "Sun 3/50", (SM_SUN3 | SM_3_50) }, -{ "Sun 3/260 Series", (SM_SUN3 | SM_3_260) }, -{ "Sun 3/110 Series", (SM_SUN3 | SM_3_110) }, -{ "Sun 3/60", (SM_SUN3 | SM_3_60) }, -{ "Sun 3/E", (SM_SUN3 | SM_3_E) }, + { .name = "Sun 3/160 Series", .id_machtype = (SM_SUN3 | SM_3_160) }, + { .name = "Sun 3/50", .id_machtype = (SM_SUN3 | SM_3_50) }, + { .name = "Sun 3/260 Series", .id_machtype = (SM_SUN3 | SM_3_260) }, + { .name = "Sun 3/110 Series", .id_machtype = (SM_SUN3 | SM_3_110) }, + { .name = "Sun 3/60", .id_machtype = (SM_SUN3 | SM_3_60) }, + { .name = "Sun 3/E", .id_machtype = (SM_SUN3 | SM_3_E) }, /* Now, Sun3x's */ -{ "Sun 3/460 Series", (SM_SUN3X | SM_3_460) }, -{ "Sun 3/80", (SM_SUN3X | SM_3_80) }, + { .name = "Sun 3/460 Series", .id_machtype = (SM_SUN3X | SM_3_460) }, + { .name = "Sun 3/80", .id_machtype = (SM_SUN3X | SM_3_80) }, /* Then, Sun4's */ -//{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) }, -//{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) }, -//{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) }, -//{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) }, +// { .name = "Sun 4/100 Series", .id_machtype = (SM_SUN4 | SM_4_110) }, +// { .name = "Sun 4/200 Series", .id_machtype = (SM_SUN4 | SM_4_260) }, +// { .name = "Sun 4/300 Series", .id_machtype = (SM_SUN4 | SM_4_330) }, +// { .name = "Sun 4/400 Series", .id_machtype = (SM_SUN4 | SM_4_470) }, /* And now, Sun4c's */ -//{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) }, -//{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) }, -//{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) }, -//{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) }, -//{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) }, -//{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) }, -//{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) }, +// { .name = "Sun4c SparcStation 1", .id_machtype = (SM_SUN4C | SM_4C_SS1) }, +// { .name = "Sun4c SparcStation IPC", .id_machtype = (SM_SUN4C | SM_4C_IPC) }, +// { .name = "Sun4c SparcStation 1+", .id_machtype = (SM_SUN4C | SM_4C_SS1PLUS) }, +// { .name = "Sun4c SparcStation SLC", .id_machtype = (SM_SUN4C | SM_4C_SLC) }, +// { .name = "Sun4c SparcStation 2", .id_machtype = (SM_SUN4C | SM_4C_SS2) }, +// { .name = "Sun4c SparcStation ELC", .id_machtype = (SM_SUN4C | SM_4C_ELC) }, +// { .name = "Sun4c SparcStation IPX", .id_machtype = (SM_SUN4C | SM_4C_IPX) }, /* Finally, early Sun4m's */ -//{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) }, -//{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) }, -//{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) }, +// { .name = "Sun4m SparcSystem600", .id_machtype = (SM_SUN4M | SM_4M_SS60) }, +// { .name = "Sun4m SparcStation10/20", .id_machtype = (SM_SUN4M | SM_4M_SS50) }, +// { .name = "Sun4m SparcStation5", .id_machtype = (SM_SUN4M | SM_4M_SS40) }, /* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */ -//{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } +// { .name = "Sun4M OBP based system", .id_machtype = (SM_SUN4M_OBP | 0x0) } }; static void __init display_system_type(unsigned char machtype) --- linux-2.6.1-rc1/arch/parisc/kernel/sys_parisc.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/parisc/kernel/sys_parisc.c 2004-01-04 17:36:44.000000000 -0800 @@ -93,17 +93,13 @@ static unsigned long get_shared_area(str unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct inode *inode; - if (len > TASK_SIZE) return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - inode = filp ? filp->f_dentry->d_inode : NULL; - - if (inode && (flags & MAP_SHARED)) { - addr = get_shared_area(inode->i_mapping, addr, len, pgoff); + if (filp && (flags & MAP_SHARED)) { + addr = get_shared_area(filp->f_mapping, addr, len, pgoff); } else { addr = get_unshared_area(addr, len); } --- linux-2.6.1-rc1/arch/ppc64/kernel/chrp_setup.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/arch/ppc64/kernel/chrp_setup.c 2004-01-04 22:15:31.000000000 -0800 @@ -96,16 +96,19 @@ chrp_get_cpuinfo(struct seq_file *m) seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - root = find_path_device("/"); + root = of_find_node_by_path("/"); if (root) model = get_property(root, "model", NULL); seq_printf(m, "machine\t\t: CHRP %s\n", model); + of_node_put(root); } #define I8042_DATA_REG 0x60 -void __init chrp_request_regions(void) +void __init chrp_request_regions(void) { + struct device_node *i8042; + request_region(0x20,0x20,"pic1"); request_region(0xa0,0x20,"pic2"); request_region(0x00,0x20,"dma1"); @@ -118,8 +121,9 @@ void __init chrp_request_regions(void) * tree and reserve the region if it does not appear. Later on * the i8042 code will try and reserve this region and fail. */ - if (!find_type_devices("8042")) + if (!(i8042 = of_find_node_by_type(NULL, "8042"))) request_region(I8042_DATA_REG, 16, "reserved (no i8042)"); + of_node_put(i8042); } void __init @@ -158,7 +162,7 @@ chrp_setup_arch(void) #endif /* Find the Open PIC if present */ - root = find_path_device("/"); + root = of_find_node_by_path("/"); opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); if (opprop != 0) { @@ -170,6 +174,7 @@ chrp_setup_arch(void) printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic); OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE); } + of_node_put(root); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -271,7 +276,7 @@ chrp_init(unsigned long r3, unsigned lon struct device_node * dn; char * hypertas; unsigned int len; - dn = find_path_device("/rtas"); + dn = of_find_node_by_path("/rtas"); cur_cpu_spec->firmware_features = 0; hypertas = get_property(dn, "ibm,hypertas-functions", &len); if (hypertas) { @@ -290,6 +295,7 @@ chrp_init(unsigned long r3, unsigned lon hypertas+= hypertas_len +1; } } + of_node_put(dn); udbg_printf("firmware_features bitmask: 0x%x \n", cur_cpu_spec->firmware_features); } @@ -405,11 +411,11 @@ void __init pSeries_calibrate_decr(void) /* * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. + * to tell us the rate at which the decrementer counts. */ freq = 16666000; /* hardcoded default */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { + cpu = of_find_node_by_type("cpu"); + if (cpu != 0) { fp = (int *) get_property(cpu, "timebase-frequency", NULL); if (fp != 0) freq = *fp; @@ -422,11 +428,12 @@ void __init pSeries_calibrate_decr(void) processor_freq = *fp; } ppc_proc_freq = processor_freq; - - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq/1000000, freq%1000000 ); + of_node_put(cpu); + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); printk("time_init: processor frequency = %lu.%.6lu MHz\n", - processor_freq/1000000, processor_freq%1000000 ); + processor_freq/1000000, processor_freq%1000000); tb_ticks_per_jiffy = freq / HZ; tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; --- linux-2.6.1-rc1/arch/ppc64/kernel/eeh.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/arch/ppc64/kernel/eeh.c 2004-01-04 22:15:31.000000000 -0800 @@ -257,7 +257,7 @@ void eeh_init(void) /* Enable EEH for all adapters. Note that eeh requires buid's */ info.adapters_enabled = 0; - for (phb = find_devices("pci"); phb; phb = phb->next) { + for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) { int len; int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len); if (!buid_vals) --- linux-2.6.1-rc1/arch/ppc64/kernel/irq.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ppc64/kernel/irq.c 2004-01-04 22:15:32.000000000 -0800 @@ -300,7 +300,7 @@ void enable_irq(unsigned int irq) spin_lock_irqsave(&desc->lock, flags); switch (desc->depth) { case 1: { - unsigned int status = desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS); + unsigned int status = desc->status & ~IRQ_DISABLED; desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status = status | IRQ_REPLAY; --- linux-2.6.1-rc1/arch/ppc64/kernel/misc.S 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/ppc64/kernel/misc.S 2004-01-04 22:15:31.000000000 -0800 @@ -825,10 +825,10 @@ _GLOBAL(sys_call_table32) .llong .sys_ni_syscall .llong .sys_ni_syscall /* 225 - reserved for tux */ .llong .sys32_sendfile64 - .llong .sys32_io_setup + .llong .compat_sys_io_setup .llong .sys_io_destroy - .llong .sys32_io_getevents - .llong .sys32_io_submit + .llong .compat_sys_io_getevents + .llong .compat_sys_io_submit .llong .sys_io_cancel .llong .sys_set_tid_address .llong .ppc32_fadvise64 @@ -838,20 +838,21 @@ _GLOBAL(sys_call_table32) .llong .sys_epoll_ctl .llong .sys_epoll_wait .llong .sys_remap_file_pages - .llong .sys_ni_syscall /* 240 */ - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 245 */ - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_ni_syscall + .llong .ppc32_timer_create /* 240 */ + .llong .compat_timer_settime + .llong .compat_timer_gettime + .llong .sys_timer_getoverrun + .llong .sys_timer_delete + .llong .compat_clock_settime /* 245 */ + .llong .compat_clock_gettime + .llong .compat_clock_getres + .llong .compat_clock_nanosleep .llong .sys_ni_syscall .llong .sys32_tgkill /* 250 */ .llong .sys32_utimes - .llong .sys_statfs64 - .llong .sys_fstatfs64 + .llong .compat_statfs64 + .llong .compat_fstatfs64 + .llong .ppc32_fadvise64_64 /* 32bit only fadvise64_64 */ .balign 8 _GLOBAL(sys_call_table) @@ -1109,3 +1110,4 @@ _GLOBAL(sys_call_table) .llong .sys_utimes .llong .sys_statfs64 .llong .sys_fstatfs64 + .llong .sys_ni_syscall /* 32bit only fadvise64_64 */ --- linux-2.6.1-rc1/arch/ppc64/kernel/nvram.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/ppc64/kernel/nvram.c 2004-01-04 22:15:31.000000000 -0800 @@ -116,7 +116,7 @@ int __init nvram_init(void) { struct device_node *nvram; unsigned int *nbytes_p, proplen; - if ((nvram = find_type_devices("nvram")) != NULL) { + if ((nvram = of_find_node_by_type(NULL, "nvram")) != NULL) { nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen); if (nbytes_p && proplen == sizeof(unsigned int)) { rtas_nvram_size = *nbytes_p; @@ -125,6 +125,7 @@ int __init nvram_init(void) nvram_fetch = rtas_token("nvram-fetch"); nvram_store = rtas_token("nvram-store"); printk(KERN_INFO "PPC64 nvram contains %d bytes\n", rtas_nvram_size); + of_node_put(nvram); return misc_register(&nvram_dev); } --- linux-2.6.1-rc1/arch/ppc64/kernel/open_pic.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/ppc64/kernel/open_pic.c 2004-01-04 22:15:31.000000000 -0800 @@ -142,7 +142,7 @@ void __init openpic_init_IRQ(void) struct device_node *kbd; #endif - if (!(np = find_devices("pci")) + if (!(np = of_find_node_by_name(NULL, "pci")) || !(addrp = (unsigned int *) get_property(np, "8259-interrupt-acknowledge", NULL))) printk(KERN_ERR "Cannot find pci to get ack address\n"); @@ -158,6 +158,7 @@ void __init openpic_init_IRQ(void) openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq); for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) irq_desc[i].handler = &i8259_pic; + of_node_put(np); } static inline u_int openpic_read(volatile u_int *addr) --- linux-2.6.1-rc1/arch/ppc64/kernel/prom.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/ppc64/kernel/prom.c 2004-01-04 22:15:31.000000000 -0800 @@ -1487,7 +1487,7 @@ finish_device_tree(void) klimit = mem; - rtas.dev = find_devices("rtas"); + rtas.dev = of_find_node_by_name(NULL, "rtas"); } static unsigned long __init @@ -1939,11 +1939,14 @@ int machine_is_compatible(const char *compat) { struct device_node *root; - - root = find_path_device("/"); - if (root == 0) - return 0; - return device_is_compatible(root, compat); + int rc = 0; + + root = of_find_node_by_path("/"); + if (root) { + rc = device_is_compatible(root, compat); + of_node_put(root); + } + return rc; } /* --- linux-2.6.1-rc1/arch/ppc64/kernel/pSeries_htab.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/arch/ppc64/kernel/pSeries_htab.c 2004-01-04 22:15:31.000000000 -0800 @@ -389,10 +389,11 @@ void hpte_init_pSeries(void) ppc_md.hpte_remove = pSeries_hpte_remove; /* Disable TLB batching on nighthawk */ - root = find_path_device("/"); + root = of_find_node_by_path("/"); if (root) { model = get_property(root, "model", NULL); if (strcmp(model, "CHRP IBM,9076-N81")) ppc_md.flush_hash_range = pSeries_flush_hash_range; + of_node_put(root); } } --- linux-2.6.1-rc1/arch/ppc64/kernel/pSeries_lpar.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/arch/ppc64/kernel/pSeries_lpar.c 2004-01-04 22:15:31.000000000 -0800 @@ -234,11 +234,12 @@ void pSeriesLP_init_early(void) * is the starting termno (the one we use) and the second is the * number of terminals. */ - np = find_path_device("/rtas"); + np = of_find_node_by_path("/rtas"); if (np) { u32 *termno = (u32 *)get_property(np, "ibm,termno", 0); if (termno) vtermno = termno[0]; + of_node_put(np); } ppc_md.udbg_putc = udbg_putcLP; ppc_md.udbg_getc = udbg_getcLP; @@ -289,15 +290,17 @@ int hvc_count(int *start_termno) { u32 *termno; struct device_node *dn; + int ret = 0; - if ((dn = find_path_device("/rtas")) != NULL) { + if ((dn = of_find_node_by_path("/rtas")) != NULL) { if ((termno = (u32 *)get_property(dn, "ibm,termno", 0)) != NULL) { if (start_termno) *start_termno = termno[0]; - return termno[1]; + ret = termno[1]; } + of_node_put(dn); } - return 0; + return ret; } --- linux-2.6.1-rc1/arch/ppc64/kernel/pSeries_pci.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/arch/ppc64/kernel/pSeries_pci.c 2004-01-04 22:15:31.000000000 -0800 @@ -188,6 +188,7 @@ static void __init pci_process_bridge_OF struct resource *res; int np, na = prom_n_addr_cells(dev); unsigned long pci_addr, cpu_phys_addr; + struct device_node *isa_dn; np = na + 5; @@ -219,8 +220,11 @@ static void __init pci_process_bridge_OF size, _PAGE_NO_CACHE); if (primary) { pci_io_base = (unsigned long)hose->io_base_virt; - if (find_type_devices("isa")) + isa_dn = of_find_node_by_type(NULL, "isa"); + if (isa_dn) { isa_io_base = pci_io_base; + of_node_put(isa_dn); + } } res = &hose->io_resource; @@ -386,7 +390,7 @@ unsigned long __init find_and_init_phbs( unsigned int root_size_cells = 0; unsigned int index; unsigned int *opprop; - struct device_node *root = find_path_device("/"); + struct device_node *root = of_find_node_by_path("/"); read_pci_config = rtas_token("read-pci-config"); write_pci_config = rtas_token("write-pci-config"); @@ -402,7 +406,9 @@ unsigned long __init find_and_init_phbs( index = 0; - for (node = root->child; node != NULL; node = node->sibling) { + for (node = of_get_next_child(root, NULL); + node != NULL; + node = of_get_next_child(root, node)) { if (node->type == NULL || strcmp(node->type, "pci") != 0) continue; @@ -420,6 +426,7 @@ unsigned long __init find_and_init_phbs( index++; } + of_node_put(root); pci_devs_phb_init(); return 0; @@ -525,11 +532,12 @@ static void check_s7a(void) struct device_node *root; char *model; - root = find_path_device("/"); + root = of_find_node_by_path("/"); if (root) { model = get_property(root, "model", NULL); if (model && !strcmp(model, "IBM,7013-S7A")) s7a_workaround = 1; + of_node_put(root); } } --- linux-2.6.1-rc1/arch/ppc64/kernel/ras.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/arch/ppc64/kernel/ras.c 2004-01-04 22:15:31.000000000 -0800 @@ -70,27 +70,29 @@ static int __init init_ras_IRQ(void) struct device_node *np; unsigned int *ireg, len, i; - if((np = find_path_device("/event-sources/internal-errors")) && - (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", - &len))) { - for(i=0; i<(len / sizeof(*ireg)); i++) { + if ((np = of_find_node_by_path("/event-sources/internal-errors")) && + (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", + &len))) { + for (i=0; i<(len / sizeof(*ireg)); i++) { request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, ras_error_interrupt, 0, "RAS_ERROR", NULL); ireg++; } } + of_node_put(np); - if((np = find_path_device("/event-sources/epow-events")) && - (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", - &len))) { - for(i=0; i<(len / sizeof(*ireg)); i++) { + if ((np = of_find_node_by_path("/event-sources/epow-events")) && + (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", + &len))) { + for (i=0; i<(len / sizeof(*ireg)); i++) { request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, ras_epow_interrupt, 0, "RAS_EPOW", NULL); ireg++; } } + of_node_put(np); return 1; } --- linux-2.6.1-rc1/arch/ppc64/kernel/rtasd.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/ppc64/kernel/rtasd.c 2004-01-04 22:15:31.000000000 -0800 @@ -165,11 +165,12 @@ static int get_eventscan_parms(void) struct device_node *node; int *ip; - node = find_path_device("/rtas"); + node = of_find_node_by_path("/rtas"); ip = (int *)get_property(node, "rtas-event-scan-rate", NULL); if (ip == NULL) { printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); + of_node_put(node); return -1; } rtas_event_scan_rate = *ip; @@ -178,6 +179,7 @@ static int get_eventscan_parms(void) ip = (int *)get_property(node, "rtas-error-log-max", NULL); if (ip == NULL) { printk(KERN_ERR "rtasd: no rtas-error-log-max\n"); + of_node_put(node); return -1; } rtas_error_log_max = *ip; @@ -187,6 +189,7 @@ static int get_eventscan_parms(void) printk(KERN_ERR "rtasd: truncated error log from %d to %d bytes\n", rtas_error_log_max, RTAS_ERROR_LOG_MAX); rtas_error_log_max = RTAS_ERROR_LOG_MAX; } + of_node_put(node); return 0; } --- linux-2.6.1-rc1/arch/ppc64/kernel/rtas-proc.c 2003-06-14 12:18:09.000000000 -0700 +++ 25/arch/ppc64/kernel/rtas-proc.c 2004-01-04 22:15:31.000000000 -0800 @@ -200,7 +200,7 @@ void proc_rtas_init(void) { struct proc_dir_entry *entry; - rtas_node = find_devices("rtas"); + rtas_node = of_find_node_by_name(NULL, "rtas"); if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) { return; } --- linux-2.6.1-rc1/arch/ppc64/kernel/setup.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/ppc64/kernel/setup.c 2004-01-04 22:15:31.000000000 -0800 @@ -315,13 +315,14 @@ static int show_cpuinfo(struct seq_file struct device_node *cpu_node; int *fp; - cpu_node = find_type_devices("cpu"); + cpu_node = of_find_node_by_type(NULL, "cpu"); if (cpu_node) { fp = (int *) get_property(cpu_node, "clock-frequency", NULL); if (fp) seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000); + of_node_put(cpu_node); } } @@ -375,11 +376,12 @@ void parse_cmd_line(unsigned long r3, un strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); #endif /* CONFIG_CMDLINE */ - chosen = find_devices("chosen"); + chosen = of_find_node_by_name(NULL, "chosen"); if (chosen != NULL) { p = get_property(chosen, "bootargs", NULL); if (p != NULL && p[0] != 0) strlcpy(cmd_line, p, sizeof(cmd_line)); + of_node_put(chosen); } /* Look for mem= option on command line */ --- linux-2.6.1-rc1/arch/ppc64/kernel/signal32.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/ppc64/kernel/signal32.c 2004-01-04 22:15:31.000000000 -0800 @@ -93,7 +93,7 @@ struct rt_sigframe_32 { * it is a pointer to the user context in the rt stack frame */ u32 puc; - struct siginfo32 info; + struct compat_siginfo info; struct ucontext32 uc; }; @@ -639,7 +639,7 @@ long sys32_rt_sigpending(compat_sigset_t } -static int copy_siginfo_to_user32(siginfo_t32 *d, siginfo_t *s) +static int copy_siginfo_to_user32(compat_siginfo_t *d, siginfo_t *s) { int err; @@ -681,7 +681,7 @@ static int copy_siginfo_to_user32(siginf return err; } -long sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo, +long sys32_rt_sigtimedwait(compat_sigset_t *uthese, compat_siginfo_t *uinfo, struct compat_timespec *uts, compat_size_t sigsetsize) { sigset_t s; @@ -714,7 +714,7 @@ long sys32_rt_sigtimedwait(compat_sigset -static siginfo_t * siginfo32to64(siginfo_t *d, siginfo_t32 *s) +static siginfo_t * siginfo32to64(siginfo_t *d, compat_siginfo_t *s) { d->si_signo = s->si_signo; d->si_errno = s->si_errno; @@ -758,14 +758,14 @@ static siginfo_t * siginfo32to64(siginfo * (msr in 32-bit mode) and the register representation of a signed int * (msr in 64-bit mode) is performed. */ -long sys32_rt_sigqueueinfo(u32 pid, u32 sig, siginfo_t32 *uinfo) +long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t *uinfo) { siginfo_t info; - siginfo_t32 info32; + compat_siginfo_t info32; int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) + if (copy_from_user (&info32, uinfo, sizeof(compat_siginfo_t))) return -EFAULT; /* XXX: Is this correct? */ siginfo32to64(&info, &info32); --- linux-2.6.1-rc1/arch/ppc64/kernel/sys_ppc32.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/ppc64/kernel/sys_ppc32.c 2004-01-04 22:15:31.000000000 -0800 @@ -2683,98 +2683,6 @@ unsigned long sys32_mmap2(unsigned long return sys_mmap(addr, len, prot, flags, fd, pgoff << 12); } -extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx); - -long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p) -{ - long ret; - aio_context_t ctx64; - mm_segment_t oldfs = get_fs(); - - if (get_user((u32)ctx64, ctx32p)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_io_setup(nr_reqs, &ctx64); - set_fs(oldfs); - - /* truncating is ok because it's a user address */ - if (!ret) - ret = put_user((u32)ctx64, ctx32p); - - return ret; -} - -long sys_io_getevents(aio_context_t ctx_id, long min_nr, long nr, - struct io_event *events, struct timespec *timeout); - -long sys32_io_getevents(aio_context_t ctx_id, u32 min_nr, u32 nr, - struct io_event *events, struct compat_timespec *t32) -{ - struct timespec t; - long ret; - mm_segment_t oldfs = get_fs(); - - if (t32) { - if (get_user(t.tv_sec, &t32->tv_sec) || - __get_user(t.tv_nsec, &t32->tv_nsec)) - return -EFAULT; - } - - if (verify_area(VERIFY_WRITE, events, nr * sizeof(*events))) - return -EFAULT; - - set_fs(KERNEL_DS); - /* sign extend min_nr and nr */ - ret = sys_io_getevents(ctx_id, (int)min_nr, (int)nr, events, - t32 ? &t : NULL); - set_fs(oldfs); - - return ret; -} - -long sys32_io_submit(aio_context_t ctx_id, u32 number, u32 *iocbpp) -{ - struct kioctx *ctx; - long ret = 0; - int i; - int nr = (int)number; /* sign extend */ - - if (unlikely(nr < 0)) - return -EINVAL; - - if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(u32))))) - return -EFAULT; - - ctx = lookup_ioctx(ctx_id); - if (unlikely(!ctx)) { - pr_debug("EINVAL: io_submit: invalid context id\n"); - return -EINVAL; - } - - for (i=0; isigev_value.sival_int) + || __get_user(event.sigev_signo, &ev32->sigev_signo) + || __get_user(event.sigev_notify, &ev32->sigev_notify) + || __get_user(event.sigev_notify_thread_id, + &ev32->sigev_notify_thread_id)) + return -EFAULT; + + if (!access_ok(VERIFY_WRITE, timer_id, sizeof(timer_t))) + return -EFAULT; + + savefs = get_fs(); + err = sys_timer_create(clock, &event, &t); + set_fs(savefs); + + if (err == 0) + err = __put_user(t, timer_id); + + return err; +} --- linux-2.6.1-rc1/arch/ppc64/kernel/time.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/ppc64/kernel/time.c 2004-01-04 22:15:31.000000000 -0800 @@ -91,6 +91,9 @@ unsigned tb_to_us; unsigned long processor_freq; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +unsigned long tb_to_ns_scale; +unsigned long tb_to_ns_shift; + struct gettimeofday_struct do_gtod; extern unsigned long wall_jiffies; @@ -313,11 +316,13 @@ int timer_interrupt(struct pt_regs * reg /* * Scheduler clock - returns current time in nanosec units. * - * This is wrong, but my CPUs run at 1GHz, so nyer nyer. + * Note: mulhdu(a, b) (multiply high double unsigned) returns + * the high 64 bits of a * b, i.e. (a * b) >> 64, where a and b + * are 64-bit unsigned numbers. */ unsigned long long sched_clock(void) { - return get_tb(); + return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; } /* @@ -473,9 +478,30 @@ void __init time_init(void) /* This function is only called on the boot processor */ unsigned long flags; struct rtc_time tm; + struct div_result res; + unsigned long scale, shift; ppc_md.calibrate_decr(); + /* + * Compute scale factor for sched_clock. + * The calibrate_decr() function has set tb_ticks_per_sec, + * which is the timebase frequency. + * We compute 1e9 * 2^64 / tb_ticks_per_sec and interpret + * the 128-bit result as a 64.64 fixed-point number. + * We then shift that number right until it is less than 1.0, + * giving us the scale factor and shift count to use in + * sched_clock(). + */ + div128_by_32(1000000000, 0, tb_ticks_per_sec, &res); + scale = res.result_low; + for (shift = 0; res.result_high != 0; ++shift) { + scale = (scale >> 1) | (res.result_high << 63); + res.result_high >>= 1; + } + tb_to_ns_scale = scale; + tb_to_ns_shift = shift; + #ifdef CONFIG_PPC_ISERIES if (!piranha_simulator) #endif --- linux-2.6.1-rc1/arch/ppc64/kernel/xics.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/arch/ppc64/kernel/xics.c 2004-01-04 22:15:31.000000000 -0800 @@ -398,7 +398,7 @@ void xics_init_IRQ(void) ibm_int_on = rtas_token("ibm,int-on"); ibm_int_off = rtas_token("ibm,int-off"); - np = find_type_devices("PowerPC-External-Interrupt-Presentation"); + np = of_find_node_by_type(NULL, "PowerPC-External-Interrupt-Presentation"); if (!np) { printk(KERN_WARNING "Can't find Interrupt Presentation\n"); udbg_printf("Can't find Interrupt Presentation\n"); @@ -433,11 +433,13 @@ nextnode: if (indx >= NR_CPUS) break; } - np = np->next; + np = of_find_node_by_type(np, "PowerPC-External-Interrupt-Presentation"); if ((indx < NR_CPUS) && np) goto nextnode; /* Find the server numbers for the boot cpu. */ - for (np = find_type_devices("cpu"); np; np = np->next) { + for (np = of_find_node_by_type(NULL, "cpu"); + np; + np = of_find_node_by_type(np, "cpu")) { ireg = (uint *)get_property(np, "reg", &ilen); if (ireg && ireg[0] == smp_processor_id()) { ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); @@ -449,11 +451,12 @@ nextnode: break; } } + of_node_put(np); intr_base = inodes[0].addr; intr_size = (ulong)inodes[0].size; - np = find_type_devices("interrupt-controller"); + np = of_find_node_by_type(NULL, "interrupt-controller"); if (!np) { printk(KERN_WARNING "xics: no ISA Interrupt Controller\n"); xics_irq_8259_cascade_real = -1; @@ -467,6 +470,7 @@ nextnode: } xics_irq_8259_cascade_real = *ireg; xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real); + of_node_put(np); } if (systemcfg->platform == PLATFORM_PSERIES) { --- linux-2.6.1-rc1/arch/ppc64/mm/numa.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/ppc64/mm/numa.c 2004-01-04 22:15:32.000000000 -0800 @@ -46,29 +46,29 @@ static inline void map_cpu_to_node(int c static int __init parse_numa_properties(void) { - struct device_node *cpu; - struct device_node *memory; + struct device_node *cpu = NULL; + struct device_node *memory = NULL; int *cpu_associativity; int *memory_associativity; int depth; int max_domain = 0; - cpu = find_type_devices("cpu"); + cpu = of_find_node_by_type(NULL, "cpu"); if (!cpu) - return -1; + goto err; - memory = find_type_devices("memory"); + memory = of_find_node_by_type(NULL, "memory"); if (!memory) - return -1; + goto err; cpu_associativity = (int *)get_property(cpu, "ibm,associativity", NULL); if (!cpu_associativity) - return -1; + goto err; memory_associativity = (int *)get_property(memory, "ibm,associativity", NULL); if (!memory_associativity) - return -1; + goto err; /* find common depth */ if (cpu_associativity[0] < memory_associativity[0]) @@ -76,7 +76,7 @@ static int __init parse_numa_properties( else depth = memory_associativity[0]; - for (cpu = find_type_devices("cpu"); cpu; cpu = cpu->next) { + for (; cpu; cpu = of_find_node_by_type(cpu, "cpu")) { int *tmp; int cpu_nr, numa_domain; @@ -106,9 +106,8 @@ static int __init parse_numa_properties( map_cpu_to_node(cpu_nr, numa_domain); } - for (memory = find_type_devices("memory"); memory; - memory = memory->next) { - int *tmp1, *tmp2; + for (; memory; memory = of_find_node_by_type(memory, "memory")) { + unsigned int *tmp1, *tmp2; unsigned long i; unsigned long start = 0; unsigned long size = 0; @@ -196,6 +195,10 @@ new_range: numnodes = max_domain + 1; return 0; +err: + of_node_put(cpu); + of_node_put(memory); + return -1; } void setup_nonnuma(void) --- linux-2.6.1-rc1/arch/ppc/boot/ld.script 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/ppc/boot/ld.script 2004-01-04 22:22:00.000000000 -0800 @@ -82,6 +82,7 @@ SECTIONS *(__ksymtab) *(__ksymtab_strings) *(__bug_table) + *(__kcrctab) } } --- linux-2.6.1-rc1/arch/ppc/kernel/Makefile 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/ppc/kernel/Makefile 2004-01-04 22:15:50.000000000 -0800 @@ -9,8 +9,7 @@ ifdef CONFIG_4xx EXTRA_AFLAGS := -Wa,-m405 endif -# Start off with 'head.o', change as needed. -extra-y := head.o +extra-$(CONFIG_PPC_STD_MMU) := head.o extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_8xx) := head_8xx.o --- linux-2.6.1-rc1/arch/ppc/kernel/ppc_ksyms.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/ppc/kernel/ppc_ksyms.c 2004-01-04 22:15:50.000000000 -0800 @@ -92,7 +92,7 @@ EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); -EXPORT_SYMBOL_NOVERS(DMA_MODE_READ); +EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); #if defined(CONFIG_PPC_PREP) EXPORT_SYMBOL(_prep_type); @@ -167,9 +167,9 @@ EXPORT_SYMBOL(ppc_ide_md); #endif #ifdef CONFIG_PCI -EXPORT_SYMBOL_NOVERS(isa_io_base); -EXPORT_SYMBOL_NOVERS(isa_mem_base); -EXPORT_SYMBOL_NOVERS(pci_dram_offset); +EXPORT_SYMBOL(isa_io_base); +EXPORT_SYMBOL(isa_mem_base); +EXPORT_SYMBOL(pci_dram_offset); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_bus_io_base); @@ -246,7 +246,7 @@ EXPORT_SYMBOL(register_backlight_control EXPORT_SYMBOL(_machine); #endif #ifdef CONFIG_PPC_PMAC -EXPORT_SYMBOL_NOVERS(sys_ctrler); +EXPORT_SYMBOL(sys_ctrler); EXPORT_SYMBOL(pmac_newworld); #endif #ifdef CONFIG_PPC_OF @@ -294,15 +294,15 @@ EXPORT_SYMBOL(to_tm); EXPORT_SYMBOL(pm_power_off); -EXPORT_SYMBOL_NOVERS(__ashrdi3); -EXPORT_SYMBOL_NOVERS(__ashldi3); -EXPORT_SYMBOL_NOVERS(__lshrdi3); -EXPORT_SYMBOL_NOVERS(memcpy); -EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memcmp); -EXPORT_SYMBOL_NOVERS(memchr); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(abs); @@ -366,7 +366,7 @@ EXPORT_SYMBOL(request_8xxirq); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(handle_mm_fault); /* For MOL */ -EXPORT_SYMBOL_NOVERS(disarm_decr); +EXPORT_SYMBOL(disarm_decr); #ifdef CONFIG_PPC_STD_MMU extern long mol_trampoline; EXPORT_SYMBOL(mol_trampoline); /* For MOL */ @@ -381,5 +381,5 @@ EXPORT_SYMBOL(intercept_table); EXPORT_SYMBOL(cur_cpu_spec); #ifdef CONFIG_PPC_PMAC extern unsigned long agp_special_page; -EXPORT_SYMBOL_NOVERS(agp_special_page); +EXPORT_SYMBOL(agp_special_page); #endif --- linux-2.6.1-rc1/arch/ppc/mm/cachemap.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/ppc/mm/cachemap.c 2004-01-04 22:15:50.000000000 -0800 @@ -170,3 +170,5 @@ void consistent_sync_page(struct page *p start = (unsigned long)page_address(page) + offset; consistent_sync((void *)start, size, direction); } + +EXPORT_SYMBOL(consistent_sync_page); --- linux-2.6.1-rc1/arch/ppc/platforms/mpc82xx.h 2003-09-27 18:57:43.000000000 -0700 +++ /dev/null 2002-08-30 16:31:37.000000000 -0700 @@ -1,42 +0,0 @@ -/* - * arch/ppc/platforms/mpc82xx.h - * - * Board specific support for various 82xx platforms. - * - * Author: Allen Curtis - * - * Copyright 2002 Ones and Zeros, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#ifndef __CONFIG_82XX_PLATFORMS -#define __CONFIG_82XX_PLATFORMS - -#ifdef CONFIG_8260 - -#ifdef CONFIG_EST8260 -#include -#endif - -#ifdef CONFIG_SBS8260 -#include -#endif - -#ifdef CONFIG_RPX6 -#include -#endif - -#ifdef CONFIG_WILLOW -#include -#endif - -#ifdef CONFIG_TQM8260 -#include -#endif - -#endif /* CONFIG_8260 */ - -#endif --- linux-2.6.1-rc1/arch/sparc64/defconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/sparc64/defconfig 2004-01-04 17:36:23.000000000 -0800 @@ -27,6 +27,7 @@ CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support @@ -345,6 +346,8 @@ CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y # CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m +# CONFIG_SCSI_DC390T_NOGENSUPP is not set # CONFIG_SCSI_NSP32 is not set CONFIG_SCSI_DEBUG=m CONFIG_SCSI_SUNESP=y @@ -1007,7 +1010,6 @@ CONFIG_KEYBOARD_SUNKBD=y # CONFIG_KEYBOARD_NEWTON is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y -# CONFIG_MOUSE_PS2_SYNAPTICS is not set CONFIG_MOUSE_SERIAL=y # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TOUCHSCREEN is not set @@ -1058,6 +1060,7 @@ CONFIG_SENSORS_EEPROM=m CONFIG_SENSORS_IT87=m CONFIG_SENSORS_LM75=m CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM83=m CONFIG_SENSORS_LM85=m CONFIG_SENSORS_VIA686A=m CONFIG_SENSORS_W83781D=m @@ -1184,12 +1187,11 @@ CONFIG_RXRPC=m # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y CONFIG_SUN_PARTITION=y -CONFIG_SMB_NLS=y -CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set @@ -1274,6 +1276,7 @@ CONFIG_DVB_CORE=m # # Supported Frontend Modules # +CONFIG_DVB_TWINHAN_DST=m CONFIG_DVB_STV0299=m CONFIG_DVB_SP887X=m CONFIG_DVB_ALPS_TDLB7=m @@ -1285,6 +1288,7 @@ CONFIG_DVB_GRUNDIG_29504_401=m CONFIG_DVB_MT312=m CONFIG_DVB_VES1820=m CONFIG_DVB_VES1X93=m +CONFIG_DVB_SP887X_FIRMWARE_FILE="/etc/dvb/sc_main.mc" # # Supported SAA7146 based PCI Adapters @@ -1299,11 +1303,17 @@ CONFIG_DVB_BUDGET_PATCH=m # Supported USB Adapters # # CONFIG_DVB_TTUSB_BUDGET is not set +CONFIG_DVB_TTUSB_DEC=m # # Supported FlexCopII (B2C2) Adapters # CONFIG_DVB_B2C2_SKYSTAR=m + +# +# Supported BT878 Adapters +# +CONFIG_DVB_BT8XX=m CONFIG_VIDEO_SAA7146=m CONFIG_VIDEO_SAA7146_VV=m CONFIG_VIDEO_VIDEOBUF=m @@ -1463,6 +1473,7 @@ CONFIG_USB_HPUSBSCSI=m # CONFIG_USB_PWC is not set # CONFIG_USB_SE401 is not set # CONFIG_USB_STV680 is not set +CONFIG_USB_W9968CF=m # # USB Network adaptors @@ -1544,6 +1555,7 @@ CONFIG_USB_EZUSB=y # CONFIG_USB_TIGL is not set CONFIG_USB_AUERSWALD=m CONFIG_USB_RIO500=m +CONFIG_USB_LEGOTOWER=m # CONFIG_USB_BRLVGER is not set CONFIG_USB_LCD=m CONFIG_USB_SPEEDTOUCH=m --- linux-2.6.1-rc1/arch/sparc64/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/sparc64/Kconfig 2004-01-04 22:21:58.000000000 -0800 @@ -840,12 +840,19 @@ config STACK_DEBUG depends on DEBUG_KERNEL bool "Stack Overflow Detection Support" +config LOCKMETER + bool "Kernel lock metering" + depends on SMP && !PREEMPT + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + # We have a custom atomic_dec_and_lock() implementation but it's not # compatible with spinlock debugging so we need to fall back on # the generic version in that case. config HAVE_DEC_LOCK bool - depends on SMP && !DEBUG_SPINLOCK + depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER default y config MCOUNT --- linux-2.6.1-rc1/arch/sparc64/lib/rwlock.S 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/sparc64/lib/rwlock.S 2004-01-04 22:21:58.000000000 -0800 @@ -85,5 +85,20 @@ __write_trylock_succeed: __write_trylock_fail: retl mov 0, %o0 + + .globl __read_trylock +__read_trylock: /* %o0 = lock_ptr */ + ldsw [%o0], %g5 + brlz,pn %g5, 100f + add %g5, 1, %g7 + cas [%o0], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __read_trylock + membar #StoreLoad | #StoreStore + retl + mov 1, %o0 +100: retl + mov 0, %o0 + rwlock_impl_end: --- linux-2.6.1-rc1/arch/um/drivers/ubd_kern.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/um/drivers/ubd_kern.c 2004-01-04 17:36:41.000000000 -0800 @@ -49,9 +49,9 @@ static spinlock_t ubd_lock = SPIN_LOCK_U static void (*do_ubd)(void); -static int ubd_open(struct inode * inode, struct file * filp); -static int ubd_release(struct inode * inode, struct file * file); -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_open(struct block_device *bdev, struct file * filp); +static int ubd_release(struct gendisk *disk); +static int ubd_ioctl(struct block_device *bdev, struct file * file, unsigned int cmd, unsigned long arg); #define MAX_DEV (8) @@ -710,9 +710,9 @@ int ubd_driver_init(void){ device_initcall(ubd_driver_init); -static int ubd_open(struct inode *inode, struct file *filp) +static int ubd_open(struct block_device *bdev, struct file *filp) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct ubd *dev = disk->private_data; int err = -EISDIR; @@ -739,9 +739,8 @@ static int ubd_open(struct inode *inode, return(err); } -static int ubd_release(struct inode * inode, struct file * file) +static int ubd_release(struct gendisk *disk) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; if(--dev->count == 0) @@ -865,11 +864,11 @@ static void do_ubd_request(request_queue } } -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_ioctl(struct block_device *bdev, struct file * file, unsigned int cmd, unsigned long arg) { struct hd_geometry *loc = (struct hd_geometry *) arg; - struct ubd *dev = inode->i_bdev->bd_disk->private_data; + struct ubd *dev = bdev->bd_disk->private_data; int err; struct hd_driveid ubd_id = { .cyls = 0, @@ -890,7 +889,7 @@ static int ubd_ioctl(struct inode * inod case HDIO_SET_UNMASKINTR: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || (inode->i_bdev->bd_contains != inode->i_bdev)) + if((arg > 1) || (bdev->bd_contains != bdev)) return(-EINVAL); return(0); @@ -910,7 +909,7 @@ static int ubd_ioctl(struct inode * inod case HDIO_SET_MULTCOUNT: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if(inode->i_bdev->bd_contains != inode->i_bdev) + if(bdev->bd_contains != bdev) return(-EINVAL); return(0); --- linux-2.6.1-rc1/arch/x86_64/boot/compressed/head.S 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/x86_64/boot/compressed/head.S 2004-01-04 17:36:33.000000000 -0800 @@ -26,6 +26,7 @@ .code32 .text +#define IN_BOOTLOADER #include #include --- linux-2.6.1-rc1/arch/x86_64/boot/compressed/misc.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/x86_64/boot/compressed/misc.c 2004-01-04 17:36:33.000000000 -0800 @@ -9,6 +9,7 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#define IN_BOOTLOADER #include "miscsetup.h" #include --- linux-2.6.1-rc1/arch/x86_64/boot/install.sh 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/x86_64/boot/install.sh 2004-01-04 17:36:23.000000000 -0800 @@ -21,6 +21,7 @@ # User may have a custom install script +if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi # Default install - same as make zlilo --- linux-2.6.1-rc1/arch/x86_64/ia32/ia32entry.S 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/ia32/ia32entry.S 2004-01-04 17:36:23.000000000 -0800 @@ -330,10 +330,10 @@ ia32_sys_call_table: .quad sys32_adjtimex .quad sys32_mprotect /* 125 */ .quad compat_sys_sigprocmask - .quad sys32_module_warning /* create_module */ + .quad quiet_ni_syscall /* create_module */ .quad sys_init_module .quad sys_delete_module - .quad sys32_module_warning /* 130 get_kernel_syms */ + .quad quiet_ni_syscall /* 130 get_kernel_syms */ .quad ni_syscall /* quotactl */ .quad sys_getpgid .quad sys_fchdir --- linux-2.6.1-rc1/arch/x86_64/ia32/ia32_ioctl.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/x86_64/ia32/ia32_ioctl.c 2004-01-04 17:36:23.000000000 -0800 @@ -59,7 +59,7 @@ static int rtc32_ioctl(unsigned fd, unsi return ret; case RTC_IRQP_SET32: - cmd = RTC_EPOCH_SET; + cmd = RTC_IRQP_SET; break; case RTC_EPOCH_READ32: --- linux-2.6.1-rc1/arch/x86_64/ia32/syscall32.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/x86_64/ia32/syscall32.c 2004-01-04 17:36:23.000000000 -0800 @@ -30,10 +30,12 @@ char *syscall32_page; int map_syscall32(struct mm_struct *mm, unsigned long address) { pte_t *pte; + pmd_t *pmd; int err = 0; + down_read(&mm->mmap_sem); spin_lock(&mm->page_table_lock); - pmd_t *pmd = pmd_alloc(mm, pgd_offset(mm, address), address); + pmd = pmd_alloc(mm, pgd_offset(mm, address), address); if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) { if (pte_none(*pte)) { set_pte(pte, --- linux-2.6.1-rc1/arch/x86_64/ia32/sys_ia32.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/ia32/sys_ia32.c 2004-01-04 17:36:23.000000000 -0800 @@ -1832,13 +1832,6 @@ long asmlinkage sys32_nfsservctl(int cmd } #endif -long sys32_module_warning(void) -{ - printk(KERN_INFO "%s: 32bit 2.4.x modutils not supported on 64bit kernel\n", - current->comm); - return -ENOSYS ; -} - extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx); long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p) @@ -2004,12 +1997,16 @@ long sys32_fadvise64_64(int fd, __u32 of long sys32_vm86_warning(void) { + struct task_struct *me = current; + static char lastcomm[8]; + if (strcmp(lastcomm, me->comm)) { printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n", - current->comm); - return -ENOSYS ; + me->comm); + strcpy(lastcomm, me->comm); + } + return -ENOSYS; } - struct exec_domain ia32_exec_domain = { .name = "linux/x86", .pers_low = PER_LINUX32, --- linux-2.6.1-rc1/arch/x86_64/Kconfig 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/Kconfig 2004-01-04 17:36:23.000000000 -0800 @@ -333,6 +333,11 @@ config PCI_DIRECT depends on PCI default y +# the drivers/pci/msi.c code needs to be fixed first before enabling +config PCI_USE_VECTOR + bool + default n + source "drivers/pci/Kconfig" config HOTPLUG @@ -526,13 +531,6 @@ config IOMMU_LEAK Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. -config MCE_DEBUG - bool "K8 Machine check debugging mode" - default y - help - Turn on all Machine Check debugging for device driver problems. - This can cause panics, but is useful to find device driver problems. - #config X86_REMOTE_DEBUG # bool "kgdb debugging stub" --- linux-2.6.1-rc1/arch/x86_64/kernel/acpi/boot.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/x86_64/kernel/acpi/boot.c 2004-01-04 22:15:28.000000000 -0800 @@ -46,11 +46,13 @@ #include #include -int acpi_lapic = 0; -int acpi_ioapic = 0; - #define PREFIX "ACPI: " +int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +int acpi_ht __initdata = 1; /* enable HT */ + +int acpi_lapic = 0; +int acpi_ioapic = 0; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -253,29 +255,66 @@ acpi_parse_hpet ( #ifdef CONFIG_ACPI_BUS /* - * Set specified PIC IRQ to level triggered mode. + * "acpi_pic_sci=level" (current default) + * programs the PIC-mode SCI to Level Trigger. + * (NO-OP if the BIOS set Level Trigger already) + * + * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_pic_sci=edge" + * (NO-OP if the BIOS set Edge Trigger already) * * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) - * - * As the BIOS should have done this for us, - * print a warning if the IRQ wasn't already set to level. */ -void acpi_pic_set_level_irq(unsigned int irq) +static int __initdata acpi_pic_sci_trigger; /* 0: level, 1: edge */ + +void __init +acpi_pic_sci_set_trigger(unsigned int irq) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); unsigned char val = inb(port); + + printk(PREFIX "IRQ%d SCI:", irq); if (!(val & mask)) { - printk(KERN_WARNING PREFIX "IRQ %d was Edge Triggered, " - "setting to Level Triggerd\n", irq); - outb(val | mask, port); + printk(" Edge"); + + if (!acpi_pic_sci_trigger) { + printk(" set to Level"); + outb(val | mask, port); + } + } else { + printk(" Level"); + + if (acpi_pic_sci_trigger) { + printk(" set to Edge"); + outb(val | mask, port); + } } + printk(" Trigger.\n"); } + +int __init +acpi_pic_sci_setup(char *str) +{ + while (str && *str) { + if (strncmp(str, "level", 5) == 0) + acpi_pic_sci_trigger = 0; /* force level trigger */ + if (strncmp(str, "edge", 4) == 0) + acpi_pic_sci_trigger = 1; /* force edge trigger */ + str = strchr(str, ','); + if (str) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("acpi_pic_sci=", acpi_pic_sci_setup); + #endif /* CONFIG_ACPI_BUS */ static unsigned long __init @@ -354,8 +393,10 @@ acpi_boot_init (void) * Initialize the ACPI boot-time table parser. */ result = acpi_table_init(); - if (result) + if (result) { + acpi_disabled = 1; return result; + } result = acpi_blacklisted(); if (result) { @@ -442,7 +483,7 @@ acpi_boot_init (void) * If MPS is present, it will handle them, * otherwise the system will stay in PIC mode */ - if (acpi_disabled) { + if (acpi_disabled || acpi_noirq) { return 1; } @@ -484,6 +525,8 @@ acpi_boot_init (void) acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; #endif /*CONFIG_X86_IO_APIC*/ --- linux-2.6.1-rc1/arch/x86_64/kernel/apic.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/x86_64/kernel/apic.c 2004-01-04 17:36:23.000000000 -0800 @@ -42,6 +42,8 @@ static DEFINE_PER_CPU(int, prof_multipli static DEFINE_PER_CPU(int, prof_old_multiplier) = 1; static DEFINE_PER_CPU(int, prof_counter) = 1; +static void apic_pm_activate(void); + void enable_NMI_through_LVT0 (void * dummy) { unsigned int v, ver; @@ -435,6 +437,7 @@ void __init setup_local_APIC (void) if (nmi_watchdog == NMI_LOCAL_APIC) setup_apic_nmi_watchdog(); + apic_pm_activate(); } #ifdef CONFIG_PM @@ -556,7 +559,7 @@ device_initcall(init_lapic_sysfs); #else /* CONFIG_PM */ -static inline void apic_pm_activate(void) { } +static void apic_pm_activate(void) { } #endif /* CONFIG_PM */ @@ -579,7 +582,6 @@ static int __init detect_init_APIC (void if (nmi_watchdog != NMI_NONE) nmi_watchdog = NMI_LOCAL_APIC; - apic_pm_activate(); return 0; } --- linux-2.6.1-rc1/arch/x86_64/kernel/bluesmoke.c 2003-08-08 22:55:11.000000000 -0700 +++ 25/arch/x86_64/kernel/bluesmoke.c 2004-01-04 17:36:23.000000000 -0800 @@ -26,19 +26,6 @@ static unsigned long mce_cpus; static int banks; static unsigned long ignored_banks, disabled_banks; -/* Machine Check on everything dubious. This is a good setting - for device driver testing. */ -#define K8_DRIVER_DEBUG ((1<<13)-1) -/* Report RAM errors and Hyper Transport Problems, but ignore Device - aborts and GART errors. */ -#define K8_NORMAL_OP 0xff - -#ifdef CONFIG_MCE_DEBUG -static u32 k8_nb_flags __initdata = K8_DRIVER_DEBUG; -#else -static u32 k8_nb_flags __initdata = K8_NORMAL_OP; -#endif - static void generic_machine_check(struct pt_regs * regs, long error_code) { int recover=1; @@ -200,11 +187,14 @@ static char *highbits[32] = { static void check_k8_nb(int header) { struct pci_dev *nb; + u32 statuslow, statushigh; + unsigned short errcode; + int i; + nb = find_k8_nb(); if (nb == NULL) return; - u32 statuslow, statushigh; pci_read_config_dword(nb, 0x48, &statuslow); pci_read_config_dword(nb, 0x4c, &statushigh); if (!(statushigh & (1<<31))) @@ -215,50 +205,42 @@ static void check_k8_nb(int header) printk(KERN_ERR "Northbridge status %08x%08x\n", statushigh,statuslow); - unsigned short errcode = statuslow & 0xffff; - switch (errcode >> 8) { - case 0: + printk(KERN_ERR " Error %s\n", extendederr[(statuslow >> 16) & 0xf]); + + errcode = statuslow & 0xffff; + switch ((statuslow >> 16) & 0xF) { + case 5: printk(KERN_ERR " GART TLB error %s %s\n", transaction[(errcode >> 2) & 3], cachelevel[errcode & 3]); break; - case 1: - if (errcode & (1<<11)) { - printk(KERN_ERR " bus error %s %s %s %s %s\n", - partproc[(errcode >> 10) & 0x3], - timeout[(errcode >> 9) & 1], + case 8: + printk(KERN_ERR " ECC error syndrome %x\n", + (((statuslow >> 24) & 0xff) << 8) | ((statushigh >> 15) & 0x7f)); + /*FALL THROUGH*/ + default: + printk(KERN_ERR " bus error %s, %s\n %s\n %s, %s\n", + partproc[(errcode >> 9) & 0x3], + timeout[(errcode >> 8) & 1], memtrans[(errcode >> 4) & 0xf], memoryio[(errcode >> 2) & 0x3], cachelevel[(errcode & 0x3)]); - } else if (errcode & (1<<8)) { - printk(KERN_ERR " memory error %s %s %s\n", - memtrans[(errcode >> 4) & 0xf], - transaction[(errcode >> 2) & 0x3], - cachelevel[(errcode & 0x3)]); - } else { - printk(KERN_ERR " unknown error code %x\n", errcode); - } - break; - } - if (statushigh & ((1<<14)|(1<<13))) - printk(KERN_ERR " ECC syndrome bits %x\n", - (((statuslow >> 24) & 0xff) << 8) | ((statushigh >> 15) & 0x7f)); - errcode = (statuslow >> 16) & 0xf; - printk(KERN_ERR " extended error %s\n", extendederr[(statuslow >> 16) & 0xf]); - /* should only print when it was a HyperTransport related error. */ printk(KERN_ERR " link number %x\n", (statushigh >> 4) & 3); + break; + } - int i; - for (i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { + if (i == 26 || i == 28) + continue; if (highbits[i] && (statushigh & (1<rip, regs->rsp); - others: generic_machine_check(regs, error_code); @@ -367,12 +346,13 @@ static void __init k8_mcheck_init(struct machine_check_vector = k8_machine_check; for (i = 0; i < banks; i++) { u64 val = ((1UL< disable bank NUMBER mce=enable enable bank number - mce=device Enable device driver test reporting in NB mce=NUMBER mcheck timer interval number seconds. Can be also comma separated in a single mce= */ static int __init mcheck_enable(char *str) @@ -486,8 +465,6 @@ static int __init mcheck_enable(char *st disabled_banks |= ~(1< #include --- linux-2.6.1-rc1/arch/x86_64/kernel/head.S 2003-08-08 22:55:11.000000000 -0700 +++ 25/arch/x86_64/kernel/head.S 2004-01-04 17:36:23.000000000 -0800 @@ -38,6 +38,9 @@ startup_32: movl %ebx,%ebp /* Save trampoline flag */ + movl $__KERNEL_DS,%eax + movl %eax,%ds + /* If the CPU doesn't support CPUID this will double fault. * Unfortunately it is hard to check for CPUID without a stack. */ @@ -114,25 +117,11 @@ reach_compatibility_mode: movl $(pGDT32 - __START_KERNEL_map), %eax lgdt (%eax) +second: movl $(ljumpvector - __START_KERNEL_map), %eax /* Finally jump in 64bit mode */ ljmp *(%eax) -second: - /* abuse syscall to get into 64bit mode. this way we don't need - a working low identity mapping just for the short 32bit roundtrip. - XXX kludge. this should not be needed. */ - movl $MSR_STAR,%ecx - xorl %eax,%eax - movl $(__USER32_CS<<16)|__KERNEL_CS,%edx - wrmsr - - movl $MSR_CSTAR,%ecx - movl $0xffffffff,%edx - movl $0x80100100,%eax # reach_long64 absolute - wrmsr - syscall - .code64 .org 0x100 reach_long64: --- linux-2.6.1-rc1/arch/x86_64/kernel/i8259.c 2003-07-02 14:53:14.000000000 -0700 +++ 25/arch/x86_64/kernel/i8259.c 2004-01-04 17:36:23.000000000 -0800 @@ -446,8 +446,10 @@ void __init init_IRQ(void) * us. (some of these will be overridden and become * 'special' SMP interrupts) */ - for (i = 0; i < NR_IRQS; i++) { + for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { int vector = FIRST_EXTERNAL_VECTOR + i; + if (i >= NR_IRQS) + break; if (vector != IA32_SYSCALL_VECTOR && vector != KDB_VECTOR) { set_intr_gate(vector, interrupt[i]); } --- linux-2.6.1-rc1/arch/x86_64/kernel/io_apic.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/x86_64/kernel/io_apic.c 2004-01-04 22:15:28.000000000 -0800 @@ -66,6 +66,14 @@ static struct irq_pin_list { short apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; +#ifdef CONFIG_PCI_USE_VECTOR +int vector_irq[NR_IRQS] = { [0 ... NR_IRQS -1] = -1}; +#define vector_to_irq(vector) \ + (platform_legacy_irq(vector) ? vector : vector_irq[vector]) +#else +#define vector_to_irq(vector) (vector) +#endif + /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super @@ -147,6 +155,13 @@ void clear_IO_APIC_pin(unsigned int apic struct IO_APIC_route_entry entry; unsigned long flags; + /* Check delivery_mode to be sure we're not clearing an SMI pin */ + spin_lock_irqsave(&ioapic_lock, flags); + *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); + *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); + spin_unlock_irqrestore(&ioapic_lock, flags); + if (entry.delivery_mode == dest_SMI) + return; /* * Disable it in the IO-APIC irq-routing table: */ @@ -625,7 +640,8 @@ static inline int IO_APIC_irq_trigger(in /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; -static int __init assign_irq_vector(int irq) +#ifndef CONFIG_PCI_USE_VECTOR +int __init assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; BUG_ON(irq >= NR_IRQ_VECTORS); @@ -647,10 +663,34 @@ next: IO_APIC_VECTOR(irq) = current_vector; return current_vector; } +#endif extern void (*interrupt[NR_IRQS])(void); -static struct hw_interrupt_type ioapic_level_irq_type; -static struct hw_interrupt_type ioapic_edge_irq_type; +static struct hw_interrupt_type ioapic_level_type; +static struct hw_interrupt_type ioapic_edge_type; + +#define IOAPIC_AUTO -1 +#define IOAPIC_EDGE 0 +#define IOAPIC_LEVEL 1 + +static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger) +{ + if (use_pci_vector() && !platform_legacy_irq(irq)) { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) + irq_desc[vector].handler = &ioapic_level_type; + else + irq_desc[vector].handler = &ioapic_edge_type; + set_intr_gate(vector, interrupt[vector]); + } else { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) + irq_desc[irq].handler = &ioapic_level_type; + else + irq_desc[irq].handler = &ioapic_edge_type; + set_intr_gate(vector, interrupt[irq]); + } +} void __init setup_IO_APIC_irqs(void) { @@ -702,13 +742,7 @@ void __init setup_IO_APIC_irqs(void) vector = assign_irq_vector(irq); entry.vector = vector; - if (IO_APIC_irq_trigger(irq)) - irq_desc[irq].handler = &ioapic_level_irq_type; - else - irq_desc[irq].handler = &ioapic_edge_irq_type; - - set_intr_gate(vector, interrupt[irq]); - + ioapic_register_intr(irq, vector, IOAPIC_AUTO); if (!apic && (irq < 16)) disable_8259A_irq(irq); } @@ -755,7 +789,7 @@ void __init setup_ExtINT_IRQ0_pin(unsign * The timer IRQ doesn't have to know that behind the * scene we have a 8259A-master in AEOI mode ... */ - irq_desc[0].handler = &ioapic_edge_irq_type; + irq_desc[0].handler = &ioapic_edge_type; /* * Add it to the IO-APIC irq-routing table: @@ -1087,8 +1121,6 @@ static void __init setup_ioapic_ids_from unsigned char old_id; unsigned long flags; - if (acpi_ioapic) return; /* ACPI does that already */ - /* * Set the IOAPIC ID to the value stored in the MPC table. */ @@ -1210,9 +1242,6 @@ static int __init timer_irq_works(void) * that was delayed but this is now handled in the device * independent code. */ -#define enable_edge_ioapic_irq unmask_IO_APIC_irq - -static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } /* * Starting up a edge-triggered IO-APIC interrupt is @@ -1241,8 +1270,6 @@ static unsigned int startup_edge_ioapic_ return was_pending; } -#define shutdown_edge_ioapic_irq disable_edge_ioapic_irq - /* * Once we have recorded IRQ_PENDING already, we can mask the * interrupt for real. This prevents IRQ storms from unhandled @@ -1256,9 +1283,6 @@ static void ack_edge_ioapic_irq(unsigned ack_APIC_irq(); } -static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ } - - /* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt @@ -1280,10 +1304,6 @@ static unsigned int startup_level_ioapic return 0; /* don't check for pending */ } -#define shutdown_level_ioapic_irq mask_IO_APIC_irq -#define enable_level_ioapic_irq unmask_IO_APIC_irq -#define disable_level_ioapic_irq mask_IO_APIC_irq - static void end_level_ioapic_irq (unsigned int irq) { unsigned long v; @@ -1343,9 +1363,7 @@ static void end_level_ioapic_irq (unsign } } -static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } - -static void set_ioapic_affinity (unsigned int irq, cpumask_t mask) +static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) { unsigned long flags; unsigned int dest; @@ -1362,6 +1380,58 @@ static void set_ioapic_affinity (unsigne spin_unlock_irqrestore(&ioapic_lock, flags); } +#ifdef CONFIG_PCI_USE_VECTOR +static unsigned int startup_edge_ioapic_vector(unsigned int vector) +{ + int irq = vector_to_irq(vector); + + return startup_edge_ioapic_irq(irq); +} + +static void ack_edge_ioapic_vector(unsigned int vector) +{ + int irq = vector_to_irq(vector); + + ack_edge_ioapic_irq(irq); +} + +static unsigned int startup_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + return startup_level_ioapic_irq (irq); +} + +static void end_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + end_level_ioapic_irq(irq); +} + +static void mask_IO_APIC_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + mask_IO_APIC_irq(irq); +} + +static void unmask_IO_APIC_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + unmask_IO_APIC_irq(irq); +} + +static void set_ioapic_affinity_vector (unsigned int vector, + cpumask_t cpu_mask) +{ + int irq = vector_to_irq(vector); + + set_ioapic_affinity_irq(irq, cpu_mask); +} +#endif + /* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be @@ -1371,25 +1441,25 @@ static void set_ioapic_affinity (unsigne * races. */ -static struct hw_interrupt_type ioapic_edge_irq_type = { +static struct hw_interrupt_type ioapic_edge_type = { .typename = "IO-APIC-edge", - .startup = startup_edge_ioapic_irq, - .shutdown = shutdown_edge_ioapic_irq, - .enable = enable_edge_ioapic_irq, - .disable = disable_edge_ioapic_irq, - .ack = ack_edge_ioapic_irq, - .end = end_edge_ioapic_irq, + .startup = startup_edge_ioapic, + .shutdown = shutdown_edge_ioapic, + .enable = enable_edge_ioapic, + .disable = disable_edge_ioapic, + .ack = ack_edge_ioapic, + .end = end_edge_ioapic, .set_affinity = set_ioapic_affinity, }; -static struct hw_interrupt_type ioapic_level_irq_type = { +static struct hw_interrupt_type ioapic_level_type = { .typename = "IO-APIC-level", - .startup = startup_level_ioapic_irq, - .shutdown = shutdown_level_ioapic_irq, - .enable = enable_level_ioapic_irq, - .disable = disable_level_ioapic_irq, - .ack = mask_and_ack_level_ioapic_irq, - .end = end_level_ioapic_irq, + .startup = startup_level_ioapic, + .shutdown = shutdown_level_ioapic, + .enable = enable_level_ioapic, + .disable = disable_level_ioapic, + .ack = mask_and_ack_level_ioapic, + .end = end_level_ioapic, .set_affinity = set_ioapic_affinity, }; @@ -1409,7 +1479,13 @@ static inline void init_IO_APIC_traps(vo * 0x80, because int 0x80 is hm, kind of importantish. ;) */ for (irq = 0; irq < NR_IRQS ; irq++) { - if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) { + int tmp = irq; + if (use_pci_vector()) { + if (!platform_legacy_irq(tmp)) + if ((tmp = vector_to_irq(tmp)) == -1) + continue; + } + if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { /* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 @@ -1673,12 +1749,14 @@ void __init setup_IO_APIC(void) /* * Set up the IO-APIC IRQ routing table. */ - setup_ioapic_ids_from_mpc(); + if (!acpi_ioapic) + setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); - print_IO_APIC(); + if (!acpi_ioapic) + print_IO_APIC(); } /* Ensure the ACPI SCI interrupt level is active low, edge-triggered */ @@ -1837,10 +1915,12 @@ int io_apic_set_pci_routing (int ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); + if (use_pci_vector() && !platform_legacy_irq(irq)) + irq = IO_APIC_VECTOR(irq); if (edge_level) { - irq_desc[irq].handler = &ioapic_level_irq_type; + irq_desc[irq].handler = &ioapic_level_type; } else { - irq_desc[irq].handler = &ioapic_edge_irq_type; + irq_desc[irq].handler = &ioapic_edge_type; } set_intr_gate(entry.vector, interrupt[irq]); --- linux-2.6.1-rc1/arch/x86_64/kernel/irq.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/kernel/irq.c 2004-01-04 17:36:23.000000000 -0800 @@ -408,6 +408,20 @@ out: return 1; } +int can_request_irq(unsigned int irq, unsigned long irqflags) +{ + struct irqaction *action; + + if (irq >= NR_IRQS) + return 0; + action = irq_desc[irq].action; + if (action) { + if (irqflags & action->flags & SA_SHIRQ) + action = NULL; + } + return !action; +} + /** * request_irq - allocate an interrupt line * @irq: Interrupt line to allocate --- linux-2.6.1-rc1/arch/x86_64/kernel/Makefile 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/kernel/Makefile 2004-01-04 17:36:23.000000000 -0800 @@ -18,13 +18,16 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o obj-$(CONFIG_PM) += suspend.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o +obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o obj-$(CONFIG_MODULES) += module.o +obj-y += topology.o + bootflag-y += ../../i386/kernel/bootflag.o cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o +topology-y += ../../i386/mach-default/topology.o -obj-$(CONFIG_CPU_FREQ) += cpufreq/ --- linux-2.6.1-rc1/arch/x86_64/kernel/mpparse.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/kernel/mpparse.c 2004-01-04 22:15:28.000000000 -0800 @@ -881,7 +881,6 @@ void __init mp_parse_prt (void) { struct list_head *node = NULL; struct acpi_prt_entry *entry = NULL; - int vector = 0; int ioapic = -1; int ioapic_pin = 0; int irq = 0; @@ -933,23 +932,27 @@ void __init mp_parse_prt (void) if ((1<irq = irq; continue; } mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; - - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x" + } + printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d" " -> IRQ %d\n", entry->id.segment, entry->id.bus, entry->id.device, ('A' + entry->pin), - mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, + mp_ioapic_routing[ioapic].apic_id, ioapic_pin, entry->irq); } + print_IO_APIC(); + return; } --- linux-2.6.1-rc1/arch/x86_64/kernel/pci-gart.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/kernel/pci-gart.c 2004-01-04 17:36:23.000000000 -0800 @@ -52,6 +52,8 @@ int iommu_merge = 0; int iommu_sac_force = 0; int iommu_fullflush = 1; +#define MAX_NB 8 + /* Allocation bitmap for the remapping area */ static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED; static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */ @@ -71,8 +73,8 @@ static unsigned long *iommu_gart_bitmap; if (dev->bus->number == 0 && \ (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31)) -static struct pci_dev *northbridges[NR_CPUS + 1]; -static u32 northbridge_flush_word[NR_CPUS + 1]; +static struct pci_dev *northbridges[MAX_NB]; +static u32 northbridge_flush_word[MAX_NB]; #define EMERGENCY_PAGES 32 /* = 128KB */ @@ -107,6 +109,8 @@ static unsigned long alloc_iommu(int siz need_flush = 1; } } + if (iommu_fullflush) + need_flush = 1; spin_unlock_irqrestore(&iommu_bitmap_lock, flags); return offset; } @@ -135,9 +139,11 @@ static void flush_gart(struct pci_dev *d int i; spin_lock_irqsave(&iommu_bitmap_lock, flags); - if (need_flush || iommu_fullflush) { - for (i = 0; northbridges[i]; i++) { + if (need_flush) { + for (i = 0; i < MAX_NB; i++) { u32 w; + if (!northbridges[i]) + continue; if (bus >= 0 && !(cpu_isset_const(i, bus_cpumask))) continue; pci_write_config_dword(northbridges[i], 0x9c, @@ -767,10 +773,9 @@ static int __init pci_iommu_init(void) for_all_nb(dev) { u32 flag; int cpu = PCI_SLOT(dev->devfn) - 24; - if (cpu >= NR_CPUS) + if (cpu >= MAX_NB) continue; northbridges[cpu] = dev; - pci_read_config_dword(dev, 0x9c, &flag); /* cache flush word */ northbridge_flush_word[cpu] = flag; } @@ -783,7 +788,8 @@ static int __init pci_iommu_init(void) /* Must execute after PCI subsystem */ fs_initcall(pci_iommu_init); -/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]] +/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge] + [,forcesac][,fullflush][,nomerge] size set size of iommu (in bytes) noagp don't initialize the AGP driver and use full aperture. off don't use the IOMMU @@ -791,6 +797,10 @@ fs_initcall(pci_iommu_init); memaper[=order] allocate an own aperture over RAM with size 32MB^order. noforce don't force IOMMU usage. Default. force Force IOMMU. + merge Do SG merging. Implies force (experimental) + nomerge Don't do SG merging. + forcesac For SAC mode for masks <40bits (experimental) + fullflush Flush IOMMU on each allocation (for testing) */ __init int iommu_setup(char *opt) { @@ -804,8 +814,10 @@ __init int iommu_setup(char *opt) no_iommu = 1; if (!memcmp(p,"force", 5)) force_iommu = 1; - if (!memcmp(p,"noforce", 7)) + if (!memcmp(p,"noforce", 7)) { + iommu_merge = 0; force_iommu = 0; + } if (!memcmp(p, "memaper", 7)) { fallback_aper_force = 1; p += 7; @@ -816,6 +828,16 @@ __init int iommu_setup(char *opt) panic_on_overflow = 1; if (!memcmp(p, "nopanic", 7)) panic_on_overflow = 0; + if (!memcmp(p, "merge", 5)) { + iommu_merge = 1; + force_iommu = 1; + } + if (!memcmp(p, "nomerge", 7)) + iommu_merge = 0; + if (!memcmp(p, "forcesac", 8)) + iommu_sac_force = 1; + if (!memcmp(p, "fullflush", 9)) + iommu_fullflush = 1; #ifdef CONFIG_IOMMU_LEAK if (!memcmp(p,"leak", 4)) { leak_trace = 1; --- linux-2.6.1-rc1/arch/x86_64/kernel/process.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/x86_64/kernel/process.c 2004-01-04 17:36:23.000000000 -0800 @@ -152,6 +152,19 @@ static int __init idle_setup (char *str) __setup("idle=", idle_setup); +void idle_warning(void) +{ + static int warned; + if (warned) + return; + warned = 1; + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + BUG(); + printk(KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n"); + printk(KERN_ERR "******* Working around it, but it will cost you a lot of power\n"); + printk(KERN_ERR "******* Please consider a BIOS update.\n"); + printk(KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"); +} /* Prints also some state that isn't saved in the pt_regs */ void __show_regs(struct pt_regs * regs) --- linux-2.6.1-rc1/arch/x86_64/kernel/setup.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/arch/x86_64/kernel/setup.c 2004-01-04 22:15:28.000000000 -0800 @@ -65,7 +65,11 @@ unsigned long mmu_cr4_features; EXPORT_SYMBOL_GPL(mmu_cr4_features); int acpi_disabled = 0; -int acpi_ht = 0; + +#ifdef CONFIG_ACPI_BOOT +extern int __initdata acpi_ht; +/* int __initdata acpi_force = 0; */ +#endif /* For PCI or other memory-mapped resources */ unsigned long pci_mem_start = 0x10000000; @@ -195,6 +199,7 @@ static __init void parse_cmdline_early ( if (c != ' ') goto next_char; +#ifdef CONFIG_ACPI_BOOT /* "acpi=off" disables both ACPI table parsing and interpreter init */ if (!memcmp(from, "acpi=off", 8)) acpi_disabled = 1; @@ -210,6 +215,7 @@ static __init void parse_cmdline_early ( if (!memcmp(from, "acpi=ht", 7)) { acpi_ht = 1; } +#endif if (!memcmp(from, "nolapic", 7) || !memcmp(from, "disableapic", 11)) @@ -237,6 +243,9 @@ static __init void parse_cmdline_early ( } #endif + if (!memcmp(from,"oops=panic", 10)) + panic_on_oops = 1; + next_char: c = *(from++); if (!c) @@ -332,6 +341,7 @@ __setup("noreplacement", noreplacement_s void __init setup_arch(char **cmdline_p) { unsigned long low_mem_size; + unsigned long kernel_end; ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; @@ -380,7 +390,6 @@ void __init setup_arch(char **cmdline_p) (table_end - table_start) << PAGE_SHIFT); /* reserve kernel */ - unsigned long kernel_end; kernel_end = round_up(__pa_symbol(&_end),PAGE_SIZE); reserve_bootmem_generic(HIGH_MEMORY, kernel_end - HIGH_MEMORY); --- linux-2.6.1-rc1/arch/x86_64/kernel/time.c 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/x86_64/kernel/time.c 2004-01-04 17:36:23.000000000 -0800 @@ -111,13 +111,14 @@ void do_gettimeofday(struct timeval *tv) sec = xtime.tv_sec; usec = xtime.tv_nsec / 1000; - /* - * If time_adjust is negative then NTP is slowing the clock - * so make sure not to go into next possible interval. - * Better to lose some accuracy than have time go backwards.. - */ - if (unlikely(time_adjust < 0) && usec > tickadj) - usec = tickadj; + /* i386 does some correction here to keep the clock + monotonus even when ntpd is fixing drift. + But they didn't work for me, there is a non monotonic + clock anyways with ntp. + I dropped all corrections now until a real solution can + be found. Note when you fix it here you need to do the same + in arch/x86_64/kernel/vsyscall.c and export all needed + variables in vmlinux.lds. -AK */ t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset(); @@ -592,6 +593,7 @@ static int hpet_init(void) if (!vxtime.hpet_address) return -1; set_fixmap_nocache(FIX_HPET_BASE, vxtime.hpet_address); + __set_fixmap(VSYSCALL_HPET, vxtime.hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); /* * Read the period, compute tick and quotient. --- linux-2.6.1-rc1/arch/x86_64/kernel/traps.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/kernel/traps.c 2004-01-04 17:36:23.000000000 -0800 @@ -345,6 +345,8 @@ void oops_end(void) bust_spinlocks(0); spin_unlock(&die_lock); local_irq_enable(); /* make sure back scroll still works */ + if (panic_on_oops) + panic("Oops"); } void __die(const char * str, struct pt_regs * regs, long err) @@ -353,8 +355,8 @@ void __die(const char * str, struct pt_r printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff,++die_counter); notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); show_registers(regs); - /* Execute summary in case the oops scrolled away */ - printk(KERN_EMERG "RIP "); + /* Executive summary in case the oops scrolled away */ + printk("RIP "); printk_address(regs->rip); printk(" RSP <%016lx>\n", regs->rsp); } @@ -848,3 +850,11 @@ void __init trap_init(void) cpu_init(); } + +/* Actual parsing is done early in setup.c. */ +static int __init oops_dummy(char *s) +{ + panic_on_oops = 1; + return -1; +} +__setup("oops=", oops_dummy); --- linux-2.6.1-rc1/arch/x86_64/kernel/vsyscall.c 2003-09-08 13:58:56.000000000 -0700 +++ 25/arch/x86_64/kernel/vsyscall.c 2004-01-04 17:36:23.000000000 -0800 @@ -49,6 +49,7 @@ #include #include #include +#include #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) #define force_inline __attribute__((always_inline)) inline @@ -88,11 +89,10 @@ static force_inline void do_vgettimeofda if (t < __vxtime.last_tsc) t = __vxtime.last_tsc; usec += ((t - __vxtime.last_tsc) * __vxtime.tsc_quot) >> 32; + /* See comment in x86_64 do_gettimeopfday. */ } else { -#if 0 usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) - __vxtime.last) * __vxtime.quot) >> 32; -#endif } } while (read_seqretry(&__xtime_lock, sequence)); --- linux-2.6.1-rc1/arch/x86_64/lib/memset.S 2003-09-08 13:58:56.000000000 -0700 +++ 25/arch/x86_64/lib/memset.S 2004-01-04 17:36:36.000000000 -0800 @@ -113,7 +113,7 @@ memset_c: /* expand byte value */ movzbl %sil,%esi movabs $0x0101010101010101,%rax - mul %esi /* with rax, clobbers rdx */ + mulq %rsi /* with rax, clobbers rdx */ rep stosq movl %r8d,%ecx --- linux-2.6.1-rc1/arch/x86_64/mm/fault.c 2003-12-30 22:37:20.000000000 -0800 +++ 25/arch/x86_64/mm/fault.c 2004-01-04 17:36:23.000000000 -0800 @@ -378,7 +378,7 @@ no_context: printk_address(regs->rip); dump_pagetable(address); __die("Oops", regs, error_code); - /* Execute summary in case the body of the oops scrolled away */ + /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); oops_end(); do_exit(SIGKILL); --- linux-2.6.1-rc1/Documentation/Changes 2003-10-08 15:07:08.000000000 -0700 +++ 25/Documentation/Changes 2004-01-04 22:15:51.000000000 -0800 @@ -56,7 +56,7 @@ o module-init-tools 0.9.10 o e2fsprogs 1.29 # tune2fs o jfsutils 1.1.3 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs -o xfsprogs 2.1.0 # xfs_db -V +o xfsprogs 2.6.0 # xfs_db -V o pcmcia-cs 3.1.21 # cardmgr -V o quota-tools 3.09 # quota -V o PPP 2.4.0 # pppd --version @@ -183,9 +183,8 @@ Xfsprogs The latest version of xfsprogs contains mkfs.xfs, xfs_db, and the xfs_repair utilities, among others, for the XFS filesystem. It is architecture independent and any version from 2.0.0 onward should -work correctly with this version of the XFS kernel code. For the new -(v2) log format that has better support for stripe-size aligning on -LVM and MD devices at least xfsprogs 2.1.0 is needed. +work correctly with this version of the XFS kernel code (2.6.0 or +later is recommended, due to some significant improvements). Pcmcia-cs @@ -359,7 +358,7 @@ o +o Pcmcia-cs --------- --- linux-2.6.1-rc1/Documentation/DocBook/kernel-locking.tmpl 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/DocBook/kernel-locking.tmpl 2004-01-04 22:16:09.000000000 -0800 @@ -66,6 +66,7 @@ fundamentals of concurrency and locking for SMP. + The Problem With Concurrency @@ -193,6 +194,7 @@ And then there are the unfriendly primitives, but I'll pretend they don't exist. + @@ -657,6 +659,7 @@ + @@ -1110,6 +1113,7 @@ used to protect the reference count itse return obj; } + @@ -1229,6 +1233,7 @@ which locks. This is extremely importan behavior of the code, and can be hard to gain from just reading. And as Alan Cox says, Lock data, not code. + @@ -1317,6 +1322,7 @@ as Alan Cox says, Lock data, not The two CPUs will spin forever, waiting for the other to give up their lock. It will look, smell, and feel like a crash. + Preventing Deadlock @@ -1886,6 +1892,7 @@ machines due to caching. + Some Functions Which Don't Sleep --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/dvb/bt8xx.txt 2004-01-04 17:36:23.000000000 -0800 @@ -0,0 +1,90 @@ +How to get the Nebula, PCTV and Twinhan DST cards working +========================================================= + +This class of cards has a bt878a as the PCI interface, and +require the bttv driver. + +Please pay close attention to the warning about the bttv module +options below for the DST card. + +1) General informations +======================= + +These drivers require the bttv driver to provide the means to access +the i2c bus and the gpio pins of the bt8xx chipset. + +Because of this, you need to enable +"Device drivers" => "Multimedia devices" + => "Video For Linux" => "BT848 Video For Linux" + +2) Loading Modules +================== + +In general you need to load the bttv driver, which will handle the gpio and +i2c communication for us. Next you need the common dvb-bt8xx device driver +and one frontend driver. + +The bttv driver will HANG YOUR SYSTEM IF YOU DO NOT SPECIFY THE CORRECT +CARD ID! + +(If you don't get your card running and you suspect that the card id you're +using is wrong, have a look at "bttv-cards.c" for a list of possible card +ids.) + +Pay attention to failures when you load the frontend drivers +(e.g. dmesg, /var/log/messages). + +3a) Nebula / Pinnacle PCTV +-------------------------- + + $ modprobe bttv i2c_hw=1 card=0x68 + $ modprobe dvb-bt8xx + +For Nebula cards use the "nxt6000" frontend driver: + $ modprobe nxt6000 + +For Pinnacle PCTV cards use the "cx24110" frontend driver: + $ modprobe cx24110 + +3b) TwinHan +----------- + + $ modprobe bttv i2c_hw=1 card=0x71 + $ modprobe dvb-bt8xx + $ modprobe dst + +The value 0x71 will override the PCI type detection for dvb-bt8xx, which +is necessary for TwinHan cards.# + +If you're having an older card (blue color circuit) and card=0x71 locks your +machine, try using 0x68, too. If that does not work, ask on the DVB mailing list. + +The DST module takes a couple of useful parameters, in case the +dst drivers fails to detect your type of card correctly. + +dst_type takes values 0 (satellite), 1 (terrestial TV), 2 (cable). + +dst_type_flags takes bit combined values: +1 = new tuner type packets. You can use this if your card is detected + and you have debug and you continually see the tuner packets not + working (make sure not a basic problem like dish alignment etc.) + +2 = TS 204. If your card tunes OK, but the picture is terrible, seemingly + breaking up in one half continually, and crc fails a lot, then + this is worth a try (or trying to turn off) + +4 = has symdiv. Some cards, mostly without new tuner packets, require + a symbol division algorithm. Doesn't apply to terrestial TV. + +You can also specify a value to have the autodetected values turned off +(e.g. 0). The autodected values are determined bythe cards 'response +string' which you can see in your logs e.g. + +dst_check_ci: recognize DST-MOT + +or + +dst_check_ci: unable to recognize DSTXCI or STXCI + +-- +Authors: Richard Walker, Jamie Honan, Michael Hunold --- linux-2.6.1-rc1/Documentation/dvb/contributors.txt 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/dvb/contributors.txt 2004-01-04 17:36:23.000000000 -0800 @@ -30,11 +30,15 @@ Steve Brown Christoph Martin for his LIRC infrared handler -Andreas Oberritter +Andreas Oberritter +Dennis Noermann +Felix Domke Florian Schirmer -...and all the other dBox2 people - for many bugfixes in the generic DVB Core and their work on the - dBox2 port of the DVB driver +Ronny Strutz <3des@elitedvb.de> +Wolfram Joost +...and all the other dbox2 people + for many bugfixes in the generic DVB Core, frontend drivers and + their work on the dbox2 port of the DVB driver Oliver Endriss for many bugfixes @@ -50,5 +54,9 @@ Roberto Ragusa Augusto Cardoso for all the work for the FlexCopII chipset by B2C2,Inc. +Davor Emard + for his work on the budget drivers, the demux code, + the module unloading problems, ... + (If you think you should be in this list, but you are not, drop a line to the DVB mailing list) --- linux-2.6.1-rc1/Documentation/dvb/readme.txt 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/dvb/readme.txt 2004-01-04 17:36:23.000000000 -0800 @@ -36,4 +36,9 @@ files and where to get them. contains detailed informations about the TT DEC2000/DEC3000 USB DVB hardware. +"bt8xx.txt" +contains detailed installation instructions for the +various bt8xx based "budget" DVB cards +(Nebula, Pinnacle PCTV, Twinhan DST) + Good luck and have fun! --- linux-2.6.1-rc1/Documentation/dvb/ttusb-dec.txt 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/dvb/ttusb-dec.txt 2004-01-04 17:36:23.000000000 -0800 @@ -9,6 +9,7 @@ Supported: Linux Kernels 2.4 and 2.6 Video Streaming Audio Streaming + Section Filters Channel Zapping Hotplug firmware loader under 2.6 kernels @@ -16,14 +17,10 @@ In Progress: DEC3000-s To Do: - Section data - Teletext streams Tuner status information DVB network interface Streaming video PC->DEC -Note: Since section data can not be retreived yet, scan apps will not work. - Getting the Firmware -------------------- Currently, the driver only works with v2.15a of the firmware. The firmwares @@ -46,7 +43,7 @@ mv STB_PC_S.bin /etc/dvb/dec3000s.bin Hotplug Firmware Loading for 2.6 kernels ---------------------------------------- For 2.6 kernels the firmware is loaded at the point that the driver module is -loaded. See linux/Documentation/dvb/FIRMWARE for more information. +loaded. See linux/Documentation/dvb/firmware.txt for more information. -mv STB_PC_T.bin /usr/lib/hotplug/firmware/dec2000t.bin -mv STB_PC_S.bin /usr/lib/hotplug/firmware/dec3000s.bin +mv STB_PC_T.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2000t-2.15a.fw +mv STB_PC_S.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-3000s-2.15a.fw --- linux-2.6.1-rc1/Documentation/filesystems/proc.txt 2003-11-09 16:45:05.000000000 -0800 +++ 25/Documentation/filesystems/proc.txt 2004-01-04 22:22:01.000000000 -0800 @@ -900,6 +900,15 @@ super-nr shows the number of currently a Every mounted file system needs a super block, so if you plan to mount lots of file systems, you may want to increase these numbers. +aio-nr and aio-max-nr +--------------------- + +aio-nr is the running total of the number of events specified on the +io_setup system call for all currently active aio contexts. If aio-nr +reaches aio-max-nr then io_setup will fail with EAGAIN. Note that +raising aio-max-nr does not result in the pre-allocation or re-sizing +of any kernel data structures. + 2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats ----------------------------------------------------------- --- linux-2.6.1-rc1/Documentation/filesystems/xfs.txt 2003-10-17 15:58:03.000000000 -0700 +++ 25/Documentation/filesystems/xfs.txt 2004-01-04 22:15:51.000000000 -0800 @@ -29,10 +29,11 @@ When mounting an XFS filesystem, the fol The preferred buffered I/O size can also be altered on an individual file basis using the ioctl(2) system call. - ikeep + ikeep/noikeep When inode clusters are emptied of inodes, keep them around - on the disk, this is the old XFS behavior. Default is now to - return the inode cluster to the free space pool. + on the disk (ikeep) - this is the traditional XFS behaviour + and is still the default for now. Using the noikeep option, + inode clusters are returned to the free space pool. logbufs=value Set the number of in-memory log buffers. Valid numbers range @@ -75,6 +76,10 @@ When mounting an XFS filesystem, the fol Filesystems mounted "norecovery" must be mounted read-only or the mount will fail. + nouuid + Don't check for double mounted file systems using the file system uuid. + This is useful to mount LVM snapshot volumes. + osyncisosync Make O_SYNC writes implement true O_SYNC. WITHOUT this option, Linux XFS behaves as if an "osyncisdsync" option is used, @@ -108,10 +113,6 @@ When mounting an XFS filesystem, the fol The "swidth" option is required if the "sunit" option has been specified, and must be a multiple of the "sunit" value. - nouuid - Don't check for double mounted file systems using the file system uuid. - This is useful to mount LVM snapshot volumes. - sysctls ======= @@ -139,14 +140,14 @@ The following sysctls are available for Causes certain error conditions to call BUG(). Value is a bitmask; AND together the tags which represent errors which should cause panics: - XFS_NO_PTAG 0LL - XFS_PTAG_IFLUSH 0x0000000000000001LL - XFS_PTAG_LOGRES 0x0000000000000002LL - XFS_PTAG_AILDELETE 0x0000000000000004LL - XFS_PTAG_ERROR_REPORT 0x0000000000000008LL - XFS_PTAG_SHUTDOWN_CORRUPT 0x0000000000000010LL - XFS_PTAG_SHUTDOWN_IOERROR 0x0000000000000020LL - XFS_PTAG_SHUTDOWN_LOGERROR 0x0000000000000040LL + XFS_NO_PTAG 0 + XFS_PTAG_IFLUSH 0x00000001 + XFS_PTAG_LOGRES 0x00000002 + XFS_PTAG_AILDELETE 0x00000004 + XFS_PTAG_ERROR_REPORT 0x00000008 + XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010 + XFS_PTAG_SHUTDOWN_IOERROR 0x00000020 + XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040 This option is intended for debugging only. @@ -165,6 +166,21 @@ The following sysctls are available for Controls whether unprivileged users can use chown to "give away" a file to another user. + fs.xfs.inherit_sync (Min: 0 Default: 1 Max 1) + Setting this to "1" will cause the "sync" flag set + by the chattr(1) command on a directory to be + inherited by files in that directory. + + fs.xfs.inherit_nodump (Min: 0 Default: 1 Max 1) + Setting this to "1" will cause the "nodump" flag set + by the chattr(1) command on a directory to be + inherited by files in that directory. + + fs.xfs.inherit_noatime (Min: 0 Default: 1 Max 1) + Setting this to "1" will cause the "noatime" flag set + by the chattr(1) command on a directory to be + inherited by files in that directory. + vm.pagebuf.stats_clear (Min: 0 Default: 0 Max: 1) Setting this to "1" clears accumulated pagebuf statistics in /proc/fs/pagebuf/stat. It then immediately reset to "0". --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/andthen 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,100 @@ + +define set_andthen + set var $thp=0 + set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0] + set var $at_size = (sizeof kgdb_data)/(sizeof *$thp) + set var $at_oc=kgdb_and_then_count + set var $at_cc=$at_oc +end + +define andthen_next + set var $at_cc=$arg0 +end + +define andthen + andthen_set_edge + if ($at_cc >= $at_oc) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc + output *($thp+($at_cc++ % $at_size )) + printf "\n" + end +end +define andthen_set_edge + set var $at_oc=kgdb_and_then_count + set var $at_low = $at_oc - $at_size + if ($at_low < 0 ) + set var $at_low = 0 + end + if (( $at_cc > $at_oc) || ($at_cc < $at_low)) + printf "Count outside of window, setting count to " + if ($at_cc >= $at_oc) + set var $at_cc = $at_oc + else + set var $at_cc = $at_low + end + printf "%d\n",$at_cc + end +end + +define beforethat + andthen_set_edge + if ($at_cc <= $at_low) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc-1 + output *($thp+(--$at_cc % $at_size )) + printf "\n" + end +end + +document andthen_next + andthen_next + . sets the number of the event to display next. If this event + . is not in the event pool, either andthen or beforethat will + . correct it to the nearest event pool edge. The event pool + . ends at the last event recorded and begins + . prior to that. If beforethat is used next, it will display + . event -1. +. + andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + + +document andthen + andthen +. displays the next event in the list. sets up to display +. the oldest saved event first. +. (optional) count of the event to display. +. note the number of events saved is specified at configure time. +. if events are saved between calls to andthen the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document set_andthen + set_andthen +. sets up to use the and commands. +. if you have defined your own struct, use the above and +. then enter the following: +. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0] +. where is the name of your structure. +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document beforethat + beforethat +. displays the next prior event in the list. sets up to +. display the last occuring event first. +. +. note the number of events saved is specified at configure time. +. if events are saved between calls to beforethat the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/debug-nmi.txt 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,37 @@ +Subject: Debugging with NMI +Date: Mon, 12 Jul 1999 11:28:31 -0500 +From: David Grothe +Organization: Gcom, Inc +To: David Grothe + +Kernel hackers: + +Maybe this is old hat, but it is new to me -- + +On an ISA bus machine, if you short out the A1 and B1 pins of an ISA +slot you will generate an NMI to the CPU. This interrupts even a +machine that is hung in a loop with interrupts disabled. Used in +conjunction with kgdb < +ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can +gain debugger control of a machine that is hung in the kernel! Even +without kgdb the kernel will print a stack trace so you can find out +where it was hung. + +The A1/B1 pins are directly opposite one another and the farthest pins +towards the bracket end of the ISA bus socket. You can stick a paper +clip or multi-meter probe between them to short them out. + +I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the +board consists of two rows of wire wrap pins. So I wired a push button +between the A1/B1 pins and now have an ISA board that I can stick into +any ISA bus slot for debugger entry. + +Microsoft has a circuit diagram of a PCI card at +http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to +build one you will have to mail them and ask for the PAL equations. +Nobody makes one comercially. + +[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if +your machine catches fire, it is your problem, not mine.] + +-- Dave (the kgdb guy) --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdb-globals.txt 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,71 @@ +Sender: akale@veritas.com +Date: Fri, 23 Jun 2000 19:26:35 +0530 +From: "Amit S. Kale" +Organization: Veritas Software (India) +To: Dave Grothe , linux-kernel@vger.rutgers.edu +CC: David Milburn , + "Edouard G. Parmelan" , + ezannoni@cygnus.com, Keith Owens +Subject: Re: Module debugging using kgdb + +Dave Grothe wrote: +> +> Amit: +> +> There is a 2.4.0 version of kgdb on our ftp site: +> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb +> and loadmodule.sh there. +> +> Have a look at the README file and see if I go it right. If not, send +> me some corrections and I will update it. +> +> Does your version of gdb solve the global variable problem? + +Yes. +Thanks to Elena Zanoni, gdb (developement version) can now calculate +correctly addresses of dynamically loaded object files. I have not been +following gdb developement for sometime and am not sure when symbol +address calculation fix is going to appear in a gdb stable version. + +Elena, any idea when the fix will make it to a prebuilt gdb from a +redhat release? + +For the time being I have built a gdb developement version. It can be +used for module debugging with loadmodule.sh script. + +The problem with calculating of module addresses with previous versions +of gdb was as follows: +gdb did not use base address of a section while calculating address of +a symbol in the section in an object file loaded via 'add-symbol-file'. +It used address of .text segment instead. Due to this addresses of +symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly. + +Above mentioned fix allow gdb to use base address of a segment while +calculating address of a symbol in it. It adds a parameter '-s' to +'add-symbol-file' command for specifying base address of a segment. + +loadmodule.sh script works as follows. + +1. Copy a module file to target machine. +2. Load the module on the target machine using insmod with -m parameter. +insmod produces a module load map which contains base addresses of all +sections in the module and addresses of symbols in the module file. +3. Find all sections and their base addresses in the module from +the module map. +4. Generate a script that loads the module file. The script uses +'add-symbol-file' and specifies address of text segment followed by +addresses of all segments in the module. + +Here is an example gdb script produced by loadmodule.sh script. + +add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5 +-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38 +-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838 + +With this command gdb can calculate addresses of symbols in ANY segment +in a module file. + +Regards. +-- +Amit Kale +Veritas Software ( http://www.veritas.com ) --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,14 @@ +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 +target remote /dev/ttyS0 +define si +stepi +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip +end +define ni +nexti +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit.hw 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,117 @@ + +#Using ia-32 hardware breakpoints. +# +#4 hardware breakpoints are available in ia-32 processors. These breakpoints +#do not need code modification. They are set using debug registers. +# +#Each hardware breakpoint can be of one of the +#three types: execution, write, access. +#1. An Execution breakpoint is triggered when code at the breakpoint address is +#executed. +#2. A write breakpoint ( aka watchpoints ) is triggered when memory location +#at the breakpoint address is written. +#3. An access breakpoint is triggered when memory location at the breakpoint +#address is either read or written. +# +#As hardware breakpoints are available in limited number, use software +#breakpoints ( br command in gdb ) instead of execution hardware breakpoints. +# +#Length of an access or a write breakpoint defines length of the datatype to +#be watched. Length is 1 for char, 2 short , 3 int. +# +#For placing execution, write and access breakpoints, use commands +#hwebrk, hwwbrk, hwabrk +#To remove a breakpoint use hwrmbrk command. +# +#These commands take following types of arguments. For arguments associated +#with each command, use help command. +#1. breakpointno: 0 to 3 +#2. length: 1 to 3 +#3. address: Memory location in hex ( without 0x ) e.g c015e9bc +# +#Use the command exinfo to find which hardware breakpoint occured. + +#hwebrk breakpointno address +define hwebrk + maintenance packet Y$arg0,0,0,$arg1 +end +document hwebrk + hwebrk
+ Places a hardware execution breakpoint + = 0 - 3 +
= Hex digits without leading "0x". +end + +#hwwbrk breakpointno length address +define hwwbrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwwbrk + hwwbrk
+ Places a hardware write breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwabrk breakpointno length address +define hwabrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwabrk + hwabrk
+ Places a hardware access breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwrmbrk breakpointno +define hwrmbrk + maintenance packet y$arg0 +end +document hwrmbrk + hwrmbrk + = 0 - 3 + Removes a hardware breakpoint +end + +define reboot + maintenance packet r +end +#exinfo +define exinfo + maintenance packet qE +end +document exinfo + exinfo + Gives information about a breakpoint. +end +define get_th + p $th=(struct thread_info *)((int)$esp & ~8191) +end +document get_th + get_tu + Gets and prints the current thread_info pointer, Defines th to be it. +end +define get_cu + p $cu=((struct thread_info *)((int)$esp & ~8191))->task +end +document get_cu + get_cu + Gets and print the "current" value. Defines $cu to be it. +end +define int_off + set var $flags=$eflags + set $eflags=$eflags&~0x200 + end +define int_on + set var $eflags|=$flags&0x200 + end +document int_off + saves the current interrupt state and clears the processor interrupt + flag. Use int_on to restore the saved flag. +end +document int_on + Restores the interrupt flag saved by int_off. +end --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit-modules 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,146 @@ +# +# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub. +# +# This don't work for Linux-2.0 or older. +# +# Author Edouard G. Parmelan +# +# +# Fri Apr 30 20:33:29 CEST 1999 +# First public release. +# +# Major cleanup after experiment Linux-2.0 kernel without success. +# Symbols of a module are not in the correct order, I can't explain +# why :( +# +# Fri Mar 19 15:41:40 CET 1999 +# Initial version. +# +# Thu Jan 6 16:29:03 CST 2000 +# A little fixing by Dave Grothe +# +# Mon Jun 19 09:33:13 CDT 2000 +# Alignment changes from Edouard Parmelan +# +# The basic idea is to find where insmod load the module and inform +# GDB to load the symbol table of the module with the GDB command +# ``add-symbol-file
''. +# +# The Linux kernel holds the list of all loaded modules in module_list, +# this list end with &kernel_module (exactly with module->next == NULL, +# but the last module is not a real module). +# +# Insmod allocates the struct module before the object file. Since +# Linux-2.1, this structure contain his size. The real address of +# the object file is then (char*)module + module->size_of_struct. +# +# You can use three user functions ``mod-list'', ``mod-print-symbols'' +# and ``add-module-symbols''. +# +# mod-list list all loaded modules with the format: +# +# +# As soon as you have found the address of your module, you can +# print its exported symbols (mod-print-symbols) or inform GDB to add +# symbols from your module file (mod-add-symbols). +# +# The argument that you give to mod-print-symbols or mod-add-symbols +# is the from the mod-list command. +# +# When using the mod-add-symbols command you must also give the full +# pathname of the modules object code file. +# +# The command mod-add-lis is an example of how to make this easier. +# You can edit this macro to contain the path name of your own +# favorite module and then use it as a shorthand to load it. You +# still need the module-address, however. +# +# The internal function ``mod-validate'' set the GDB variable $mod +# as a ``struct module*'' if the kernel known the module otherwise +# $mod is set to NULL. This ensure to not add symbols for a wrong +# address. +# +# Have a nice hacking day ! +# +# +define mod-list + set $mod = (struct module*)module_list + # the last module is the kernel, ignore it + while $mod != &kernel_module + printf "%p\t%s\n", (long)$mod, ($mod)->name + set $mod = $mod->next + end +end +document mod-list +List all modules in the form: +Use the as the argument for the other +mod-commands: mod-print-symbols, mod-add-symbols. +end + +define mod-validate + set $mod = (struct module*)module_list + while ($mod != $arg0) && ($mod != &kernel_module) + set $mod = $mod->next + end + if $mod == &kernel_module + set $mod = 0 + printf "%p is not a module\n", $arg0 + end +end +document mod-validate +mod-validate +Internal user-command used to validate the module parameter. +If is a real loaded module, set $mod to it otherwise set $mod to 0. +end + + +define mod-print-symbols + mod-validate $arg0 + if $mod != 0 + set $i = 0 + while $i < $mod->nsyms + set $sym = $mod->syms[$i] + printf "%p\t%s\n", $sym->value, $sym->name + set $i = $i + 1 + end + end +end +document mod-print-symbols +mod-print-symbols +Print all exported symbols of the module. see mod-list +end + + +define mod-add-symbols-align + mod-validate $arg0 + if $mod != 0 + set $mod_base = ($mod->size_of_struct + (long)$mod) + if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0) + set $mod_base = ($mod_base | ($arg2 - 1)) + 1 + end + add-symbol-file $arg1 $mod_base + end +end +document mod-add-symbols-align +mod-add-symbols-align +Load the symbols table of the module from the object file where +first section aligment is . +To retreive alignment, use `objdump -h '. +end + +define mod-add-symbols + mod-add-symbols-align $arg0 $arg1 sizeof(long) +end +document mod-add-symbols +mod-add-symbols +Load the symbols table of the module from the object file. +Default alignment is 4. See mod-add-symbols-align. +end + +define mod-add-lis + mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16 +end +document mod-add-lis +mod-add-lis +Does mod-add-symbols /usr/src/LiS/streams.o +end --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/kgdbeth.txt 2004-01-04 17:36:35.000000000 -0800 @@ -0,0 +1,92 @@ +KGDB over ethernet +================== + +Authors +------- + +Robert Walsh (2.6 port) +wangdi (2.6 port) +Matt Mackall (netpoll api) +San Mehat (original 2.4 code) + + +Introduction +------------ + +KGDB supports debugging over ethernet (kgdboe) via polling of a given +network interface. Most cards should be supported automatically. +Debugging facilities are available as soon as the network driver and +kgdboe have initialized. Unfortunately, this is too late in the boot +process for debugging some issues, but works quite well for many +others. This should not interfere with normal network usage and +doesn't require a dedicated NIC. + +Terminology +----------- + +This document uses the following terms: + + TARGET: the machine being debugged. + HOST: the machine running gdb. + + +Usage +----- + +You need to use the following command-line option on the TARGET kernel: + + kgdboe=[tgt-port]@/[dev],[host-port]@/[host-macaddr] + + where + tgt-port source for UDP packets (defaults to 6443) + tgt-ip source IP to use (interface address) + dev network interface (eth0) + host-port HOST UDP port (6442) (not really used) + host-ip IP address for HOST machine + host-macaddr ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff) + + examples: + + kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D + this machine is 192.168.0.1 on eth1 + remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D + listen for gdb packets on port 7000 + send unsolicited gdb packets to port 7001 + + kgdboe=@192.168.0.1/,@192.168.0.2/ + this machine is 192.168.0.1 on default interface eth0 + remote machine is 192.168.0.2, use default broadcast MAC address + listen for gdb packets on default port 6443 + send unsolicited gdb packets to port 6442 + +Only packets originating from the configured HOST IP address will be +accepted by the debugger. + +On the HOST side, run gdb as normal and use a remote UDP host as the +target: + + % gdb ./vmlinux + GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) + Copyright 2003 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux-gnu"... + (gdb) target remote udp:HOSTNAME:6443 + +You can now continue as if you were debugging over a serial line. + +Limitations +----------- + +The current release of this code is exclusive of using kgdb on a +serial interface, so you must boot without the kgdboe option to use +serial debugging. Trying to debug the network driver while using it +will prove interesting. + +Bug reports +----------- + +Send bug reports to Robert Walsh and Matt +Mackall . --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/kgdb.txt 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,775 @@ +Last edit: <20030806.1637.12> +This file has information specific to the i386 kgdb option. Other +platforms with the kgdb option may behave in a similar fashion. + +New features: +============ +20030806.1557.37 +This version was made against the 2.6.0-test2 kernel. We have made the +following changes: + +- The getthread() code in the stub calls find_task_by_pid(). It fails + if we are early in the bring up such that the pid arrays have yet to + be allocated. We have added a line to kernel/pid.c to make + "kgdb_pid_init_done" true once the arrays are allocated. This way the + getthread() code knows not to call. This is only used by the thread + debugging stuff and threads will not yet exist at this point in the + boot. + +- For some reason, gdb was not asking for a new thread list when the + "info thread" command was given. We changed to the newer version of + the thread info command and gdb now seems to ask when needed. Result, + we now get all threads in the thread list. + +- We now respond to the ThreadExtraInfo request from gdb with the thread + name from task_struct .comm. This then appears in the thread list. + Thoughts on additional options for this are welcome. Things such as + "has BKL" and "Preempted" come to mind. I think we could have a flag + word that could enable different bits of info here. + +- We now honor, sort of, the C and S commands. These are continue and + single set after delivering a signal. We ignore the signal and do the + requested action. This only happens when we told gdb that a signal + was the reason for entry, which is only done on memory faults. The + result is that you can now continue into the Oops. + +- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb, + but it is more exact on what language to use. + +- We added two dwarf2 include files and a bit of code at the end of + entry.S. This does not yet work, so it is disabled. Still we want to + keep track of the code and "maybe" someone out there can fix it. + +- Randy Dunlap sent some fix ups for this file which are now merged. + +- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a + compiler warning if CONFIG_KGDB is off (now who would do that :). + +- Andrew Morton sent a fix for the serial driver which is now merged. + +- Andrew also sent a change to the stub around the cpu managment code + which is also merged. + +- Andrew also sent a patch to make "f" as well as "g" work as SysRq + commands to enter kgdb, merged. + +- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a + "who" field to the spinlock data struct. This is filled with + "current" when ever the spinlock suceeds. Useful if you want to know + who has the lock. + +_ And last, but not least, we fixed the "get_cu" macro to properly get + the current value of "current". + +New features: +============ +20030505.1827.27 +We are starting to align with the sourceforge version, at least in +commands. To this end, the boot command string to start kgdb at +boot time has been changed from "kgdb" to "gdb". + +Andrew Morton sent a couple of patches which are now included as follows: +1.) We now return a flag to the interrupt handler. +2.) We no longer use smp_num_cpus (a conflict with the lock meter). +3.) And from William Lee Irwin III code to make + sure high-mem is set up before we attempt to register our interrupt + handler. +We now include asm/kgdb.h from config.h so you will most likely never +have to include it. It also 'NULLS' the kgdb macros you might have in +your code when CONFIG_KGDB is not defined. This allows you to just +turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such. +This include is conditioned on the machine being an x86 so as to not +mess with other archs. + +20020801.1129.03 +This is currently the version for the 2.4.18 (and beyond?) kernel. + +We have several new "features" beginning with this version: + +1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more + waiting and it will pull that guy out of an IRQ off spin lock :) + +2.) We doctored up the code that tells where a task is waiting and + included it so that the "info thread" command will show a bit more + than "schedule()". Try it... + +3.) Added the ability to call a function from gdb. All the standard gdb + issues apply, i.e. if you hit a breakpoint in the function, you are + not allowed to call another (gdb limitation, not kgdb). To help + this capability we added a memory allocation function. Gdb does not + return this memory (it is used for strings that you pass to that function + you are calling from gdb) so we fixed up a way to allow you to + manually return the memory (see below). + +4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the + interrupt flag to now also include the preemption count and the + "in_interrupt" info. The flag is now called "with_pif" to indicate + the order, preempt_count, in_interrupt, flag. The preempt_count is + shifted left by 4 bits so you can read the count in hex by dropping + the low order digit. In_interrupt is in bit 1, and the flag is in + bit 0. + +5.) The command: "p kgdb_info" is now expanded and prints something + like: +(gdb) p kgdb_info +$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259, + errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1, + cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0, + regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}} + + Things to note here: a.) used_malloc is the amount of memory that + has been malloc'ed to do calls from gdb. You can reclaim this + memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.) + cpus_waiting is now "sized" by the number of CPUs you enter at + configure time in the kgdb configure section. This is NOT used + anywhere else in the system, but it is "nice" here. c.) The task's + "pid" is now in the structure. This is the pid you will need to use + to decode to the thread id to get gdb to look at that thread. + Remember that the "info thread" command prints a list of threads + wherein it numbers each thread with its reference number followed + by the thread's pid. Note that the per-CPU idle threads actually + have pids of 0 (yes, there is more than one pid 0 in an SMP system). + To avoid confusion, kgdb numbers these threads with numbers beyond + the MAX_PID. That is why you see 32768 and above. + +6.) A subtle change, we now provide the complete register set for tasks + that are active on the other CPUs. This allows better trace back on + those tasks. + + And, let's mention what we could not fix. Back-trace from all but the + thread that we trapped will, most likely, have a bogus entry in it. + The problem is that gdb does not recognize the entry code for + functions that use "current" near (at all?) the entry. The compiler + is putting the "current" decode as the first two instructions of the + function where gdb expects to find %ebp changing code. Back trace + also has trouble with interrupt frames. I am talking with Daniel + Jacobowitz about some way to fix this, but don't hold your breath. + +20011220.0050.35 +Major enhancement with this version is the ability to hold one or more +CPUs in an SMP system while allowing the others to continue. Also, by +default only the current CPU is enabled on single-step commands (please +note that gdb issues single-step commands at times other than when you +use the si command). + +Another change is to collect some useful information in +a global structure called "kgdb_info". You should be able to just: + +p kgdb_info + +although I have seen cases where the first time this is done gdb just +prints the first member but prints the whole structure if you then enter +CR (carriage return or enter). This also works: + +p *&kgdb_info + +Here is a sample: +(gdb) p kgdb_info +$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0, + vector = 3, print_debug_info = 0} + +"Called_from" is the return address from the current entry into kgdb. +Sometimes it is useful to know why you are in kgdb, for example, was +it an NMI or a real breakpoint? The simple way to interrogate this +return address is: + +l *0xc010732c + +which will print the surrounding few lines of source code. + +"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the +kgdb_ts entries). + +"errcode" and "vector" are other entry parameters which may be helpful on +some traps. + +"print_debug_info" is the internal debugging kgdb print enable flag. Yes, +you can modify it. + +In SMP systems kgdb_info also includes the "cpus_waiting" structure and +"hold_on_step": + +(gdb) p kgdb_info +$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0, + vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{ + task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0, + regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}}} + +"Cpus_waiting" has an entry for each CPU other than the current one that +has been stopped. Each entry contains the task_struct address for that +CPU, the address of the regs for that task and a hold flag. All these +have the proper typing so that, for example: + +p *kgdb_info.cpus_waiting[1].regs + +will print the registers for CPU 1. + +"Hold_on_sstep" is a new feature with this version and comes up set or +true. What this means is that whenever kgdb is asked to single-step all +other CPUs are held (i.e. not allowed to execute). The flag applies to +all but the current CPU and, again, can be changed: + +p kgdb_info.hold_on_sstep=0 + +restores the old behavior of letting all CPUs run during single-stepping. + +Likewise, each CPU has a "hold" flag, which if set, locks that CPU out +of execution. Note that this has some risk in cases where the CPUs need +to communicate with each other. If kgdb finds no CPU available on exit, +it will push a message thru gdb and stay in kgdb. Note that it is legal +to hold the current CPU as long as at least one CPU can execute. + +20010621.1117.09 +This version implements an event queue. Events are signaled by calling +a function in the kgdb stub and may be examined from gdb. See EVENTS +below for details. This version also tightens up the interrupt and SMP +handling to not allow interrupts on the way to kgdb from a breakpoint +trap. It is fine to allow these interrupts for user code, but not +system debugging. + +Version +======= + +This version of the kgdb package was developed and tested on +kernel version 2.4.16. It will not install on any earlier kernels. +It is possible that it will continue to work on later versions +of 2.4 and then versions of 2.5 (I hope). + + +Debugging Setup +=============== + +Designate one machine as the "development" machine. This is the +machine on which you run your compiles and which has your source +code for the kernel. Designate a second machine as the "target" +machine. This is the machine that will run your experimental +kernel. + +The two machines will be connected together via a serial line out +one or the other of the COM ports of the PC. You will need the +appropriate modem eliminator (null modem) cable(s) for this. + +Decide on which tty port you want the machines to communicate, then +connect them up back-to-back using the null modem cable. COM1 is +/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection +with the two machines prior to trying to debug a kernel. Once you +have it working, on the TARGET machine, enter: + +setserial /dev/ttyS0 (or what ever tty you are using) + +and record the port address and the IRQ number. + +On the DEVELOPMENT machine you need to apply the patch for the kgdb +hooks. You have probably already done that if you are reading this +file. + +On your DEVELOPMENT machine, go to your kernel source directory and do +"make Xconfig" where X is one of "x", "menu", or "". If you are +configuring in the standard serial driver, it must not be a module. +Either yes or no is ok, but making the serial driver a module means it +will initialize after kgdb has set up the UART interrupt code and may +cause a failure of the control-C option discussed below. The configure +question for the serial driver is under the "Character devices" heading +and is: + +"Standard/generic (8250/16550 and compatible UARTs) serial support" + +Go down to the kernel debugging menu item and open it up. Enable the +kernel kgdb stub code by selecting that item. You can also choose to +turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler +to put more debug info (like local symbols) in the object file. On the +i386 -g and -ggdb are the same so this option just reduces to "O1". The +-O1 reduces the optimization level. This may be helpful in some cases, +be aware, however, that this may also mask the problem you are looking +for. + +The baud rate. Default is 115200. What ever you choose be sure that +the host machine is set to the same speed. I recommend the default. + +The port. This is the I/O address of the serial UART that you should +have gotten using setserial as described above. The standard COM1 port +(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ +3. + +The port IRQ (see above). + +Stack overflow test. This option makes a minor change in the trap, +system call and interrupt code to detect stack overflow and transfer +control to kgdb if it happens. (Some platforms have this in the +baseline code, but the i386 does not.) + +You can also configure the system to recognize the boot option +"console=kgdb" which if given will cause all console output during +booting to be put thru gdb as well as other consoles. This option +requires that gdb and kgdb be connected prior to sending console output +so, if they are not, a breakpoint is executed to force the connection. +This will happen before any kernel output (it is going thru gdb, right), +and will stall the boot until the connection is made. + +You can also configure in a patch to SysRq to enable the kGdb SysRq. +This request generates a breakpoint. Since the serial port IRQ line is +set up after any serial drivers, it is possible that this command will +work when the control-C will not. + +Save and exit the Xconfig program. Then do "make clean" , "make dep" +and "make bzImage" (or whatever target you want to make). This gets the +kernel compiled with the "-g" option set -- necessary for debugging. + +You have just built the kernel on your DEVELOPMENT machine that you +intend to run on your TARGET machine. + +To install this new kernel, use the following installation procedure. +Remember, you are on the DEVELOPMENT machine patching the kernel source +for the kernel that you intend to run on the TARGET machine. + +Copy this kernel to your target machine using your usual procedures. I +usually arrange to copy development: +/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine +via a LAN based NFS access. That is, I run the cp command on the target +and copy from the development machine via the LAN. Run Lilo (see "man +lilo" for details on how to set this up) on the new kernel on the target +machine so that it will boot! Then boot the kernel on the target +machine. + +On the DEVELOPMENT machine, create a file called .gdbinit in the +directory /usr/src/linux. An example .gdbinit file looks like this: + +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 (or what ever speed you have chosen) +target remote /dev/ttyS0 + + +Change the "echo" and "target" definition so that it specifies the tty +port that you intend to use. Change the "remotebaud" definition to +match the data rate that you are going to use for the com line. + +You are now ready to try it out. + +Boot your target machine with "kgdb" in the boot command i.e. something +like: + +lilo> test kgdb + +or if you also want console output thru gdb: + +lilo> test kgdb console=kgdb + +You should see the lilo message saying it has loaded the kernel and then +all output stops. The kgdb stub is trying to connect with gdb. Start +gdb something like this: + + +On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux". +When gdb gets the symbols loaded it will read your .gdbinit file and, if +everything is working correctly, you should see gdb print out a few +lines indicating that a breakpoint has been taken. It will actually +show a line of code in the target kernel inside the kgdb activation +code. + +The gdb interaction should look something like this: + + linux-dev:/usr/src/linux# gdb vmlinux + GDB is free software and you are welcome to distribute copies of it + under certain conditions; type "show copying" to see the conditions. + There is absolutely no warranty for GDB; type "show warranty" for details. + GDB 4.15.1 (i486-slackware-linux), + Copyright 1995 Free Software Foundation, Inc... + breakpoint () at i386-stub.c:750 + 750 } + (gdb) + +You can now use whatever gdb commands you like to set breakpoints. +Enter "continue" to start your target machine executing again. At this +point the target system will run at full speed until it encounters +your breakpoint or gets a segment violation in the kernel, or whatever. + +If you have the kgdb console enabled when you continue, gdb will print +out all the console messages. + +The above example caused a breakpoint relatively early in the boot +process. For the i386 kgdb it is possible to code a break instruction +as the first C-language point in init/main.c, i.e. as the first instruction +in start_kernel(). This could be done as follows: + +#include + breakpoint(); + +This breakpoint() is really a function that sets up the breakpoint and +single-step hardware trap cells and then executes a breakpoint. Any +early hard coded breakpoint will need to use this function. Once the +trap cells are set up they need not be set again, but doing it again +does not hurt anything, so you don't need to be concerned about which +breakpoint is hit first. Once the trap cells are set up (and the kernel +sets them up in due course even if breakpoint() is never called) the +macro: + +BREAKPOINT; + +will generate an inline breakpoint. This may be more useful as it stops +the processor at the instruction instead of in a function a step removed +from the location of interest. In either case must be +included to define both breakpoint() and BREAKPOINT. + +Triggering kgdbstub at other times +================================== + +Often you don't need to enter the debugger until much later in the boot +or even after the machine has been running for some time. Once the +kernel is booted and interrupts are on, you can force the system to +enter the debugger by sending a control-C to the debug port. This is +what the first line of the recommended .gdbinit file does. This allows +you to start gdb any time after the system is up as well as when the +system is already at a breakpoint. (In the case where the system is +already at a breakpoint the control-C is not needed, however, it will +be ignored by the target so no harm is done. Also note the the echo +command assumes that the port speed is already set. This will be true +once gdb has connected, but it is best to set the port speed before you +run gdb.) + +Another simple way to do this is to put the following file in you ~/bin +directory: + +#!/bin/bash +echo -e "\003" > /dev/ttyS0 + +Here, the ttyS0 should be replaced with what ever port you are using. +The "\003" is control-C. Once you are connected with gdb, you can enter +control-C at the command prompt. + +An alternative way to get control to the debugger is to enable the kGdb +SysRq command. Then you would enter Alt-SysRq-g (all three keys at the +same time, but push them down in the order given). To refresh your +memory of the available SysRq commands try Alt-SysRq-=. Actually any +undefined command could replace the "=", but I like to KNOW that what I +am pushing will never be defined. + +Debugging hints +=============== + +You can break into the target machine at any time from the development +machine by typing ^C (see above paragraph). If the target machine has +interrupts enabled this will stop it in the kernel and enter the +debugger. + +There is unfortunately no way of breaking into the kernel if it is +in a loop with interrupts disabled, so if this happens to you then +you need to place exploratory breakpoints or printk's into the kernel +to find out where it is looping. The exploratory breakpoints can be +entered either thru gdb or hard coded into the source. This is very +handy if you do something like: + +if () BREAKPOINT; + + +There is a copy of an e-mail in the Documentation/i386/kgdb/ directory +(debug-nmi.txt) which describes how to create an NMI on an ISA bus +machine using a paper clip. I have a sophisticated version of this made +by wiring a push button switch into a PC104/ISA bus adapter card. The +adapter card nicely furnishes wire wrap pins for all the ISA bus +signals. + +When you are done debugging the kernel on the target machine it is a +good idea to leave it in a running state. This makes reboots faster, +bypassing the fsck. So do a gdb "continue" as the last gdb command if +this is possible. To terminate gdb itself on the development machine +and leave the target machine running, first clear all breakpoints and +continue, then type ^Z to suspend gdb and then kill it with "kill %1" or +something similar. + +If gdbstub Does Not Work +======================== + +If it doesn't work, you will have to troubleshoot it. Do the easy +things first like double checking your cabling and data rates. You +might try some non-kernel based programs to see if the back-to-back +connection works properly. Just something simple like cat /etc/hosts +>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you +if you can send data from one machine to the other. Make sure it works +in both directions. There is no point in tearing out your hair in the +kernel if the line doesn't work. + +All of the real action takes place in the file +/usr/src/linux/arch/i386/kernel/kgdb_stub.c. That is the code on the target +machine that interacts with gdb on the development machine. In gdb you can +turn on a debug switch with the following command: + + set remotedebug + +This will print out the protocol messages that gdb is exchanging with +the target machine. + +Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is +the code that talks to the serial port on the target side. There might +be a problem there. In particular there is a section of this code that +tests the UART which will tell you what UART you have if you define +"PRNT" (just remove "_off" from the #define PRNT_off). To view this +report you will need to boot the system without any beakpoints. This +allows the kernel to run to the point where it calls kgdb to set up +interrupts. At this time kgdb will test the UART and print out the type +it finds. (You need to wait so that the printks are actually being +printed. Early in the boot they are cached, waiting for the console to +be enabled. Also, if kgdb is entered thru a breakpoint it is possible +to cause a dead lock by calling printk when the console is locked. The +stub thus avoids doing printks from breakpoints, especially in the +serial code.) At this time, if the UART fails to do the expected thing, +kgdb will print out (using printk) information on what failed. (These +messages will be buried in all the other boot up messages. Look for +lines that start with "gdb_hook_interrupt:". You may want to use dmesg +once the system is up to view the log. If this fails or if you still +don't connect, review your answers for the port address. Use: + +setserial /dev/ttyS0 + +to get the current port and IRQ information. This command will also +tell you what the system found for the UART type. The stub recognizes +the following UART types: + +16450, 16550, and 16550A + +If you are really desperate you can use printk debugging in the +kgdbstub code in the target kernel until you get it working. In particular, +there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c +named "remote_debug". Compile your kernel with this set to 1, rather +than 0 and the debug stub will print out lots of stuff as it does +what it does. Likewise there are debug printks in the kgdb_serial.c +code that can be turned on with simple changes in the macro defines. + + +Debugging Loadable Modules +========================== + +This technique comes courtesy of Edouard Parmelan + + +When you run gdb, enter the command + +source gdbinit-modules + +This will read in a file of gdb macros that was installed in your +kernel source directory when kgdb was installed. This file implements +the following commands: + +mod-list + Lists the loaded modules in the form + +mod-print-symbols + Prints all the symbols in the indicated module. + +mod-add-symbols + Loads the symbols from the object file and associates them + with the indicated module. + +After you have loaded the module that you want to debug, use the command +mod-list to find the of your module. Then use that +address in the mod-add-symbols command to load your module's symbols. +From that point onward you can debug your module as if it were a part +of the kernel. + +The file gdbinit-modules also contains a command named mod-add-lis as +an example of how to construct a command of your own to load your +favorite module. The idea is to "can" the pathname of the module +in the command so you don't have to type so much. + +Threads +======= + +Each process in a target machine is seen as a gdb thread. gdb thread +related commands (info threads, thread n) can be used. + +ia-32 hardware breakpoints +========================== + +kgdb stub contains support for hardware breakpoints using debugging features +of ia-32(x86) processors. These breakpoints do not need code modification. +They use debugging registers. 4 hardware breakpoints are available in ia-32 +processors. + +Each hardware breakpoint can be of one of the following three types. + +1. Execution breakpoint - An Execution breakpoint is triggered when code + at the breakpoint address is executed. + + As limited number of hardware breakpoints are available, it is + advisable to use software breakpoints ( break command ) instead + of execution hardware breakpoints, unless modification of code + is to be avoided. + +2. Write breakpoint - A write breakpoint is triggered when memory + location at the breakpoint address is written. + + A write or can be placed for data of variable length. Length of + a write breakpoint indicates length of the datatype to be + watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for + 4 byte data. + +3. Access breakpoint - An access breakpoint is triggered when memory + location at the breakpoint address is either read or written. + + Access breakpoints also have lengths similar to write breakpoints. + +IO breakpoints in ia-32 are not supported. + +Since gdb stub at present does not use the protocol used by gdb for hardware +breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros +for hardware breakpoints are described below. + +hwebrk - Places an execution breakpoint + hwebrk breakpointno address +hwwbrk - Places a write breakpoint + hwwbrk breakpointno length address +hwabrk - Places an access breakpoint + hwabrk breakpointno length address +hwrmbrk - Removes a breakpoint + hwrmbrk breakpointno +exinfo - Tells whether a software or hardware breakpoint has occurred. + Prints number of the hardware breakpoint if a hardware breakpoint has + occurred. + +Arguments required by these commands are as follows +breakpointno - 0 to 3 +length - 1 to 3 +address - Memory location in hex digits ( without 0x ) e.g c015e9bc + +SMP support +========== + +When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb +client, all the processors are forced to enter the debugger. Current +thread corresponds to the thread running on the processor where +breakpoint occurred. Threads running on other processor(s) appear +similar to other non-running threads in the 'info threads' output. +Within the kgdb stub there is a structure "waiting_cpus" in which kgdb +records the values of "current" and "regs" for each CPU other than the +one that hit the breakpoint. "current" is a pointer to the task +structure for the task that CPU is running, while "regs" points to the +saved registers for the task. This structure can be examined with the +gdb "p" command. + +ia-32 hardware debugging registers on all processors are set to same +values. Hence any hardware breakpoints may occur on any processor. + +gdb troubleshooting +=================== + +1. gdb hangs +Kill it. restart gdb. Connect to target machine. + +2. gdb cannot connect to target machine (after killing a gdb and +restarting another) If the target machine was not inside debugger when +you killed gdb, gdb cannot connect because the target machine won't +respond. In this case echo "Ctrl+C"(ASCII 3) to the serial line. +e.g. echo -e "\003" > /dev/ttyS1 +This forces that target machine into the debugger, after which you +can connect. + +3. gdb cannot connect even after echoing Ctrl+C into serial line +Try changing serial line settings min to 1 and time to 0 +e.g. stty min 1 time 0 < /dev/ttyS1 +Try echoing again + +Check serial line speed and set it to correct value if required +e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1 + +EVENTS +====== + +Ever want to know the order of things happening? Which CPU did what and +when? How did the spinlock get the way it is? Then events are for +you. Events are defined by calls to an event collection interface and +saved for later examination. In this case, kgdb events are saved by a +very fast bit of code in kgdb which is fully SMP and interrupt protected +and they are examined by using gdb to display them. Kgdb keeps only +the last N events, where N must be a power of two and is defined at +configure time. + + +Events are signaled to kgdb by calling: + +kgdb_ts(data0,data1) + +For each call kgdb records each call in an array along with other info. +Here is the array definition: + +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + int data0; + int data1; +}; + +For SMP machines the CPU is recorded, for all machines the TSC is +recorded (gets a time stamp) as well as the line number and source file +the call was made from. The address of the (from), the "if" (interrupt +flag) and the two data items are also recorded. The macro kgdb_ts casts +the types to int, so you can put any 32-bit values here. There is a +configure option to select the number of events you want to keep. A +nice number might be 128, but you can keep up to 1024 if you want. The +number must be a power of two. An "andthen" macro library is provided +for gdb to help you look at these events. It is also possible to define +a different structure for the event storage and cast the data to this +structure. For example the following structure is defined in kgdb: + +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + struct task_struct *t1; + struct task_struct *t2; +}; + +If you use this for display, the data elements will be displayed as +pointers to task_struct entries. You may want to define your own +structure to use in casting. You should only change the last two items +and you must keep the structure size the same. Kgdb will handle these +as 32-bit ints, but within that constraint you can define a structure to +cast to any 32-bit quantity. This need only be available to gdb and is +only used for casting in the display code. + +Final Items +=========== + +I picked up this code from Amit S. Kale and enhanced it. + +If you make some really cool modification to this stuff, or if you +fix a bug, please let me know. + +George Anzinger + + +Amit S. Kale + + +(First kgdb by David Grothe ) + +(modified by Tigran Aivazian ) + Putting gdbstub into the kernel config menu. + +(modified by Scott Foehner ) + Hooks for entering gdbstub at boot time. + +(modified by Amit S. Kale ) + Threads, ia-32 hw debugging, mp support, console support, + nmi watchdog handling. + +(modified by George Anzinger ) + Extended threads to include the idle threads. + Enhancements to allow breakpoint() at first C code. + Use of module_init() and __setup() to automate the configure. + Enhanced the cpu "collection" code to work in early bring-up. + Added ability to call functions from gdb + Print info thread stuff without going back to schedule() + Now collect the "other" cpus with an IPI/ NMI. --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/i386/kgdb/loadmodule.sh 2004-01-04 17:36:33.000000000 -0800 @@ -0,0 +1,78 @@ +#/bin/sh +# This script loads a module on a target machine and generates a gdb script. +# source generated gdb script to load the module file at appropriate addresses +# in gdb. +# +# Usage: +# Loading the module on target machine and generating gdb script) +# [foo]$ loadmodule.sh +# +# Loading the module file into gdb +# (gdb) source +# +# Modify following variables according to your setup. +# TESTMACHINE - Name of the target machine +# GDBSCRIPTS - The directory where a gdb script will be generated +# +# Author: Amit S. Kale (akale@veritas.com). +# +# If you run into problems, please check files pointed to by following +# variables. +# ERRFILE - /tmp/.errs contains stderr output of insmod +# MAPFILE - /tmp/.map contains stdout output of insmod +# GDBSCRIPT - $GDBSCRIPTS/load gdb script. + +TESTMACHINE=foo +GDBSCRIPTS=/home/bar + +if [ $# -lt 1 ] ; then { + echo Usage: $0 modulefile + exit +} ; fi + +MODULEFILE=$1 +MODULEFILEBASENAME=`basename $1` + +if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then { + MODULEFILE=`pwd`/$MODULEFILE +} fi + +ERRFILE=/tmp/$MODULEFILEBASENAME.errs +MAPFILE=/tmp/$MODULEFILEBASENAME.map +GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME + +function findaddr() { + local ADDR=0x$(echo "$SEGMENTS" | \ + grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \ + sed 's/[ ]*[^ ]*$//') + echo $ADDR +} + +function checkerrs() { + if [ "`cat $ERRFILE`" != "" ] ; then { + cat $ERRFILE + exit + } fi +} + +#load the module +echo Copying $MODULEFILE to $TESTMACHINE +rcp $MODULEFILE root@${TESTMACHINE}: + +echo Loading module $MODULEFILE +rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \ + > $MAPFILE 2> $ERRFILE +checkerrs + +SEGMENTS=`head -n 11 $MAPFILE | tail -n 10` +TEXTADDR=$(findaddr "\\.text[^.]") +LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR" +SEGADDRS=`echo "$SEGMENTS" | awk '//{ + if ($1 != ".text" && $1 != ".this" && + $1 != ".kstrtab" && $1 != ".kmodtab") { + print " -s " $1 " 0x" $3 " " + } +}'` +LOADSTRING="$LOADSTRING $SEGADDRS" +echo Generating script $GDBSCRIPT +echo $LOADSTRING > $GDBSCRIPT --- linux-2.6.1-rc1/Documentation/kernel-parameters.txt 2003-12-30 22:37:20.000000000 -0800 +++ 25/Documentation/kernel-parameters.txt 2004-01-04 22:15:42.000000000 -0800 @@ -37,7 +37,7 @@ restrictions referred to are that the re MCA MCA bus support is enabled. MDA MDA console support is enabled. MOUSE Appropriate mouse support is enabled. - MTD MTD support is nebaled. + MTD MTD support is enabled. NET Appropriate network support is enabled. NFS Appropriate NFS support is enabled. OSS OSS sound support is enabled. @@ -57,6 +57,7 @@ restrictions referred to are that the re SMP The kernel is an SMP kernel. SPARC Sparc architecture is enabled. SWSUSP Software suspension is enabled. + TS Appropriate touchscreen support is enabled. USB USB support is enabled. V4L Video For Linux support is enabled. VGA The VGA console has been enabled. @@ -85,6 +86,9 @@ running once the system is up. See header of drivers/scsi/53c7xx.c. See also Documentation/scsi/ncr53c7xx.txt. + 98busmouse.irq= [HW,MOUSE] PC-9801 Bus Mouse Driver + Format: , default is 13 + acpi= [HW,ACPI] Advanced Configuration and Power Interface Format: { force | off | ht } force -- enables ACPI for systems with default off @@ -92,6 +96,23 @@ running once the system is up. ht -- run only enough ACPI to enable Hyper Threading See also Documentation/pm.txt. + acpi_pic_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode + Format: { level | edge } + level Force PIC-mode SCI to Level Trigger (default) + edge Force PIC-mode SCI to Edge Trigge + + acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs + default in APIC mode + + acpi_irq_nobalance [HW,ACPI] ACPI will not move active IRQs (default) + default in PIC mode + + acpi_irq_pci= [HW,ACPI] If irq_balance, Clear listed IRQs for use by PCI + Format: ,... + + acpi_irq_isa= [HW,ACPI] If irq_balance, Mark listed IRQs used by ISA + Format: ,... + ad1816= [HW,OSS] Format: ,,, See also Documentation/sound/oss/AD1816. @@ -153,10 +174,11 @@ running once the system is up. atascsi= [HW,SCSI] Atari SCSI - atkbd_set= [HW] Select keyboard code set + atkbd.set= [HW] Select keyboard code set Format: - - atkbd_reset [HW] Reset keyboard during initialization + atkbd.softrepeat= + [HW] Use software keyboard repeat + atkbd.reset= [HW] Reset keyboard during initialization autotest [IA64] @@ -215,7 +237,7 @@ running once the system is up. Forces specified timesource (if avaliable) to be used when calculating gettimeofday(). If specicified timesource is not avalible, it defaults to PIT. - Format: { pit | tsc | cyclone | ... } + Format: { pit | tsc | cyclone | pmtmr } hpet= [IA-32,HPET] option to disable HPET and use PIT. Format: disable @@ -372,13 +394,15 @@ running once the system is up. noirqbalance [IA-32,SMP,KNL] Disable kernel irq balancing - i8042_direct [HW] Keyboard has been put into non-translated mode - by BIOS - i8042_dumbkbd [HW] Don't attempt to blink the leds - i8042_noaux [HW] Don't check for auxiliary (== mouse) port - i8042_nomux - i8042_reset [HW] Reset the controller during init and cleanup - i8042_unlock [HW] Unlock (ignore) the keylock + i8042.direct [HW] Put keyboard port into non-translated mode + i8042.dumbkbd [HW] Pretend that controlled can only read data from + keyboard and can not control its state + (Don't attempt to blink the leds) + i8042.noaux [HW] Don't check for auxiliary (== mouse) port + i8042.nomux [HW] Don't check presence of an active multiplexing + controller + i8042.reset [HW] Reset the controller during init and cleanup + i8042.unlock [HW] Unlock (ignore) the keylock i810= [HW,DRM] @@ -414,7 +438,7 @@ running once the system is up. initrd= [BOOT] Specify the location of the initial ramdisk - inport_irq= [HW] Inport (ATI XL and Microsoft) busmouse driver + inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver Format: inttest= [IA64] @@ -462,7 +486,7 @@ running once the system is up. lockd.tcpport= [NFS] - logibm_irq= [HW,MOUSE] Logitech Bus Mouse Driver + logibm.irq= [HW,MOUSE] Logitech Bus Mouse Driver Format: log_buf_len=n Sets the size of the printk ring buffer, in bytes. @@ -562,6 +586,11 @@ running once the system is up. mga= [HW,DRM] + mousedev.xres [MOUSE] Horizontal screen resolution, used for devices + reporting absolute coordinates, such as tablets + mousedev.yres [MOUSE] Vertical screen resolution, used for devices + reporting absolute coordinates, such as tablets + mpu401= [HW,OSS] Format: , @@ -795,12 +824,18 @@ running once the system is up. before loading. See Documentation/ramdisk.txt. - psmouse_proto= [HW,MOUSE] Highest PS2 mouse protocol extension to + psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to probe for (bare|imps|exps). - - psmouse_resetafter= + psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports + per second. + psmouse.resetafter= [HW,MOUSE] Try to reset Synaptics Touchpad after so many bad packets (0 = never). + psmouse.resolution= + [HW,MOUSE] Set desired mouse resolution, in dpi. + psmouse.smartscroll= + [HW,MOUSE] Controls Logitech smartscroll autorepeat, + 0 = disabled, 1 = enabled (default). pss= [HW,OSS] Personal Sound System (ECHO ESC614) Format: ,,,,, @@ -1118,6 +1153,9 @@ running once the system is up. trix= [HW,OSS] MediaTrix AudioTrix Pro Format: ,,,,,,,, + tsdev.xres [TS] Horizontal screen resolution. + tsdev.yres [TS] Vertical screen resolution. + u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter See header of drivers/scsi/u14-34f.c. --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25/Documentation/laptop-mode.txt 2004-01-04 22:16:29.000000000 -0800 @@ -0,0 +1,423 @@ +How to conserve battery power using laptop-mode +----------------------------------------------- + +Document Author: Bart Samwel (bart@samwel.tk) +Date created: January 2, 2004 + +Introduction +------------ + +Laptopmode is used to minimize the time that the hard disk needs to be spun up, +to conserve battery power on laptops. It has been reported to cause significant +power savings. + +Contents +-------- + +* Introduction +* The short story +* Caveats +* The details +* Tips & Tricks +* Control script +* Monitoring tool + + +The short story +--------------- + +If you just want to use it, run the laptop_mode control script (which is included +at the end of this document) as follows: + +# laptop_mode start + +Then set your harddisk spindown time to a relatively low value with hdparm: + +hdparm -S 4 /dev/hda + +The value -S 4 means 20 seconds idle time before spindown. Your harddisk will +now only spin up when a disk cache miss occurs, or at least once every 10 +minutes to write back any pending changes. + +To stop laptop_mode, remount your filesystems with regular commit intervals +(e.g., 5 seconds), and run "laptop_mode stop". + + +Caveats +------- + +* The downside of laptop mode is that you have a chance of losing up + to 10 minutes of work. If you cannot afford this, don't use it! + +* Most desktop hard drives have a very limited lifetime measured in spindown + cycles, typically about 50.000 times (it's usually listed on the spec sheet). + Check your drive's rating, and don't wear down your drive's lifetime if you + don't need to. + +* If you mount some of your ext3/reiserfs filesystems with the -n option, then + the control script will not be able to remount them correctly. You must set + DO_REMOUNTS=0 in the control script, otherwise it will remount them with the + wrong options -- or it will fail because it cannot write to /etc/mtab. + +* If you have your filesystems listed as type "auto" in fstab, like I did, then + the control script will not recognize them as filesystems that need remounting. + +The details +----------- + +Laptop-mode is controlled by the flag /proc/sys/vm/laptop_mode. When this +flag is set, any physical disk read operation (that might have caused the +hard disk to spin up) causes Linux to flush all dirty blocks. The result +of this is that after a disk has spun down, it will not be spun up anymore +to write dirty blocks, because those blocks had already been written +immediately after the most recent read operation + +To increase the effectiveness of the laptop_mode strategy, the laptop_mode +control script increases dirty_expire_centisecs and dirty_writeback_centisecs in +/proc/sys/vm to about 10 minutes (by default), which means that pages that are +dirtied are not forced to be written to disk as often. The control script also +changes the dirty background ratio, so that background writeback of dirty pages +is not done anymore. Combined with a higher commit value (also 10 minutes) for +ext3 or ReiserFS filesystems (also done automatically by the control script), +this results in concentration of disk activity in a small time interval which +occurs only once every 10 minutes, or whenever the disk is forced to spin up by +a cache miss. The disk can then be spun down in the periods of inactivity. + +If you want to find out which process caused the disk to spin up, you can +gather information by setting the flag /proc/sys/vm/block_dump. When this flag +is set, Linux reports all disk read and write operations that take place, and +all block dirtyings done to files. This makes it possible to debug why a disk +needs to spin up, and to increase battery life even more. + +If 10 minutes is too much or too little downtime for you, you can configure +this downtime as follows. In the control script, set the MAX_AGE value to the +maximum number of seconds of disk downtime that you would like. You should +then set your filesystem's commit interval to the same value. The dirty ratio +is also configurable from the control script. + +If you don't like the idea of the control script remounting your filesystems +for you, you can change DO_REMOUNTS to 0 in the script. + +Thanks to Kiko Piris, the control script can be used to enable laptop mode on +both the Linux 2.4 and 2.6 series. + + +Tips & Tricks +------------- + +* Bartek Krania reports getting up to 50 minutes of extra battery life (on top + of his regular 3 to 3.5 hours) using very aggressive power management (hdparm + -B1) and a spindown time of 5 seconds (hdparm -S1). + +* You can spin down the disk while playing MP3, by setting the disk readahead + to 8MB (hdparm -a 16384). Effectively, the disk will read a complete MP3 at + once, and will then spin down while the MP3 is playing. (Thanks to Bartek + Krania.) + + +Control script +-------------- + +Please note that this control script works for the Linux 2.4 and 2.6 series. + +--------------------CONTROL SCRIPT BEGIN------------------------------------------ +#!/bin/sh + +# start or stop laptop_mode, best run by a power management daemon when +# ac gets connected/disconnected from a laptop +# +# Contributors to this script: Kiko Piris +# Bart Samwel +# Original Linux 2.4 version by: Jens Axboe + +parse_mount_opts () { + echo "$*" | \ + sed 's/commit=[0-9]*//g' | \ + sed 's/,,*/,/g' | \ + sed 's/^,//' | \ + sed 's/,$//' | \ + cat - +} + +KLEVEL="$(uname -r | cut -c1-3)" +case "$KLEVEL" in + "2.4") + true + ;; + "2.6") + true + ;; + *) + echo "Unhandled kernel level: $KLEVEL ('uname -r' = '$(uname -r)')" + exit 1 + ;; +esac + +# Shall we remount journaled fs. with appropiate commit interval? (1=yes) +DO_REMOUNTS=1 + +# age time, in seconds. should be put into a sysconfig file +MAX_AGE=600 + +# Allowed dirty ratio, in pct. should be put into a sysconfig file as well. +DIRTY_RATIO=40 + +# kernel default dirty buffer age +DEF_AGE=30 +DEF_UPDATE=5 +DEF_DIRTY_BACKGROUND_RATIO=10 +DEF_DIRTY_RATIO=40 + + +if [ ! -e /proc/sys/vm/laptop_mode ]; then + echo "Kernel is not patched with laptop_mode patch." + exit 1 +fi + +if [ ! -w /proc/sys/vm/laptop_mode ]; then + echo "You do not have enough privileges to enable laptop_mode." + exit 1 +fi + +case "$1" in + start) + AGE=$((100*$MAX_AGE)) + echo -n "Starting laptop_mode" + case "$KLEVEL" in + "2.4") + echo "1" > /proc/sys/vm/laptop_mode + echo "30 500 0 0 $AGE $AGE 60 20 0" > /proc/sys/vm/bdflush + ;; + "2.6") + echo "1" > /proc/sys/vm/laptop_mode + echo "$AGE" > /proc/sys/vm/dirty_writeback_centisecs + echo "$AGE" > /proc/sys/vm/dirty_expire_centisecs + echo "$DIRTY_RATIO" > /proc/sys/vm/dirty_ratio + echo "$DIRTY_RATIO" > /proc/sys/vm/dirty_background_ratio + ;; + esac + if [ $DO_REMOUNTS -eq 1 ]; then + cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do + PARSEDOPTS="$(parse_mount_opts "$OPTS")" + case "$FST" in + "ext3") mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;; + "reiserfs") mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;; + "xfs") mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;; + done + fi + echo "." + ;; + stop) + U_AGE=$((100*$DEF_UPDATE)) + B_AGE=$((100*$DEF_AGE)) + echo -n "Stopping laptop_mode" + case "$KLEVEL" in + "2.4") + echo "0" > /proc/sys/vm/laptop_mode + echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush + ;; + "2.6") + echo "0" > /proc/sys/vm/laptop_mode + echo "$U_AGE" > /proc/sys/vm/dirty_writeback_centisecs + echo "$B_AGE" > /proc/sys/vm/dirty_expire_centisecs + echo "$DEF_DIRTY_RATIO" > /proc/sys/vm/dirty_ratio + echo "$DEF_DIRTY_BACKGROUND_RATIO" > /proc/sys/vm/dirty_background_ratio + ;; + esac + if [ $DO_REMOUNTS -eq 1 ]; then + cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do + PARSEDOPTS="$(parse_mount_opts "$OPTS")" + case "$FST" in + "ext3") mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;; + "reiserfs") mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;; + "xfs") mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;; + esac + done + fi + echo "." + ;; + *) + echo "$0 {start|stop}" + ;; + +esac + +exit 0 + +--------------------CONTROL SCRIPT END-------------------------------------------- + + + +Monitoring tool +--------------- + +Bartek Kania submitted this, it can be used to measure how much time your disk +spends spun up/down. + +---------------------------dslm.c BEGIN------------------------------------------- +/* + * Simple Disk SLeep Monitor + * by Bartek Kania + * Licenced under the GPL + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +int endit = 0; + +/* Check if the disk is in powersave-mode + * Most of the code is stolen from hdparm. + * 1 = active, 0 = standby/sleep, -1 = unknown */ +int check_powermode(int fd) +{ + unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0}; + int state; + + if (ioctl(fd, HDIO_DRIVE_CMD, &args) + && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */ + && ioctl(fd, HDIO_DRIVE_CMD, &args)) { + if (errno != EIO || args[0] != 0 || args[1] != 0) { + state = -1; /* "unknown"; */ + } else + state = 0; /* "sleeping"; */ + } else { + state = (args[2] == 255) ? 1 : 0; + } + D(printf(" drive state is: %s\n", state)); + + return state; +} + +char *state_name(int i) +{ + if (i == -1) return "unknown"; + if (i == 0) return "sleeping"; + if (i == 1) return "active"; + + return "internal error"; +} + +char *myctime(time_t time) +{ + char *ts = ctime(&time); + ts[strlen(ts) - 1] = 0; + + return ts; +} + +void measure(int fd) +{ + time_t start_time; + int last_state; + time_t last_time; + int curr_state; + time_t curr_time = 0; + time_t time_diff; + time_t active_time = 0; + time_t sleep_time = 0; + time_t unknown_time = 0; + time_t total_time = 0; + int changes = 0; + float tmp; + + printf("Starting measurements\n"); + + last_state = check_powermode(fd); + start_time = last_time = time(0); + printf(" System is in state %s\n\n", state_name(last_state)); + + while(!endit) { + sleep(1); + curr_state = check_powermode(fd); + + if (curr_state != last_state || endit) { + changes++; + curr_time = time(0); + time_diff = curr_time - last_time; + + if (last_state == 1) active_time += time_diff; + else if (last_state == 0) sleep_time += time_diff; + else unknown_time += time_diff; + + last_state = curr_state; + last_time = curr_time; + + printf("%s: State-change to %s\n", myctime(curr_time), + state_name(curr_state)); + } + } + changes--; /* Compensate for SIGINT */ + + total_time = time(0) - start_time; + printf("\nTotal running time: %lus\n", curr_time - start_time); + printf(" State changed %d times\n", changes); + + tmp = (float)sleep_time / (float)total_time * 100; + printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp); + tmp = (float)active_time / (float)total_time * 100; + printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp); + tmp = (float)unknown_time / (float)total_time * 100; + printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp); +} + +void ender(int s) +{ + endit = 1; +} + +void usage() +{ + puts("usage: dslm [-w