Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' 1.0
Jack Lange [Sat, 25 Oct 2008 18:39:54 +0000 (13:39 -0500)]
Conflicts:
palacios/include/devices/generic.h
palacios/src/devices/ramdisk.c

451 files changed:
build/Makefile
build/RunIso.sh [new file with mode: 0755]
geekos/include/geekos/vmm_stubs.h
geekos/src/geekos/keyboard.c
geekos/src/geekos/main.c
geekos/src/geekos/timer.c
geekos/src/geekos/vm.c
geekos/src/geekos/vmm_stubs.c
kitten/.hgignore [new file with mode: 0644]
kitten/COPYING [new file with mode: 0644]
kitten/CREDITS [new file with mode: 0644]
kitten/Kbuild [new file with mode: 0644]
kitten/Makefile [new file with mode: 0644]
kitten/README [new file with mode: 0644]
kitten/arch/x86_64/Kconfig [new file with mode: 0644]
kitten/arch/x86_64/Kconfig.debug [new file with mode: 0644]
kitten/arch/x86_64/Makefile [new file with mode: 0644]
kitten/arch/x86_64/boot/Makefile [new file with mode: 0644]
kitten/arch/x86_64/boot/bootsect.S [new file with mode: 0644]
kitten/arch/x86_64/boot/compressed/Makefile [new file with mode: 0644]
kitten/arch/x86_64/boot/compressed/head.S [new file with mode: 0644]
kitten/arch/x86_64/boot/compressed/misc.c [new file with mode: 0644]
kitten/arch/x86_64/boot/compressed/vmlwk.lds [new file with mode: 0644]
kitten/arch/x86_64/boot/compressed/vmlwk.scr [new file with mode: 0644]
kitten/arch/x86_64/boot/setup.S [new file with mode: 0644]
kitten/arch/x86_64/boot/tools/build.c [new file with mode: 0644]
kitten/arch/x86_64/boot/video.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/Makefile [new file with mode: 0644]
kitten/arch/x86_64/kernel/asm-offsets.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/bios.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/cpu.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/cpuinfo.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/e820.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/entry.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/head.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/head64.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/i387.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/init_task.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/interrupts.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/ioapic.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/lapic.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/mpboot.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/mpparse.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/percpu.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/rca/Makefile [new file with mode: 0644]
kitten/arch/x86_64/kernel/rca/l0rca.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/resource.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/sched.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/setup.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/show.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/sys_arch_prctl.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/syscall.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/task.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/time.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/trampoline.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/verify_cpu.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/vmlwk.lds.S [new file with mode: 0644]
kitten/arch/x86_64/kernel/vsyscall.c [new file with mode: 0644]
kitten/arch/x86_64/kernel/xcall.c [new file with mode: 0644]
kitten/arch/x86_64/lib/Makefile [new file with mode: 0644]
kitten/arch/x86_64/lib/bitops.c [new file with mode: 0644]
kitten/arch/x86_64/lib/copy_user.S [new file with mode: 0644]
kitten/arch/x86_64/lib/delay.c [new file with mode: 0644]
kitten/arch/x86_64/lib/extable.c [new file with mode: 0644]
kitten/arch/x86_64/lib/getuser.S [new file with mode: 0644]
kitten/arch/x86_64/lib/memcpy.S [new file with mode: 0644]
kitten/arch/x86_64/lib/memmove.c [new file with mode: 0644]
kitten/arch/x86_64/lib/memset.c [new file with mode: 0644]
kitten/arch/x86_64/lib/putuser.S [new file with mode: 0644]
kitten/arch/x86_64/lib/thunk.S [new file with mode: 0644]
kitten/arch/x86_64/lib/usercopy.c [new file with mode: 0644]
kitten/arch/x86_64/mm/Makefile [new file with mode: 0644]
kitten/arch/x86_64/mm/aspace.c [new file with mode: 0644]
kitten/arch/x86_64/mm/fault.c [new file with mode: 0644]
kitten/arch/x86_64/mm/init.c [new file with mode: 0644]
kitten/arch/x86_64/mm/phys_addr.c [new file with mode: 0644]
kitten/boot-kitten [new file with mode: 0755]
kitten/boot-kitten2 [new file with mode: 0755]
kitten/drivers/Makefile [new file with mode: 0644]
kitten/drivers/console/Makefile [new file with mode: 0644]
kitten/drivers/console/rcal0.c [new file with mode: 0644]
kitten/drivers/console/serial.c [new file with mode: 0644]
kitten/drivers/console/vga.c [new file with mode: 0644]
kitten/include/arch-generic/atomic.h [new file with mode: 0644]
kitten/include/arch-generic/bitops/hweight.h [new file with mode: 0644]
kitten/include/arch-generic/bug.h [new file with mode: 0644]
kitten/include/arch-generic/div64.h [new file with mode: 0644]
kitten/include/arch-generic/errno-base.h [new file with mode: 0644]
kitten/include/arch-generic/errno.h [new file with mode: 0644]
kitten/include/arch-generic/iomap.h [new file with mode: 0644]
kitten/include/arch-generic/mman.h [new file with mode: 0644]
kitten/include/arch-generic/pgtable.h [new file with mode: 0644]
kitten/include/arch-generic/sections.h [new file with mode: 0644]
kitten/include/arch-generic/siginfo.h [new file with mode: 0644]
kitten/include/arch-generic/signal.h [new file with mode: 0644]
kitten/include/arch-generic/vmlwk.lds.h [new file with mode: 0644]
kitten/include/arch-x86_64/apic.h [new file with mode: 0644]
kitten/include/arch-x86_64/apicdef.h [new file with mode: 0644]
kitten/include/arch-x86_64/aspace.h [new file with mode: 0644]
kitten/include/arch-x86_64/atomic.h [new file with mode: 0644]
kitten/include/arch-x86_64/auxvec.h [new file with mode: 0644]
kitten/include/arch-x86_64/bitops.h [new file with mode: 0644]
kitten/include/arch-x86_64/boot.h [new file with mode: 0644]
kitten/include/arch-x86_64/bootsetup.h [new file with mode: 0644]
kitten/include/arch-x86_64/bug.h [new file with mode: 0644]
kitten/include/arch-x86_64/byteorder.h [new file with mode: 0644]
kitten/include/arch-x86_64/cache.h [new file with mode: 0644]
kitten/include/arch-x86_64/calling.h [new file with mode: 0644]
kitten/include/arch-x86_64/cpufeature.h [new file with mode: 0644]
kitten/include/arch-x86_64/cpuinfo.h [new file with mode: 0644]
kitten/include/arch-x86_64/current.h [new file with mode: 0644]
kitten/include/arch-x86_64/debugreg.h [new file with mode: 0644]
kitten/include/arch-x86_64/delay.h [new file with mode: 0644]
kitten/include/arch-x86_64/desc.h [new file with mode: 0644]
kitten/include/arch-x86_64/div64.h [new file with mode: 0644]
kitten/include/arch-x86_64/dwarf2.h [new file with mode: 0644]
kitten/include/arch-x86_64/e820.h [new file with mode: 0644]
kitten/include/arch-x86_64/elf.h [new file with mode: 0644]
kitten/include/arch-x86_64/errno.h [new file with mode: 0644]
kitten/include/arch-x86_64/extable.h [new file with mode: 0644]
kitten/include/arch-x86_64/fixmap.h [new file with mode: 0644]
kitten/include/arch-x86_64/i387.h [new file with mode: 0644]
kitten/include/arch-x86_64/idt_vectors.h [new file with mode: 0644]
kitten/include/arch-x86_64/io.h [new file with mode: 0644]
kitten/include/arch-x86_64/io_apic.h [new file with mode: 0644]
kitten/include/arch-x86_64/ldt.h [new file with mode: 0644]
kitten/include/arch-x86_64/linkage.h [new file with mode: 0644]
kitten/include/arch-x86_64/mman.h [new file with mode: 0644]
kitten/include/arch-x86_64/mmu.h [new file with mode: 0644]
kitten/include/arch-x86_64/mpspec.h [new file with mode: 0644]
kitten/include/arch-x86_64/msr.h [new file with mode: 0644]
kitten/include/arch-x86_64/page.h [new file with mode: 0644]
kitten/include/arch-x86_64/page_table.h [new file with mode: 0644]
kitten/include/arch-x86_64/param.h [new file with mode: 0644]
kitten/include/arch-x86_64/pda.h [new file with mode: 0644]
kitten/include/arch-x86_64/percpu.h [new file with mode: 0644]
kitten/include/arch-x86_64/pgtable.h [new file with mode: 0644]
kitten/include/arch-x86_64/posix_types.h [new file with mode: 0644]
kitten/include/arch-x86_64/prctl.h [new file with mode: 0644]
kitten/include/arch-x86_64/processor.h [new file with mode: 0644]
kitten/include/arch-x86_64/proto.h [new file with mode: 0644]
kitten/include/arch-x86_64/ptrace.h [new file with mode: 0644]
kitten/include/arch-x86_64/rwlock.h [new file with mode: 0644]
kitten/include/arch-x86_64/sections.h [new file with mode: 0644]
kitten/include/arch-x86_64/segment.h [new file with mode: 0644]
kitten/include/arch-x86_64/show.h [new file with mode: 0644]
kitten/include/arch-x86_64/sigcontext.h [new file with mode: 0644]
kitten/include/arch-x86_64/siginfo.h [new file with mode: 0644]
kitten/include/arch-x86_64/signal.h [new file with mode: 0644]
kitten/include/arch-x86_64/smp.h [new file with mode: 0644]
kitten/include/arch-x86_64/spinlock.h [new file with mode: 0644]
kitten/include/arch-x86_64/spinlock_types.h [new file with mode: 0644]
kitten/include/arch-x86_64/stat.h [new file with mode: 0644]
kitten/include/arch-x86_64/string.h [new file with mode: 0644]
kitten/include/arch-x86_64/system.h [new file with mode: 0644]
kitten/include/arch-x86_64/task.h [new file with mode: 0644]
kitten/include/arch-x86_64/time.h [new file with mode: 0644]
kitten/include/arch-x86_64/tlbflush.h [new file with mode: 0644]
kitten/include/arch-x86_64/tsc.h [new file with mode: 0644]
kitten/include/arch-x86_64/types.h [new file with mode: 0644]
kitten/include/arch-x86_64/uaccess.h [new file with mode: 0644]
kitten/include/arch-x86_64/unistd.h [new file with mode: 0644]
kitten/include/arch-x86_64/user.h [new file with mode: 0644]
kitten/include/arch-x86_64/vsyscall.h [new file with mode: 0644]
kitten/include/arch-x86_64/xcall.h [new file with mode: 0644]
kitten/include/lwk/aspace.h [new file with mode: 0644]
kitten/include/lwk/auxvec.h [new file with mode: 0644]
kitten/include/lwk/bitmap.h [new file with mode: 0644]
kitten/include/lwk/bitops.h [new file with mode: 0644]
kitten/include/lwk/bootmem.h [new file with mode: 0644]
kitten/include/lwk/buddy.h [new file with mode: 0644]
kitten/include/lwk/byteorder/Kbuild [new file with mode: 0644]
kitten/include/lwk/byteorder/big_endian.h [new file with mode: 0644]
kitten/include/lwk/byteorder/generic.h [new file with mode: 0644]
kitten/include/lwk/byteorder/little_endian.h [new file with mode: 0644]
kitten/include/lwk/byteorder/swab.h [new file with mode: 0644]
kitten/include/lwk/cache.h [new file with mode: 0644]
kitten/include/lwk/compiler-gcc.h [new file with mode: 0644]
kitten/include/lwk/compiler-gcc4.h [new file with mode: 0644]
kitten/include/lwk/compiler.h [new file with mode: 0644]
kitten/include/lwk/console.h [new file with mode: 0644]
kitten/include/lwk/const.h [new file with mode: 0644]
kitten/include/lwk/cpu.h [new file with mode: 0644]
kitten/include/lwk/cpuinfo.h [new file with mode: 0644]
kitten/include/lwk/cpumask.h [new file with mode: 0644]
kitten/include/lwk/ctype.h [new file with mode: 0644]
kitten/include/lwk/delay.h [new file with mode: 0644]
kitten/include/lwk/driver.h [new file with mode: 0644]
kitten/include/lwk/elf-em.h [new file with mode: 0644]
kitten/include/lwk/elf.h [new file with mode: 0644]
kitten/include/lwk/errno.h [new file with mode: 0644]
kitten/include/lwk/extable.h [new file with mode: 0644]
kitten/include/lwk/hash.h [new file with mode: 0644]
kitten/include/lwk/htable.h [new file with mode: 0644]
kitten/include/lwk/idspace.h [new file with mode: 0644]
kitten/include/lwk/init.h [new file with mode: 0644]
kitten/include/lwk/init_task.h [new file with mode: 0644]
kitten/include/lwk/interrupt.h [new file with mode: 0644]
kitten/include/lwk/kallsyms.h [new file with mode: 0644]
kitten/include/lwk/kernel.h [new file with mode: 0644]
kitten/include/lwk/kmem.h [new file with mode: 0644]
kitten/include/lwk/liblwk.h [new symlink]
kitten/include/lwk/linkage.h [new file with mode: 0644]
kitten/include/lwk/linux_compat.h [new file with mode: 0644]
kitten/include/lwk/list.h [new file with mode: 0644]
kitten/include/lwk/log2.h [new file with mode: 0644]
kitten/include/lwk/palacios.h [new file with mode: 0644]
kitten/include/lwk/params.h [new file with mode: 0644]
kitten/include/lwk/percpu.h [new file with mode: 0644]
kitten/include/lwk/pfn.h [new file with mode: 0644]
kitten/include/lwk/pmem.h [new file with mode: 0644]
kitten/include/lwk/posix_types.h [new file with mode: 0644]
kitten/include/lwk/prefetch.h [new file with mode: 0644]
kitten/include/lwk/print.h [new file with mode: 0644]
kitten/include/lwk/ptrace.h [new file with mode: 0644]
kitten/include/lwk/resource.h [new file with mode: 0644]
kitten/include/lwk/sched.h [new file with mode: 0644]
kitten/include/lwk/screen_info.h [new file with mode: 0644]
kitten/include/lwk/seqlock.h [new file with mode: 0644]
kitten/include/lwk/show.h [new file with mode: 0644]
kitten/include/lwk/signal.h [new file with mode: 0644]
kitten/include/lwk/smp.h [new file with mode: 0644]
kitten/include/lwk/sort.h [new file with mode: 0644]
kitten/include/lwk/spinlock.h [new file with mode: 0644]
kitten/include/lwk/spinlock_api_smp.h [new file with mode: 0644]
kitten/include/lwk/spinlock_types.h [new file with mode: 0644]
kitten/include/lwk/stat.h [new file with mode: 0644]
kitten/include/lwk/stddef.h [new file with mode: 0644]
kitten/include/lwk/string.h [new file with mode: 0644]
kitten/include/lwk/stringify.h [new file with mode: 0644]
kitten/include/lwk/task.h [new file with mode: 0644]
kitten/include/lwk/time.h [new file with mode: 0644]
kitten/include/lwk/timer.h [new file with mode: 0644]
kitten/include/lwk/types.h [new file with mode: 0644]
kitten/include/lwk/unistd.h [new file with mode: 0644]
kitten/include/lwk/uts.h [new file with mode: 0644]
kitten/include/lwk/utsname.h [new file with mode: 0644]
kitten/include/lwk/waitq.h [new file with mode: 0644]
kitten/include/lwk/xcall.h [new file with mode: 0644]
kitten/include/rca/cray_event_def.h [new file with mode: 0644]
kitten/include/rca/l0rca_config.h [new file with mode: 0644]
kitten/include/rca/rca_defs.h [new file with mode: 0644]
kitten/include/rca/rca_l0.h [new file with mode: 0644]
kitten/include/rca/rca_l0_linux.h [new file with mode: 0644]
kitten/init/Kconfig [new file with mode: 0644]
kitten/init/Makefile [new file with mode: 0644]
kitten/init/main.c [new file with mode: 0644]
kitten/init/version.c [new file with mode: 0644]
kitten/kernel/Makefile [new file with mode: 0644]
kitten/kernel/console.c [new file with mode: 0644]
kitten/kernel/cpuinfo.c [new file with mode: 0644]
kitten/kernel/driver.c [new file with mode: 0644]
kitten/kernel/elf.c [new file with mode: 0644]
kitten/kernel/elf_liblwk.c [new symlink]
kitten/kernel/extable.c [new file with mode: 0644]
kitten/kernel/htable.c [new file with mode: 0644]
kitten/kernel/idspace.c [new file with mode: 0644]
kitten/kernel/init_task.c [new file with mode: 0644]
kitten/kernel/kallsyms.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/Makefile [new file with mode: 0644]
kitten/kernel/linux_syscalls/brk.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/fstat.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/gettimeofday.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/id.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/mmap.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/nanosleep.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/sched_yield.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/settimeofday.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/time.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/uname.c [new file with mode: 0644]
kitten/kernel/linux_syscalls/write.c [new file with mode: 0644]
kitten/kernel/panic.c [new file with mode: 0644]
kitten/kernel/params.c [new file with mode: 0644]
kitten/kernel/printk.c [new file with mode: 0644]
kitten/kernel/resource.c [new file with mode: 0644]
kitten/kernel/sched.c [new file with mode: 0644]
kitten/kernel/show.c [new file with mode: 0644]
kitten/kernel/spinlock.c [new file with mode: 0644]
kitten/kernel/task.c [new file with mode: 0644]
kitten/kernel/time.c [new file with mode: 0644]
kitten/kernel/timer.c [new file with mode: 0644]
kitten/kernel/waitq.c [new file with mode: 0644]
kitten/kernel/xcall.c [new file with mode: 0644]
kitten/lib/Kconfig.debug [new file with mode: 0644]
kitten/lib/Makefile [new file with mode: 0644]
kitten/lib/bitmap.c [new file with mode: 0644]
kitten/lib/cmdline.c [new file with mode: 0644]
kitten/lib/cpumask.c [new file with mode: 0644]
kitten/lib/ctype.c [new file with mode: 0644]
kitten/lib/extable.c [new file with mode: 0644]
kitten/lib/hweight.c [new file with mode: 0644]
kitten/lib/inflate.c [new file with mode: 0644]
kitten/lib/sort.c [new file with mode: 0644]
kitten/lib/string.c [new file with mode: 0644]
kitten/lib/vsprintf.c [new file with mode: 0644]
kitten/mm/Makefile [new file with mode: 0644]
kitten/mm/aspace.c [new file with mode: 0644]
kitten/mm/aspace_liblwk.c [new symlink]
kitten/mm/bootmem.c [new file with mode: 0644]
kitten/mm/buddy.c [new file with mode: 0644]
kitten/mm/kmem.c [new file with mode: 0644]
kitten/mm/pmem.c [new file with mode: 0644]
kitten/mm/pmem_liblwk.c [new symlink]
kitten/palacios-glue/Makefile [new file with mode: 0644]
kitten/palacios-glue/vm.c [new file with mode: 0644]
kitten/palacios-glue/vmm_stubs.c [new file with mode: 0644]
kitten/palacios/.do-not-delete [new file with mode: 0644]
kitten/scripts/Kbuild.include [new file with mode: 0644]
kitten/scripts/Makefile [new file with mode: 0644]
kitten/scripts/Makefile.build [new file with mode: 0644]
kitten/scripts/Makefile.clean [new file with mode: 0644]
kitten/scripts/Makefile.host [new file with mode: 0644]
kitten/scripts/Makefile.lib [new file with mode: 0644]
kitten/scripts/Makefile.modpost [new file with mode: 0644]
kitten/scripts/basic/Makefile [new file with mode: 0644]
kitten/scripts/basic/docproc.c [new file with mode: 0644]
kitten/scripts/basic/fixdep.c [new file with mode: 0644]
kitten/scripts/basic/split-include.c [new file with mode: 0644]
kitten/scripts/kallsyms.c [new file with mode: 0644]
kitten/scripts/kconfig/Makefile [new file with mode: 0644]
kitten/scripts/kconfig/POTFILES.in [new file with mode: 0644]
kitten/scripts/kconfig/conf.c [new file with mode: 0644]
kitten/scripts/kconfig/confdata.c [new file with mode: 0644]
kitten/scripts/kconfig/expr.c [new file with mode: 0644]
kitten/scripts/kconfig/expr.h [new file with mode: 0644]
kitten/scripts/kconfig/gconf.c [new file with mode: 0644]
kitten/scripts/kconfig/gconf.glade [new file with mode: 0644]
kitten/scripts/kconfig/images.c [new file with mode: 0644]
kitten/scripts/kconfig/kconfig_load.c [new file with mode: 0644]
kitten/scripts/kconfig/kxgettext.c [new file with mode: 0644]
kitten/scripts/kconfig/lex.zconf.c_shipped [new file with mode: 0644]
kitten/scripts/kconfig/lkc.h [new file with mode: 0644]
kitten/scripts/kconfig/lkc_proto.h [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/BIG.FAT.WARNING [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/Makefile [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/check-lxdialog.sh [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/checklist.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/colors.h [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/dialog.h [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/inputbox.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/lxdialog.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/menubox.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/msgbox.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/textbox.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/util.c [new file with mode: 0644]
kitten/scripts/kconfig/lxdialog/yesno.c [new file with mode: 0644]
kitten/scripts/kconfig/mconf.c [new file with mode: 0644]
kitten/scripts/kconfig/menu.c [new file with mode: 0644]
kitten/scripts/kconfig/qconf.cc [new file with mode: 0644]
kitten/scripts/kconfig/qconf.h [new file with mode: 0644]
kitten/scripts/kconfig/symbol.c [new file with mode: 0644]
kitten/scripts/kconfig/util.c [new file with mode: 0644]
kitten/scripts/kconfig/zconf.gperf [new file with mode: 0644]
kitten/scripts/kconfig/zconf.hash.c_shipped [new file with mode: 0644]
kitten/scripts/kconfig/zconf.l [new file with mode: 0644]
kitten/scripts/kconfig/zconf.tab.c_shipped [new file with mode: 0644]
kitten/scripts/kconfig/zconf.y [new file with mode: 0644]
kitten/scripts/mkcompile_h [new file with mode: 0755]
kitten/scripts/mksysmap [new file with mode: 0644]
kitten/scripts/toolchain/build-x86_64.sh [new file with mode: 0755]
kitten/user/Make.rules [new file with mode: 0644]
kitten/user/Makefile [new file with mode: 0644]
kitten/user/hello_world/COPYING [new file with mode: 0644]
kitten/user/hello_world/Makefile [new file with mode: 0644]
kitten/user/hello_world/hello_world.c [new file with mode: 0644]
kitten/user/liblwk/COPYING [new file with mode: 0644]
kitten/user/liblwk/Makefile [new file with mode: 0644]
kitten/user/liblwk/aspace.c [new file with mode: 0644]
kitten/user/liblwk/elf.c [new file with mode: 0644]
kitten/user/liblwk/include/lwk/liblwk.h [new file with mode: 0644]
kitten/user/liblwk/pmem.c [new file with mode: 0644]
kitten/user/liblwk/syscalls.c [new file with mode: 0644]
palacios/build/Makefile
palacios/include/devices/8237_dma.h
palacios/include/devices/8254.h
palacios/include/devices/8259a.h
palacios/include/devices/bochs_debug.h [new file with mode: 0644]
palacios/include/devices/cdrom.h
palacios/include/devices/generic.h
palacios/include/devices/ide.h
palacios/include/devices/keyboard.h
palacios/include/devices/nvram.h
palacios/include/devices/ramdisk.h
palacios/include/devices/serial.h
palacios/include/devices/simple_pic.h
palacios/include/devices/timer.h
palacios/include/palacios/svm.h
palacios/include/palacios/svm_halt.h
palacios/include/palacios/svm_handler.h
palacios/include/palacios/svm_io.h
palacios/include/palacios/svm_pause.h
palacios/include/palacios/svm_wbinvd.h
palacios/include/palacios/vm_dev.h
palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm.h
palacios/include/palacios/vmm_config.h
palacios/include/palacios/vmm_ctrl_regs.h
palacios/include/palacios/vmm_decoder.h
palacios/include/palacios/vmm_dev_mgr.h
palacios/include/palacios/vmm_emulator.h
palacios/include/palacios/vmm_host_events.h [new file with mode: 0644]
palacios/include/palacios/vmm_intr.h
palacios/include/palacios/vmm_io.h
palacios/include/palacios/vmm_list.h
palacios/include/palacios/vmm_lowlevel.h [new file with mode: 0644]
palacios/include/palacios/vmm_paging.h
palacios/include/palacios/vmm_shadow_paging.h
palacios/include/palacios/vmm_time.h
palacios/include/palacios/vmm_types.h
palacios/lib/xed/libxed32e.a [new file with mode: 0644]
palacios/src/devices/8237_dma.c
palacios/src/devices/8254.c
palacios/src/devices/8259a.c
palacios/src/devices/bochs_debug.c [new file with mode: 0644]
palacios/src/devices/cdrom.c
palacios/src/devices/generic.c
palacios/src/devices/keyboard.c
palacios/src/devices/nvram.c
palacios/src/devices/ramdisk.c
palacios/src/devices/serial.c
palacios/src/devices/simple_pic.c
palacios/src/devices/timer.c
palacios/src/palacios/svm.c
palacios/src/palacios/svm_halt.c
palacios/src/palacios/svm_handler.c
palacios/src/palacios/svm_io.c
palacios/src/palacios/svm_lowlevel.S [new file with mode: 0644]
palacios/src/palacios/svm_lowlevel.asm [deleted file]
palacios/src/palacios/svm_pause.c
palacios/src/palacios/svm_wbinvd.c
palacios/src/palacios/vm_dev.c
palacios/src/palacios/vm_guest.c
palacios/src/palacios/vm_guest_mem.c
palacios/src/palacios/vmcb.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_ctrl_regs.c
palacios/src/palacios/vmm_debug.c
palacios/src/palacios/vmm_decoder.c
palacios/src/palacios/vmm_dev_mgr.c
palacios/src/palacios/vmm_emulator.c
palacios/src/palacios/vmm_hashtable.c
palacios/src/palacios/vmm_host_events.c [new file with mode: 0644]
palacios/src/palacios/vmm_intr.c
palacios/src/palacios/vmm_io.c
palacios/src/palacios/vmm_lowlevel.asm [deleted file]
palacios/src/palacios/vmm_mem.c
palacios/src/palacios/vmm_paging.c
palacios/src/palacios/vmm_shadow_paging.c
palacios/src/palacios/vmm_util.c
palacios/src/palacios/vmm_xed.c

index 0364304..4c190c8 100644 (file)
@@ -40,6 +40,7 @@
 # ----------------------------------------------------------------------
 PROJECT_ROOT := ..
 PALACIOS_BUILD_DIR := $(PROJECT_ROOT)/palacios/build
+KITTEN_TOP_DIR := $(PROJECT_ROOT)/kitten
 GEEKOS_BUILD_DIR := $(PROJECT_ROOT)/geekos/build
 GUEST_ISO_DIR := /opt/vmm-tools/isos
 
@@ -152,6 +153,30 @@ DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_RAMDISK=0
 endif
 endif
 
+ifeq ($(DEBUG_XED),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_XED=1
+else 
+ifeq ($(DEBUG_XED),0) 
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_XED=0
+endif
+endif
+
+ifeq ($(DEBUG_HALT),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_HALT=1
+else 
+ifeq ($(DEBUG_HALT),0) 
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_HALT=0
+endif
+endif
+
+ifeq ($(DEBUG_DEV_MGR),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_DEV_MGR=1
+else 
+ifeq ($(DEBUG_DEV_MGR),0) 
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) DEBUG_DEV_MGR=0
+endif
+endif
+
 
 # ----------------------------------------------------------------------
 # Targets -
@@ -162,30 +187,47 @@ endif
 all : $(ALL_TARGETS)
 
 
+palacios64:
+       (cd $(PALACIOS_BUILD_DIR) && make ARCH=64 $(DEBUG_SECTIONS))
 
-palacios:
+palacios32:
        (cd $(PALACIOS_BUILD_DIR) && make $(DEBUG_SECTIONS))
 
 
-palacios-full:
+palacios-full32:
        (cd $(PALACIOS_BUILD_DIR) && make $(DEBUG_SECTIONS) world)
 
+palacios-full64:
+       (cd $(PALACIOS_BUILD_DIR) && make ARCH=64 $(DEBUG_SECTIONS) world)      
+
+palacios-lean:
+       (cd $(PALACIOS_BUILD_DIR) && make LEAN_AND_MEAN=1 world)
+
+kitten:
+       (cd $(KITTEN_TOP_DIR) && make)
+
+kitten-full: palacios-full64
+       (cd $(KITTEN_TOP_DIR) && make clean)
+       cp $(PALACIOS_BUILD_DIR)/libv3vee.a $(KITTEN_TOP_DIR)/palacios/
+       cp $(PALACIOS_BUILD_DIR)/../lib/xed/libxed32e.a $(KITTEN_TOP_DIR)/palacios/
+       cp $(PALACIOS_BUILD_DIR)/vm_kernel $(KITTEN_TOP_DIR)/palacios/
+       (cd $(KITTEN_TOP_DIR) && make)
+
 
 geekos: 
-       cp $(PALACIOS_BUILD_DIR)/libv3vee.a $(GEEKOS_BUILD_DIR)/palacios/
-       cp $(PALACIOS_BUILD_DIR)/../lib/xed/libxed.a $(GEEKOS_BUILD_DIR)/palacios/
-       cp $(PALACIOS_BUILD_DIR)/vm_kernel $(GEEKOS_BUILD_DIR)/palacios/
        (cd $(GEEKOS_BUILD_DIR) && make)
 
 
-geekos-full: 
+geekos-full: palacios-full32
        cp $(PALACIOS_BUILD_DIR)/libv3vee.a $(GEEKOS_BUILD_DIR)/palacios/
        cp $(PALACIOS_BUILD_DIR)/../lib/xed/libxed.a $(GEEKOS_BUILD_DIR)/palacios/
        cp $(PALACIOS_BUILD_DIR)/vm_kernel $(GEEKOS_BUILD_DIR)/palacios/
        (cd $(GEEKOS_BUILD_DIR) && make clean && make)
 
 
-world: palacios-full geekos-full
+world: geekos-full kitten-full
+
+lean-and-mean: palacios-lean geekos-full
 
 
 
diff --git a/build/RunIso.sh b/build/RunIso.sh
new file mode 100755 (executable)
index 0000000..64fcf72
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+/usr/local/qemu/bin/qemu-system-x86_64   -serial file:serial.out -m 1024 -cdrom test.iso 
index b56c114..d2d0ce4 100644 (file)
@@ -49,17 +49,22 @@ int ack_irq(int irq);
 int geekos_hook_interrupt(struct guest_info * info, uint_t irq);
 
 
-unsigned int get_cpu_khz();
-
-void Init_Stubs();
-
-
 
+unsigned int get_cpu_khz();
 
+void Init_Stubs(struct guest_info * info);
 
 
 
 
+/**** 
+ * 
+ * stubs called by geekos....
+ * 
+ ***/
+void send_key_to_vmm(unsigned char status, unsigned char scancode);
+void send_mouse_to_vmm(unsigned char packet[3]);
+void send_tick_to_vmm(unsigned int period_us);
 
 
 #if 0
index e33e989..501359e 100644 (file)
 #include <geekos/keyboard.h>
 
 
+#include <geekos/vmm_stubs.h>
 
 
 
-static enum {TARGET_GEEKOS,TARGET_VMM} target = TARGET_VMM;
+static enum {TARGET_GEEKOS, TARGET_VMM} target = TARGET_VMM;
+
 
 
-extern void deliver_key_to_vmm(uchar_t status, uchar_t scancode);
 
 /* ----------------------------------------------------------------------
  * Private data and functions
@@ -264,7 +265,7 @@ noflagchange:
       
 skip_flagchange:
 
-      if (target==TARGET_GEEKOS) { 
+      if (target == TARGET_GEEKOS) { 
        if (raw_scancode==0xc4) {  // F10 release
          Print("Switching keyboard to VMM\n");
          target=TARGET_VMM;
@@ -284,13 +285,15 @@ skip_flagchange:
           */
          g_needReschedule = true;
        }
-      } else if (target==TARGET_VMM) { 
-       if (raw_scancode==0xc4) {   // F10 release
+      } else if (target == TARGET_VMM) { 
+
+       if (raw_scancode == 0xc4) {   // F10 release
          Print("Switching keyboard to GeekOS\n");
-         target=TARGET_GEEKOS;
+         target = TARGET_GEEKOS;
        } else {
-         deliver_key_to_vmm(raw_status,raw_scancode);
+         send_key_to_vmm(raw_status, raw_scancode);
        }
+
       }
     }
 
index 29c2dde..5d71341 100644 (file)
@@ -220,7 +220,7 @@ void Main(struct Boot_Info* bootInfo)
   
   //Init_PCI();
 
-  Init_Stubs();
+
 
   //  Init_Network();
 
index 964f50b..8409fd7 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <geekos/io_defs.h>
 
+#include <geekos/vmm_stubs.h>
+
 /* PAD this currently is in nvram.c */
 /* JRL: This is completely broken
 extern void deliver_timer_interrupt_to_vmm(uint_t period_us);
@@ -218,9 +220,9 @@ static void Timer_Interrupt_Handler(struct Interrupt_State* state)
     
   }
   
-  /* JRL: Broken,  
-  deliver_timer_interrupt_to_vmm(1000000/HZ);
-  */
+
+  send_tick_to_vmm(1000000/HZ);
+
   End_IRQ(state);
 }
 
index 10c34ca..c391c63 100644 (file)
 #include <palacios/vmm_io.h>
 
 
-
-extern void * g_ramdiskImage;
-extern ulong_t s_ramdiskSize;
-
-
-#define SPEAKER_PORT 0x61
-
-static inline void VM_Out_Byte(ushort_t port, uchar_t value)
-{
-    __asm__ __volatile__ (
-       "outb %b0, %w1"
-       :
-       : "a" (value), "Nd" (port)
-    );
-}
-
-/*
- * Read a byte from an I/O port.
- */
-static inline uchar_t VM_In_Byte(ushort_t port)
-{
-    uchar_t value;
-
-    __asm__ __volatile__ (
-       "inb %w1, %b0"
-       : "=a" (value)
-       : "Nd" (port)
-    );
-
-    return value;
-}
-
-
-
-
-int IO_Read(ushort_t port, void * dst, uint_t length, void * priv_data) {
-
-  if (length != 1) {
-    return 0;
-  }
-
-  *(uchar_t*)dst = VM_In_Byte(port);    
-  return 1;
-}
-
+#define MAGIC_CODE 0xf1e2d3c4
 
 
-int IO_Write(ushort_t port, void * src, uint_t length, void * priv_data) {
+struct layout_region {
+  ulong_t length;
+  ulong_t final_addr;
+};
 
-  if (length != 1) {
-    return 0;
-  }
-
-  VM_Out_Byte(port, *(uchar_t *)src);    
-
-  return 1;
-}
-
-
-int IO_Read_to_Serial(ushort_t port, void * dst, uint_t length, void * priv_data) {
-  PrintBoth("Input from Guest on port %d (0x%x) Length=%d\n", port, port, length);
-  
-  return 0;
-}
-
-
-char * bochs_debug_buf = NULL;
-int bochs_debug_offset = 0;
-
-char * bochs_info_buf = NULL;
-int bochs_info_offset = 0;
+struct guest_mem_layout {
+  ulong_t magic;
+  ulong_t num_regions;
+  struct layout_region regions[0];
+};
 
 
-int IO_BOCHS_debug(ushort_t port, void * src, uint_t length, void * priv_data) {
-  if (!bochs_debug_buf) {
-    bochs_debug_buf = (char*)Malloc(1024);
-  }
-
-  bochs_debug_buf[bochs_debug_offset++] = *(char*)src;
-
-  if ((*(char*)src == 0xa) ||  (bochs_debug_offset == 1023)) {
-    SerialPrint("BOCHSDEBUG>%s", bochs_debug_buf);
-    memset(bochs_debug_buf, 0, 1024);
-    bochs_debug_offset = 0;
-  }
-
-  return length;
-}
-
-int IO_BOCHS_info(ushort_t port, void * src, uint_t length, void * priv_data) {
-  if (!bochs_info_buf) {
-    bochs_info_buf = (char*)Malloc(1024);
-  }
-
-  bochs_info_buf[bochs_info_offset++] = *(char*)src;
-
-  if ((*(char*)src == 0xa) ||  (bochs_info_offset == 1023)) {
-    SerialPrint("BOCHSINFO>%s", bochs_info_buf);
-    memset(bochs_info_buf, 0, 1024);
-    bochs_info_offset = 0;
-  }
 
-  return length;
-}
-
-
-int IO_Write_to_Serial(ushort_t port, void * src, uint_t length, void * priv_data) {
- SerialPrint("Output from Guest on port %d (0x%x) Length=%d\n", port, port, length);
-  switch (length) {
-
-  case 1:
-    SerialPrint(">0x%.2x\n", *(char*)src);
-    break;
-  case 2:
-    SerialPrint(">0x%.4x\n", *(ushort_t*)src);
-    break;
-  case 4:
-    SerialPrint(">0x%.8x\n", *(uint_t*)src);
-    break;
-  default:
-    break;
-  }
-
-  //  SerialMemDump(src, length);
-  return length;
-}
-
-
-
-void BuzzVM()
-{
-  int x;
-  int j;
-  unsigned char init;
-
-#if 0  
-  __asm__ __volatile__ (
-    "popf"
-    );
-    
-#endif
-    
-  PrintBoth("Starting To Buzz\n");
-
-  init=VM_In_Byte(SPEAKER_PORT);
-
-  while (1) {
-    VM_Out_Byte(SPEAKER_PORT, init|0x2);
-    for (j=0;j<1000000;j++) { 
-      x+=j;
-    }
-    VM_Out_Byte(SPEAKER_PORT, init);
-    for (j=0;j<1000000;j++) { 
-      x+=j;
-    }
-  }
-}
-
-
-/*
-int passthrough_mem_read(void * guest_addr, void * dst, uint_t length, void * priv_data) {
-  memcpy(dst, (void*)guest_addr, length);
-  return length;
-}
-
-int passthrough_mem_write(void * guest_addr, void * src, uint_t length, void * priv_data) {
-  memcpy((void*)guest_addr, src, length);
-  return length;
-}
-*/
+extern void * g_ramdiskImage;
+extern ulong_t s_ramdiskSize;
 
 
-/* We need a configuration mechanism, so we can wrap this completely inside the VMM code, 
- * with no pollution into the HOST OS
- */
-
 int RunVMM(struct Boot_Info * bootInfo) {
-  struct vmm_os_hooks os_hooks;
-  struct vmm_ctrl_ops vmm_ops;
+  struct v3_os_hooks os_hooks;
+  struct v3_ctrl_ops v3_ops;
   struct guest_info * vm_info = 0;
   struct v3_vm_config vm_config;
+  void * region_start;
 
-
-  
-  memset(&os_hooks, 0, sizeof(struct vmm_os_hooks));
-  memset(&vmm_ops, 0, sizeof(struct vmm_ctrl_ops));
+  memset(&os_hooks, 0, sizeof(struct v3_os_hooks));
+  memset(&v3_ops, 0, sizeof(struct v3_ctrl_ops));
   memset(&vm_config, 0, sizeof(struct v3_vm_config));
 
   
@@ -234,15 +77,43 @@ int RunVMM(struct Boot_Info * bootInfo) {
 
 
   
-  Init_V3(&os_hooks, &vmm_ops);
+  Init_V3(&os_hooks, &v3_ops);
 
 
   extern char _binary___palacios_vm_kernel_start;
   PrintBoth(" Guest Load Addr: 0x%x\n", &_binary___palacios_vm_kernel_start);
+
+  struct guest_mem_layout * layout = (struct guest_mem_layout *)&_binary___palacios_vm_kernel_start;
+
+  if (layout->magic != MAGIC_CODE) {
+    
+    PrintBoth("Layout Magic Mismatch (0x%x)\n", layout->magic);
+    return -1;
+  }
+  
+  PrintBoth("%d layout regions\n", layout->num_regions);
   
-  vm_config.vm_kernel = &_binary___palacios_vm_kernel_start;
+  region_start = (void *)&(layout->regions[layout->num_regions]);
   
+  PrintBoth("region start = 0x%x\n", region_start);
   
+
+  {
+    struct layout_region * rombios = &(layout->regions[0]);
+    struct layout_region * vgabios = &(layout->regions[1]);    
+    
+    vm_config.rombios = region_start;
+    vm_config.rombios_size = rombios->length;
+    
+    region_start += rombios->length;
+    
+    vm_config.vgabios = region_start;
+    vm_config.vgabios_size = vgabios->length;
+  }
+
+
+
+
   if (g_ramdiskImage != NULL) {
     vm_config.use_ramdisk = 1;
     vm_config.ramdisk = g_ramdiskImage;
@@ -251,29 +122,21 @@ int RunVMM(struct Boot_Info * bootInfo) {
 
 
 
+  vm_info = (v3_ops).allocate_guest();
 
-  vm_info = (vmm_ops).allocate_guest();
+  Init_Stubs(vm_info);
 
   PrintBoth("Allocated Guest\n");
 
-  (vmm_ops).config_guest(vm_info, &vm_config);
+  (v3_ops).config_guest(vm_info, &vm_config);
 
   PrintBoth("Configured guest\n");
 
-
-  //v3_hook_io_port(&vm_info, 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
-  
-  //v3_hook_io_port(vm_info, 0x61, &IO_Read, &IO_Write, NULL);
-  //v3_hook_io_port(vm_info, 0x400, &IO_Read, &IO_Write_to_Serial, NULL);
-  //v3_hook_io_port(vm_info, 0x401, &IO_Read, &IO_Write_to_Serial, NULL);
-  //v3_hook_io_port(vm_info, 0x402, &IO_Read, &IO_BOCHS_info, NULL);
-  //v3_hook_io_port(vm_info, 0x403, &IO_Read, &IO_BOCHS_debug, NULL);
-  
-
-  (vmm_ops).init_guest(vm_info);
+  (v3_ops).init_guest(vm_info);
   PrintBoth("Starting Guest\n");
   //Clear_Screen();
-  (vmm_ops).start_guest(vm_info);
+
+  (v3_ops).start_guest(vm_info);
   
     return 0;
 }
index e40c8dd..e6b2610 100644 (file)
 #include <geekos/serial.h>
 #include <geekos/debug.h>
 #include <palacios/vmm.h>
+#include <palacios/vmm_host_events.h>
+
+
+struct guest_info * g_vm_guest = NULL;
+
+
+// This is the function the interface code should call to deliver
+// the interrupt to the vmm for handling
+//extern int v3_deliver_interrupt(struct guest_info * vm, struct v3_interrupt *intr);
+
+
+struct guest_info * irq_to_guest_map[256];
+
 
 
 
@@ -51,6 +64,12 @@ static inline uchar_t VM_In_Byte(ushort_t port)
 
 
 
+void Init_Stubs(struct guest_info * info) {
+  memset(irq_to_guest_map, 0, sizeof(struct guest_info *) * 256);
+  g_vm_guest = info;
+}
+
+
 
 void * Identity(void *addr) { return addr; };
 
@@ -95,13 +114,38 @@ void VMM_Free(void * addr) {
 }
 
 
-// This is the function the interface code should call to deliver
-// the interrupt to the vmm for handling
-//extern int v3_deliver_interrupt(struct guest_info * vm, struct v3_interrupt *intr);
 
+void send_key_to_vmm(unsigned char status, unsigned char scancode) {
+  struct v3_keyboard_event evt;
+
+  evt.status = status;
+  evt.scan_code = scancode;
+
+  if (g_vm_guest) {
+    v3_deliver_keyboard_event(g_vm_guest, &evt);
+  }
+}
 
-struct guest_info * irq_to_guest_map[256];
 
+void send_mouse_to_vmm(unsigned char packet[3]) {
+  struct v3_mouse_event evt;
+
+  memcpy(evt.data, packet, 3);
+
+  if (g_vm_guest) {
+    v3_deliver_mouse_event(g_vm_guest, &evt);
+  }
+}
+
+void send_tick_to_vmm(unsigned int period_us) {
+  struct v3_timer_event evt;
+
+  evt.period_us = period_us;
+
+  if (g_vm_guest) {
+    v3_deliver_timer_event(g_vm_guest, &evt);
+  }
+}
 
 
 void translate_intr_handler(struct Interrupt_State *state) {
@@ -144,9 +188,6 @@ int ack_irq(int irq) {
 }
 
   
-void Init_Stubs() {
-  memset(irq_to_guest_map, 0, sizeof(struct guest_info *) * 256);
-}
 
 
 unsigned int get_cpu_khz() {
@@ -159,3 +200,4 @@ unsigned int get_cpu_khz() {
   return cpu_khz_freq;
 }
 
+
diff --git a/kitten/.hgignore b/kitten/.hgignore
new file mode 100644 (file)
index 0000000..841a071
--- /dev/null
@@ -0,0 +1,46 @@
+# use glob syntax.
+syntax: glob
+
+*.o
+*.cmd
+*.out
+vmlwk
+vmlwk.*
+System.map
+*.swp
+.config
+.config.old
+.kconfig.d
+.version
+.kernelrelease
+patch
+out
+lib.a
+*.iso
+arch/x86_64/boot/bootsect
+arch/x86_64/boot/bzImage
+arch/x86_64/boot/setup
+arch/x86_64/boot/tools/build
+arch/x86_64/kernel/asm-offsets.s
+bochs/bochsout.txt
+include/arch-x86_64/asm-offsets.h
+include/lwk/autoconf.h
+include/lwk/compile.h
+include/lwk/version.h
+scripts/basic/docproc
+scripts/basic/fixdep
+scripts/basic/split-include
+scripts/kconfig/conf
+scripts/kconfig/lex.zconf.c
+scripts/kconfig/zconf.hash.c
+scripts/kconfig/zconf.tab.c
+scripts/kallsyms
+.tmp_*
+include/arch
+init_task
+user/hello_world/hello_world
+user/liblwk/liblwk.a
+
+
+syntax: regexp
+^include/config
diff --git a/kitten/COPYING b/kitten/COPYING
new file mode 100644 (file)
index 0000000..62fe70d
--- /dev/null
@@ -0,0 +1,372 @@
+Kitten is derived from the Linux kernel and is licensed under the same
+GPL v2 license as the Linux kernel.  The full Linux COPYING file is
+listed below and applies to the Kitten kernel.  Most of the user space
+programs and libraries in the /user directory are licensed under the
+LGPL (each directory should have its own COPYING file).
+
+Files containing:
+
+  /* Copyright (c) 2008, Sandia National Laboratories */
+
+or similar (year(s) changed) have been either written solely by Sandia
+National Laboratories or significantly modified from the source code
+upon which the file is derived.  When a file is derived from other
+source code, the original copyright headers and license are maintained.
+
+----------------------------------------
+
+   NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the Linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+ Also note that the only valid version of the GPL as far as the kernel
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+                       Linus Torvalds
+
+----------------------------------------
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kitten/CREDITS b/kitten/CREDITS
new file mode 100644 (file)
index 0000000..1a4baf5
--- /dev/null
@@ -0,0 +1 @@
+  
diff --git a/kitten/Kbuild b/kitten/Kbuild
new file mode 100644 (file)
index 0000000..f4b8197
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# Kbuild for top-level directory of the kernel
+# This file takes care of the following:
+# 1) Generate asm-offsets.h
+
+#####
+# 1) Generate asm-offsets.h
+#
+
+offsets-file := include/arch-$(ARCH)/asm-offsets.h
+
+always  := $(offsets-file)
+targets := $(offsets-file)
+targets += arch/$(ARCH)/kernel/asm-offsets.s
+
+# Default sed regexp - multiline due to syntax constraints
+define sed-y
+       "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
+endef
+# Override default regexp for specific architectures
+sed-$(CONFIG_MIPS) := "/^@@@/{s/^@@@//; s/ \#.*\$$//; p;}"
+
+quiet_cmd_offsets = GEN     $@
+define cmd_offsets
+       (set -e; \
+        echo "#ifndef __ASM_OFFSETS_H__"; \
+        echo "#define __ASM_OFFSETS_H__"; \
+        echo "/*"; \
+        echo " * DO NOT MODIFY."; \
+        echo " *"; \
+        echo " * This file was generated by $(srctree)/Kbuild"; \
+        echo " *"; \
+        echo " */"; \
+        echo ""; \
+        sed -ne $(sed-y) $<; \
+        echo ""; \
+        echo "#endif" ) > $@
+endef
+
+# We use internal kbuild rules to avoid the "is up to date" message from make
+arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE
+       $(Q)mkdir -p $(dir $@)
+       $(call if_changed_dep,cc_s_c)
+
+$(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild
+       $(Q)mkdir -p $(dir $@)
+       $(call cmd,offsets)
+
diff --git a/kitten/Makefile b/kitten/Makefile
new file mode 100644 (file)
index 0000000..3407681
--- /dev/null
@@ -0,0 +1,1405 @@
+VERSION = 1
+PATCHLEVEL = 0
+SUBLEVEL = 0
+EXTRAVERSION = Kitten
+NAME=Kitten
+
+
+# *DOCUMENTATION*
+# To see a list of typical targets execute "make help"
+# More info can be located in ./README
+# Comments in this file are targeted only to the developer, do not
+# expect to learn how to build the kernel reading this file.
+
+# Do not print "Entering directory ..."
+MAKEFLAGS += --no-print-directory
+
+# We are using a recursive build, so we need to do a little thinking
+# to get the ordering right.
+#
+# Most importantly: sub-Makefiles should only ever modify files in
+# their own directory. If in some directory we have a dependency on
+# a file in another dir (which doesn't happen often, but it's often
+# unavoidable when linking the built-in.o targets which finally
+# turn into vmlwk), we will call a sub make in that other dir, and
+# after that we are sure that everything which is in that other dir
+# is now up to date.
+#
+# The only cases where we need to modify files which have global
+# effects are thus separated out and done before the recursive
+# descending is started. They are now explicitly listed as the
+# prepare rule.
+
+# To put more focus on warnings, be less verbose as default
+# Use 'make V=1' to see the full commands
+
+ifdef V
+  ifeq ("$(origin V)", "command line")
+    KBUILD_VERBOSE = $(V)
+  endif
+endif
+ifndef KBUILD_VERBOSE
+  KBUILD_VERBOSE = 0
+endif
+
+# Call sparse as part of compilation of C files
+# Use 'make C=1' to enable sparse checking
+
+ifdef C
+  ifeq ("$(origin C)", "command line")
+    KBUILD_CHECKSRC = $(C)
+  endif
+endif
+ifndef KBUILD_CHECKSRC
+  KBUILD_CHECKSRC = 0
+endif
+
+# Use make M=dir to specify directory of external module to build
+# Old syntax make ... SUBDIRS=$PWD is still supported
+# Setting the environment variable KBUILD_EXTMOD take precedence
+ifdef SUBDIRS
+  KBUILD_EXTMOD ?= $(SUBDIRS)
+endif
+ifdef M
+  ifeq ("$(origin M)", "command line")
+    KBUILD_EXTMOD := $(M)
+  endif
+endif
+
+
+# kbuild supports saving output files in a separate directory.
+# To locate output files in a separate directory two syntaxes are supported.
+# In both cases the working directory must be the root of the kernel src.
+# 1) O=
+# Use "make O=dir/to/store/output/files/"
+# 
+# 2) Set KBUILD_OUTPUT
+# Set the environment variable KBUILD_OUTPUT to point to the directory
+# where the output files shall be placed.
+# export KBUILD_OUTPUT=dir/to/store/output/files/
+# make
+#
+# The O= assignment takes precedence over the KBUILD_OUTPUT environment
+# variable.
+
+
+# KBUILD_SRC is set on invocation of make in OBJ directory
+# KBUILD_SRC is not intended to be used by the regular user (for now)
+ifeq ($(KBUILD_SRC),)
+
+# OK, Make called in directory where kernel src resides
+# Do we want to locate output files in a separate directory?
+ifdef O
+  ifeq ("$(origin O)", "command line")
+    KBUILD_OUTPUT := $(O)
+  endif
+endif
+
+# That's our default target when none is given on the command line
+PHONY := _all
+_all:
+
+ifneq ($(KBUILD_OUTPUT),)
+# Invoke a second make in the output directory, passing relevant variables
+# check that the output directory actually exists
+saved-output := $(KBUILD_OUTPUT)
+KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)
+$(if $(KBUILD_OUTPUT),, \
+     $(error output directory "$(saved-output)" does not exist))
+
+PHONY += $(MAKECMDGOALS)
+
+$(filter-out _all,$(MAKECMDGOALS)) _all:
+       $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
+       KBUILD_SRC=$(CURDIR) \
+       KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@
+
+# Leave processing to above invocation of make
+skip-makefile := 1
+endif # ifneq ($(KBUILD_OUTPUT),)
+endif # ifeq ($(KBUILD_SRC),)
+
+# We process the rest of the Makefile if this is the final invocation of make
+ifeq ($(skip-makefile),)
+
+# If building an external module we do not care about the all: rule
+# but instead _all depend on modules
+PHONY += all
+ifeq ($(KBUILD_EXTMOD),)
+_all: all
+else
+_all: modules
+endif
+
+srctree                := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
+TOPDIR         := $(srctree)
+# FIXME - TOPDIR is obsolete, use srctree/objtree
+objtree                := $(CURDIR)
+src            := $(srctree)
+obj            := $(objtree)
+
+VPATH          := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
+
+export srctree objtree VPATH TOPDIR
+
+
+# SUBARCH tells the usermode build what the underlying arch is.  That is set
+# first, and if a usermode build is happening, the "ARCH=um" on the command
+# line overrides the setting of ARCH below.  If a native build is happening,
+# then ARCH is assigned, getting whatever value it gets normally, and 
+# SUBARCH is subsequently ignored.
+
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+                                 -e s/arm.*/arm/ -e s/sa110/arm/ \
+                                 -e s/s390x/s390/ -e s/parisc64/parisc/ \
+                                 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
+
+# Cross compiling and selecting different set of gcc/bin-utils
+# ---------------------------------------------------------------------------
+#
+# When performing cross compilation for other architectures ARCH shall be set
+# to the target architecture. (See arch/* for the possibilities).
+# ARCH can be set during invocation of make:
+# make ARCH=ia64
+# Another way is to have ARCH set in the environment.
+# The default ARCH is the host where make is executed.
+
+# CROSS_COMPILE specify the prefix used for all executables used
+# during compilation. Only gcc and related bin-utils executables
+# are prefixed with $(CROSS_COMPILE).
+# CROSS_COMPILE can be set on the command line
+# make CROSS_COMPILE=ia64-linux-
+# Alternatively CROSS_COMPILE can be set in the environment.
+# Default value for CROSS_COMPILE is not to prefix executables
+# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+
+ARCH           ?= $(SUBARCH)
+CROSS_COMPILE  ?=
+
+# Architecture as present in compile.h
+UTS_MACHINE := $(ARCH)
+
+# SHELL used by kbuild
+CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+         else if [ -x /bin/bash ]; then echo /bin/bash; \
+         else echo sh; fi ; fi)
+
+HOSTCC         = gcc
+HOSTCXX        = g++
+HOSTCFLAGS     = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCXXFLAGS   = -O2
+
+#      Decide whether to build built-in, modular, or both.
+#      Normally, just do built-in.
+
+KBUILD_MODULES :=
+KBUILD_BUILTIN := 1
+
+#      If we have only "make modules", don't compile built-in objects.
+#      When we're building modules with modversions, we need to consider
+#      the built-in objects during the descend as well, in order to
+#      make sure the checksums are uptodate before we record them.
+
+ifeq ($(MAKECMDGOALS),modules)
+  KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
+endif
+
+#      If we have "make <whatever> modules", compile modules
+#      in addition to whatever we do anyway.
+#      Just "make" or "make all" shall build modules as well
+
+ifneq ($(filter all _all modules,$(MAKECMDGOALS)),)
+  KBUILD_MODULES := 1
+endif
+
+ifeq ($(MAKECMDGOALS),)
+  KBUILD_MODULES := 1
+endif
+
+export KBUILD_MODULES KBUILD_BUILTIN
+export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
+
+# Beautify output
+# ---------------------------------------------------------------------------
+#
+# Normally, we echo the whole command before executing it. By making
+# that echo $($(quiet)$(cmd)), we now have the possibility to set
+# $(quiet) to choose other forms of output instead, e.g.
+#
+#         quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
+#         cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
+#
+# If $(quiet) is empty, the whole command will be printed.
+# If it is set to "quiet_", only the short version will be printed. 
+# If it is set to "silent_", nothing wil be printed at all, since
+# the variable $(silent_cmd_cc_o_c) doesn't exist.
+#
+# A simple variant is to prefix commands with $(Q) - that's useful
+# for commands that shall be hidden in non-verbose mode.
+#
+#      $(Q)ln $@ :<
+#
+# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
+# If KBUILD_VERBOSE equals 1 then the above command is displayed.
+
+ifeq ($(KBUILD_VERBOSE),1)
+  quiet =
+  Q =
+else
+  quiet=quiet_
+  Q = @
+endif
+
+# If the user is running make -s (silent mode), suppress echoing of
+# commands
+
+ifneq ($(findstring s,$(MAKEFLAGS)),)
+  quiet=silent_
+endif
+
+export quiet Q KBUILD_VERBOSE
+
+
+# Look for make include files relative to root of kernel src
+MAKEFLAGS += --include-dir=$(srctree)
+
+# We need some generic definitions
+include  $(srctree)/scripts/Kbuild.include
+
+# For maximum performance (+ possibly random breakage, uncomment
+# the following)
+
+#MAKEFLAGS += -rR
+
+# Make variables (CC, etc...)
+
+AS             = $(CROSS_COMPILE)as
+LD             = $(CROSS_COMPILE)ld
+CC             = $(CROSS_COMPILE)gcc
+CPP            = $(CC) -E
+AR             = $(CROSS_COMPILE)ar
+NM             = $(CROSS_COMPILE)nm
+STRIP          = $(CROSS_COMPILE)strip
+OBJCOPY                = $(CROSS_COMPILE)objcopy
+OBJDUMP                = $(CROSS_COMPILE)objdump
+AWK            = awk
+GENKSYMS       = scripts/genksyms/genksyms
+DEPMOD         = /sbin/depmod
+KALLSYMS       = scripts/kallsyms
+PERL           = perl
+CHECK          = sparse
+
+CHECKFLAGS     := -D__lwk__ -Dlwk -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF)
+MODFLAGS       = -DMODULE
+CFLAGS_MODULE   = $(MODFLAGS)
+AFLAGS_MODULE   = $(MODFLAGS)
+LDFLAGS_MODULE  = -r
+CFLAGS_KERNEL  =
+AFLAGS_KERNEL  =
+
+
+# Use LWKINCLUDE when you must reference the include/ directory.
+# Needed to be compatible with the O= option
+LWKINCLUDE      := -Iinclude \
+                   $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
+                  -include include/lwk/autoconf.h
+
+CPPFLAGS        := -D__KERNEL__ $(LWKINCLUDE)
+
+CFLAGS                 := -std=gnu99 \
+                  -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
+                  -fno-strict-aliasing -fno-common
+
+ifeq ($(call cc-option-yn, -fstack-protector),y)
+CFLAGS         += -fno-stack-protector
+endif
+
+ifeq ($(call cc-option-yn, -fgnu89-inline),y)
+CFLAGS         += -fgnu89-inline
+endif
+
+AFLAGS         := -D__ASSEMBLY__
+
+# Read KERNELRELEASE from .kernelrelease (if it exists)
+KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null)
+KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
+export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \
+       ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
+       CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \
+       HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
+
+export CPPFLAGS NOSTDINC_FLAGS LWKINCLUDE OBJCOPYFLAGS LDFLAGS
+export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE 
+export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
+
+# When compiling out-of-tree modules, put MODVERDIR in the module
+# tree rather than in the kernel tree. The kernel tree might
+# even be read-only.
+export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
+
+# Files to ignore in find ... statements
+
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o
+export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git
+
+# ===========================================================================
+# Rules shared between *config targets and build targets
+
+# Basic helpers built in scripts/
+PHONY += scripts_basic
+scripts_basic:
+       $(Q)$(MAKE) $(build)=scripts/basic
+
+# To avoid any implicit rule to kick in, define an empty command.
+scripts/basic/%: scripts_basic ;
+
+PHONY += outputmakefile
+# outputmakefile generates a Makefile in the output directory, if using a
+# separate output directory. This allows convenient use of make in the
+# output directory.
+outputmakefile:
+ifneq ($(KBUILD_SRC),)
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
+           $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
+endif
+
+# To make sure we do not include .config for any of the *config targets
+# catch them early, and hand them over to scripts/kconfig/Makefile
+# It is allowed to specify more targets when calling make, including
+# mixing *config targets and build targets.
+# For example 'make oldconfig all'. 
+# Detect when mixed targets is specified, and make a second invocation
+# of make so .config is not included in this case either (for *config).
+
+no-dot-config-targets := clean mrproper distclean \
+                        cscope TAGS tags help %docs check%
+
+config-targets := 0
+mixed-targets  := 0
+dot-config     := 1
+
+ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
+       ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
+               dot-config := 0
+       endif
+endif
+
+ifeq ($(KBUILD_EXTMOD),)
+        ifneq ($(filter config %config,$(MAKECMDGOALS)),)
+                config-targets := 1
+                ifneq ($(filter-out config %config,$(MAKECMDGOALS)),)
+                        mixed-targets := 1
+                endif
+        endif
+endif
+
+ifeq ($(mixed-targets),1)
+# ===========================================================================
+# We're called with mixed targets (*config and build targets).
+# Handle them one by one.
+
+%:: FORCE
+       $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
+
+else
+ifeq ($(config-targets),1)
+# ===========================================================================
+# *config targets only - make sure prerequisites are updated, and descend
+# in scripts/kconfig to make the *config target
+
+# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed.
+# KBUILD_DEFCONFIG may point out an alternative default configuration
+# used for 'make defconfig'
+include $(srctree)/arch/$(ARCH)/Makefile
+export KBUILD_DEFCONFIG
+
+config %config: scripts_basic outputmakefile FORCE
+       $(Q)mkdir -p include/lwk
+       $(Q)$(MAKE) $(build)=scripts/kconfig $@
+       $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease
+
+else
+# ===========================================================================
+# Build targets only - this includes vmlwk, arch specific targets, clean
+# targets and others. In general all targets except *config targets.
+
+ifeq ($(KBUILD_EXTMOD),)
+# Additional helpers built in scripts/
+# Carefully list dependencies so we do not try to build scripts twice
+# in parrallel
+PHONY += scripts
+scripts: scripts_basic include/config/MARKER
+       $(Q)$(MAKE) $(build)=$(@)
+
+scripts_basic: include/lwk/autoconf.h
+
+# Objects we will link into vmlwk / subdirs we need to visit
+init-y         := init/
+drivers-y      := drivers/
+#net-y         := net/
+libs-y         := lib/
+#core-y                := usr/
+endif # KBUILD_EXTMOD
+
+ifeq ($(dot-config),1)
+# In this section, we need .config
+
+# Read in dependencies to all Kconfig* files, make sure to run
+# oldconfig if changes are detected.
+-include .kconfig.d
+
+include .config
+
+# If .config needs to be updated, it will be done via the dependency
+# that autoconf has on .config.
+# To avoid any implicit rule to kick in, define an empty command
+.config .kconfig.d: ;
+
+# If .config is newer than include/lwk/autoconf.h, someone tinkered
+# with it and forgot to run make oldconfig.
+# If kconfig.d is missing then we are probarly in a cleaned tree so
+# we execute the config step to be sure to catch updated Kconfig files
+include/lwk/autoconf.h: .kconfig.d .config
+       $(Q)mkdir -p include/lwk
+       $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
+else
+# Dummy target needed, because used as prerequisite
+include/lwk/autoconf.h: ;
+endif
+
+DEFAULT_EXTRA_TARGETS=vmlwk.bin vmlwk.asm init_task
+
+# The all: target is the default when no target is given on the
+# command line.
+# This allow a user to issue only 'make' to build a kernel including modules
+# Defaults vmlwk but it is usually overriden in the arch makefile
+all: vmlwk $(DEFAULT_EXTRA_TARGETS)
+
+ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+CFLAGS         += -Os
+else
+CFLAGS         += -O2
+endif
+
+ifdef CONFIG_FRAME_POINTER
+CFLAGS         += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+else
+CFLAGS         += -fomit-frame-pointer
+endif
+
+ifdef CONFIG_UNWIND_INFO
+CFLAGS         += -fasynchronous-unwind-tables
+endif
+
+ifdef CONFIG_DEBUG_INFO
+CFLAGS         += -g
+endif
+
+ifdef CONFIG_V3VEE
+CFLAGS += -I../palacios/include
+endif
+
+
+include $(srctree)/arch/$(ARCH)/Makefile
+
+# arch Makefile may override CC so keep this after arch Makefile is included
+NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+CHECKFLAGS     += $(NOSTDINC_FLAGS)
+
+# disable pointer signedness warnings in gcc 4.0
+CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+
+# Default kernel image to build when no specific target is given.
+# KBUILD_IMAGE may be overruled on the commandline or
+# set in the environment
+# Also any assignments in arch/$(ARCH)/Makefile take precedence over
+# this default value
+export KBUILD_IMAGE ?= vmlwk
+
+#
+# INSTALL_PATH specifies where to place the updated kernel and system map
+# images. Default is /boot, but you can set it to other values
+export INSTALL_PATH ?= /boot
+
+#
+# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
+# relocations required by build roots.  This is not defined in the
+# makefile but the arguement can be passed to make if needed.
+#
+
+MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+export MODLIB
+
+
+ifeq ($(KBUILD_EXTMOD),)
+#core-y                += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y         += kernel/ mm/
+core-$(CONFIG_V3VEE) += palacios-glue/
+
+vmlwk-dirs     := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
+                    $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
+                    $(net-y) $(net-m) $(libs-y) $(libs-m)))
+
+vmlwk-alldirs  := $(sort $(vmlwk-dirs) $(patsubst %/,%,$(filter %/, \
+                    $(init-n) $(init-) \
+                    $(core-n) $(core-) $(drivers-n) $(drivers-) \
+                    $(net-n)  $(net-)  $(libs-n)    $(libs-))))
+
+init-y         := $(patsubst %/, %/built-in.o, $(init-y))
+core-y         := $(patsubst %/, %/built-in.o, $(core-y))
+drivers-y      := $(patsubst %/, %/built-in.o, $(drivers-y))
+net-y          := $(patsubst %/, %/built-in.o, $(net-y))
+libs-y1                := $(patsubst %/, %/lib.a, $(libs-y))
+libs-y2                := $(patsubst %/, %/built-in.o, $(libs-y))
+libs-y         := $(libs-y1) $(libs-y2)
+
+libs-$(CONFIG_V3VEE) += palacios/libv3vee.a
+libs-$(CONFIG_V3VEE) += palacios/libxed32e.a
+
+# Build vmlwk
+# ---------------------------------------------------------------------------
+# vmlwk is build from the objects selected by $(vmlwk-init) and
+# $(vmlwk-main). Most are built-in.o files from top-level directories
+# in the kernel tree, others are specified in arch/$(ARCH)Makefile.
+# Ordering when linking is important, and $(vmlwk-init) must be first.
+#
+# vmlwk
+#   ^
+#   |
+#   +-< $(vmlwk-init)
+#   |   +--< init/version.o + more
+#   |
+#   +--< $(vmlwk-main)
+#   |    +--< driver/built-in.o mm/built-in.o + more
+#   |
+#   +-< kallsyms.o (see description in CONFIG_KALLSYMS section)
+#
+# vmlwk version (uname -v) cannot be updated during normal
+# descending-into-subdirs phase since we do not yet know if we need to
+# update vmlwk.
+# Therefore this step is delayed until just before final link of vmlwk -
+# except in the kallsyms case where it is done just before adding the
+# symbols to the kernel.
+#
+# System.map is generated to document addresses of all kernel symbols
+
+vmlwk-init := $(head-y) $(init-y)
+vmlwk-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
+vmlwk-all  := $(vmlwk-init) $(vmlwk-main)
+vmlwk-lds  := arch/$(ARCH)/kernel/vmlwk.lds
+
+# Rule to link vmlwk - also used during CONFIG_KALLSYMS
+# May be overridden by arch/$(ARCH)/Makefile
+quiet_cmd_vmlwk__ ?= LD      $@
+      cmd_vmlwk__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlwk) -o $@   \
+      -T $(vmlwk-lds) $(vmlwk-init)                            \
+      --start-group $(vmlwk-main) --end-group                  \
+      $(filter-out $(vmlwk-lds) $(vmlwk-init) $(vmlwk-main) FORCE ,$^)
+
+# Generate new vmlwk version
+quiet_cmd_vmlwk_version = GEN     .version
+      cmd_vmlwk_version = set -e;                       \
+       if [ ! -r .version ]; then                      \
+         rm -f .version;                               \
+         echo 1 >.version;                             \
+       else                                            \
+         mv .version .old_version;                     \
+         expr 0$$(cat .old_version) + 1 >.version;     \
+       fi;                                             \
+       $(MAKE) $(build)=init
+
+# Generate System.map
+quiet_cmd_sysmap = SYSMAP 
+      cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
+
+# Link of vmlwk
+# If CONFIG_KALLSYMS is set .version is already updated
+# Generate System.map and verify that the content is consistent
+# Use + in front of the vmlwk_version rule to silent warning with make -j2
+# First command is ':' to allow us to use + in front of the rule
+define rule_vmlwk__
+       :
+       $(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlwk_version))
+
+       $(call cmd,vmlwk__)
+       $(Q)echo 'cmd_$@ := $(cmd_vmlwk__)' > $(@D)/.$(@F).cmd
+
+       $(Q)$(if $($(quiet)cmd_sysmap),                 \
+         echo '  $($(quiet)cmd_sysmap) System.map' &&) \
+       $(cmd_sysmap) $@ System.map;                    \
+       if [ $$? -ne 0 ]; then                          \
+               rm -f $@;                               \
+               /bin/false;                             \
+       fi;
+       $(verify_kallsyms)
+endef
+
+
+ifdef CONFIG_KALLSYMS
+# Generate section listing all symbols and add it into vmlwk $(kallsyms.o)
+# It's a three stage process:
+# o .tmp_vmlwk1 has all symbols and sections, but __kallsyms is
+#   empty
+#   Running kallsyms on that gives us .tmp_kallsyms1.o with
+#   the right size - vmlwk version (uname -v) is updated during this step
+# o .tmp_vmlwk2 now has a __kallsyms section of the right size,
+#   but due to the added section, some addresses have shifted.
+#   From here, we generate a correct .tmp_kallsyms2.o
+# o The correct .tmp_kallsyms2.o is linked into the final vmlwk.
+# o Verify that the System.map from vmlwk matches the map from
+#   .tmp_vmlwk2, just in case we did not generate kallsyms correctly.
+# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+#   .tmp_vmlwk3 and .tmp_kallsyms3.o.  This is only meant as a
+#   temporary bypass to allow the kernel to be built while the
+#   maintainers work out what went wrong with kallsyms.
+
+ifdef CONFIG_KALLSYMS_EXTRA_PASS
+last_kallsyms := 3
+else
+last_kallsyms := 2
+endif
+
+kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
+
+define verify_kallsyms
+       $(Q)$(if $($(quiet)cmd_sysmap),                       \
+         echo '  $($(quiet)cmd_sysmap) .tmp_System.map' &&)  \
+         $(cmd_sysmap) .tmp_vmlwk$(last_kallsyms) .tmp_System.map
+       $(Q)cmp -s System.map .tmp_System.map ||              \
+               (echo Inconsistent kallsyms data;             \
+                echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \
+                rm .tmp_kallsyms* ; /bin/false )
+endef
+
+# Update vmlwk version before link
+# Use + in front of this rule to silent warning about make -j1
+# First command is ':' to allow us to use + in front of this rule
+cmd_ksym_ld = $(cmd_vmlwk__)
+define rule_ksym_ld
+       : 
+       +$(call cmd,vmlwk_version)
+       $(call cmd,vmlwk__)
+       $(Q)echo 'cmd_$@ := $(cmd_vmlwk__)' > $(@D)/.$(@F).cmd
+endef
+
+# Generate .S file with all kernel symbols
+quiet_cmd_kallsyms = KSYM    $@
+      cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+                     $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
+
+.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
+       $(call if_changed_dep,as_o_S)
+
+.tmp_kallsyms%.S: .tmp_vmlwk% $(KALLSYMS)
+       $(call cmd,kallsyms)
+
+# .tmp_vmlwk1 must be complete except kallsyms, so update vmlwk version
+.tmp_vmlwk1: $(vmlwk-lds) $(vmlwk-all) FORCE
+       $(call if_changed_rule,ksym_ld)
+
+.tmp_vmlwk2: $(vmlwk-lds) $(vmlwk-all) .tmp_kallsyms1.o FORCE
+       $(call if_changed,vmlwk__)
+
+.tmp_vmlwk3: $(vmlwk-lds) $(vmlwk-all) .tmp_kallsyms2.o FORCE
+       $(call if_changed,vmlwk__)
+
+# Needs to visit scripts/ before $(KALLSYMS) can be used.
+$(KALLSYMS): scripts ;
+
+# Generate some data for debugging strange kallsyms problems
+debug_kallsyms: .tmp_map$(last_kallsyms)
+
+.tmp_map%: .tmp_vmlwk% FORCE
+       ($(OBJDUMP) -h $< | $(AWK) '/^ +[0-9]/{print $$4 " 0 " $$2}'; $(NM) $<) | sort > $@
+
+.tmp_map3: .tmp_map2
+
+.tmp_map2: .tmp_map1
+
+endif # ifdef CONFIG_KALLSYMS
+
+# vmlwk image - including updated kernel symbols
+vmlwk: $(vmlwk-lds) $(vmlwk-init) $(vmlwk-main) $(kallsyms.o) FORCE
+       $(call if_changed_rule,vmlwk__)
+       $(Q)rm -f .old_version
+
+vmlwk.bin: vmlwk FORCE
+       $(OBJCOPY) -O binary $< $@
+
+vmlwk.asm: vmlwk
+       $(OBJDUMP) --disassemble $< > $@
+
+# The actual objects are generated when descending, 
+# make sure no implicit rule kicks in
+$(sort $(vmlwk-init) $(vmlwk-main)) $(vmlwk-lds): $(vmlwk-dirs) ;
+
+# Handle descending into subdirectories listed in $(vmlwk-dirs)
+# Preset locale variables to speed up the build process. Limit locale
+# tweaks to this spot to avoid wrong language settings when running
+# make menuconfig etc.
+# Error messages still appears in the original language
+
+PHONY += $(vmlwk-dirs)
+$(vmlwk-dirs): prepare scripts
+       $(Q)$(MAKE) $(build)=$@
+
+# Build the kernel release string
+# The KERNELRELEASE is stored in a file named .kernelrelease
+# to be used when executing for example make install or make modules_install
+#
+# Take the contents of any files called localversion* and the config
+# variable CONFIG_LOCALVERSION and append them to KERNELRELEASE.
+# LOCALVERSION from the command line override all of this
+
+nullstring :=
+space      := $(nullstring) # end of line
+
+___localver = $(objtree)/localversion* $(srctree)/localversion*
+__localver  = $(sort $(wildcard $(___localver)))
+# skip backup files (containing '~')
+_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f)))
+
+localver = $(subst $(space),, \
+          $(shell cat /dev/null $(_localver)) \
+          $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+              
+# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
+# and if the SCM is know a tag from the SCM is appended.
+# The appended tag is determinded by the SCM used.
+#
+# Currently, only git is supported.
+# Other SCMs can edit scripts/setlocalversion and add the appropriate
+# checks as needed.
+ifdef CONFIG_LOCALVERSION_AUTO
+       _localver-auto = $(shell $(CONFIG_SHELL) \
+                         $(srctree)/scripts/setlocalversion $(srctree))
+       localver-auto  = $(LOCALVERSION)$(_localver-auto)
+endif
+
+localver-full = $(localver)$(localver-auto)
+
+# Store (new) KERNELRELASE string in .kernelrelease
+kernelrelease = $(KERNELVERSION)$(localver-full)
+.kernelrelease: FORCE
+       $(Q)rm -f $@
+       $(Q)echo $(kernelrelease) > $@
+
+
+# Things we need to do before we recursively start building the kernel
+# or the modules are listed in "prepare".
+# A multi level approach is used. prepareN is processed before prepareN-1.
+# archprepare is used in arch Makefiles and when processed arch symlink,
+# version.h and scripts_basic is processed / created.
+
+# Listed in dependency order
+PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3
+
+# prepare-all is deprecated, use prepare as valid replacement
+PHONY += prepare-all
+
+# prepare3 is used to check if we are building in a separate output directory,
+# and if so do:
+# 1) Check that make has not been executed in the kernel src $(srctree)
+# 2) Create the include2 directory, used for the second arch symlink
+prepare3: .kernelrelease
+ifneq ($(KBUILD_SRC),)
+       @echo '  Using $(srctree) as source for kernel'
+       $(Q)if [ -f $(srctree)/.config ]; then \
+               echo "  $(srctree) is not clean, please run 'make mrproper'";\
+               echo "  in the '$(srctree)' directory.";\
+               /bin/false; \
+       fi;
+       $(Q)if [ ! -d include2 ]; then mkdir -p include2; fi;
+       $(Q)ln -fsn $(srctree)/include/arch-$(ARCH) include2/arch
+endif
+
+# prepare2 creates a makefile if using a separate output directory
+prepare2: prepare3 outputmakefile
+
+prepare1: prepare2 include/lwk/version.h include/arch \
+                   include/config/MARKER
+ifneq ($(KBUILD_MODULES),)
+       $(Q)mkdir -p $(MODVERDIR)
+       $(Q)rm -f $(MODVERDIR)/*
+endif
+
+archprepare: prepare1 scripts_basic
+
+prepare0: archprepare FORCE
+       $(Q)$(MAKE) $(build)=.
+
+# All the preparing..
+prepare prepare-all: prepare0
+
+#      Leave this as default for preprocessing vmlwk.lds.S, which is now
+#      done in arch/$(ARCH)/kernel/Makefile
+
+export CPPFLAGS_vmlwk.lds += -P -C -U$(ARCH)
+
+#      FIXME: The arch symlink changes when $(ARCH) changes. That's
+#      hard to detect, but I suppose "make mrproper" is a good idea
+#      before switching between archs anyway.
+
+include/arch:
+       @echo '  SYMLINK $@ -> include/arch-$(ARCH)'
+       $(Q)if [ ! -d include ]; then mkdir -p include; fi;
+       @ln -fsn arch-$(ARCH) $@
+
+#      Split autoconf.h into include/lwk/config/*
+
+include/config/MARKER: scripts/basic/split-include include/lwk/autoconf.h
+       @echo '  SPLIT   include/lwk/autoconf.h -> include/config/*'
+       @scripts/basic/split-include include/lwk/autoconf.h include/config
+       @touch $@
+
+# Generate some files
+# ---------------------------------------------------------------------------
+
+# KERNELRELEASE can change from a few different places, meaning version.h
+# needs to be updated, so this check is forced on all builds
+
+uts_len := 64
+
+define filechk_version.h
+       if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
+         echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
+         exit 1; \
+       fi; \
+       (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\"; \
+         echo \#define LWK_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)`; \
+        echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'; \
+       )
+endef
+
+include/lwk/version.h: $(srctree)/Makefile .config .kernelrelease FORCE
+       $(call filechk,version.h)
+
+# ---------------------------------------------------------------------------
+
+PHONY += depend dep
+depend dep:
+       @echo '*** Warning: make $@ is unnecessary now.'
+
+# ---------------------------------------------------------------------------
+# Kernel headers
+INSTALL_HDR_PATH=$(MODLIB)/abi
+export INSTALL_HDR_PATH
+
+PHONY += headers_install
+headers_install: include/lwk/version.h
+       $(Q)unifdef -Ux /dev/null
+       $(Q)rm -rf $(INSTALL_HDR_PATH)/include
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.headersinst obj=include
+
+PHONY += headers_check
+headers_check: headers_install
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.headersinst obj=include HDRCHECK=1
+
+# ---------------------------------------------------------------------------
+# Modules
+
+ifdef CONFIG_MODULES
+
+#      By default, build modules as well
+
+all: modules
+
+#      Build modules
+
+PHONY += modules
+modules: $(vmlwk-dirs) $(if $(KBUILD_BUILTIN),vmlwk)
+       @echo '  Building modules, stage 2.';
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
+
+
+# Target to prepare building external modules
+PHONY += modules_prepare
+modules_prepare: prepare scripts
+
+# Target to install modules
+PHONY += modules_install
+modules_install: _modinst_ _modinst_post
+
+PHONY += _modinst_
+_modinst_:
+       @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
+               echo "Warning: you may need to install module-init-tools"; \
+               echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
+               sleep 1; \
+       fi
+       @rm -rf $(MODLIB)/kernel
+       @rm -f $(MODLIB)/source
+       @mkdir -p $(MODLIB)/kernel
+       @ln -s $(srctree) $(MODLIB)/source
+       @if [ ! $(objtree) -ef  $(MODLIB)/build ]; then \
+               rm -f $(MODLIB)/build ; \
+               ln -s $(objtree) $(MODLIB)/build ; \
+       fi
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst
+
+# If System.map exists, run depmod.  This deliberately does not have a
+# dependency on System.map since that would run the dependency tree on
+# vmlwk.  This depmod is only for convenience to give the initial
+# boot a modules.dep even before / is mounted read-write.  However the
+# boot script depmod is the master version.
+ifeq "$(strip $(INSTALL_MOD_PATH))" ""
+depmod_opts    :=
+else
+depmod_opts    := -b $(INSTALL_MOD_PATH) -r
+endif
+PHONY += _modinst_post
+_modinst_post: _modinst_
+       if [ -r System.map -a -x $(DEPMOD) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+
+else # CONFIG_MODULES
+
+# Modules not configured
+# ---------------------------------------------------------------------------
+
+modules modules_install: FORCE
+       @echo
+       @echo "The present kernel configuration has modules disabled."
+       @echo "Type 'make config' and enable loadable module support."
+       @echo "Then build a kernel with module support enabled."
+       @echo
+       @exit 1
+
+endif # CONFIG_MODULES
+
+###
+# Cleaning is done on three levels.
+# make clean     Delete most generated files
+#                Leave enough to build external modules
+# make mrproper  Delete the current configuration, and all generated files
+# make distclean Remove editor backup files, patch leftover files and the like
+
+# Directories & files removed with 'make clean'
+CLEAN_DIRS  += $(MODVERDIR)
+CLEAN_FILES += vmlwk System.map vmlwk.bin vmlwk.asm \
+                .tmp_kallsyms* .tmp_version .tmp_vmlwk* .tmp_System.map
+
+# Directories & files removed with 'make mrproper'
+MRPROPER_DIRS  += include/config include2
+MRPROPER_FILES += .config .config.old include/arch .version .old_version \
+                  include/lwk/autoconf.h include/lwk/version.h \
+                 .kernelrelease Module.symvers tags TAGS cscope*
+
+# clean - Delete most, but leave enough to build external modules
+#
+clean: rm-dirs  := $(CLEAN_DIRS)
+clean: rm-files := $(CLEAN_FILES)
+clean-dirs      := $(addprefix _clean_,$(srctree) $(vmlwk-alldirs))
+
+PHONY += $(clean-dirs) clean archclean
+$(clean-dirs):
+       $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
+
+clean: archclean $(clean-dirs)
+       $(call cmd,rmdirs)
+       $(call cmd,rmfiles)
+       @find . $(RCS_FIND_IGNORE) \
+               \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+               -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
+               -type f -print | xargs rm -f
+       @rm -f init_task
+
+# mrproper - Delete all generated files, including .config
+#
+mrproper: rm-dirs  := $(wildcard $(MRPROPER_DIRS))
+mrproper: rm-files := $(wildcard $(MRPROPER_FILES))
+#mrproper-dirs      := $(addprefix _mrproper_,Documentation/DocBook scripts)
+mrproper-dirs      := $(addprefix _mrproper_, scripts)
+
+PHONY += $(mrproper-dirs) mrproper archmrproper
+$(mrproper-dirs):
+       $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@)
+
+mrproper: clean archmrproper $(mrproper-dirs)
+       $(call cmd,rmdirs)
+       $(call cmd,rmfiles)
+
+# distclean
+#
+PHONY += distclean
+
+distclean: mrproper
+       @find $(srctree) $(RCS_FIND_IGNORE) \
+               \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+               -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+               -o -name '.*.rej' -o -size 0 \
+               -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
+               -type f -print | xargs rm -f
+
+
+# Packaging of the kernel to various formats
+# ---------------------------------------------------------------------------
+# rpm target kept for backward compatibility
+package-dir    := $(srctree)/scripts/package
+
+%pkg: FORCE
+       $(Q)$(MAKE) $(build)=$(package-dir) $@
+rpm: FORCE
+       $(Q)$(MAKE) $(build)=$(package-dir) $@
+
+
+# Brief documentation of the typical targets used
+# ---------------------------------------------------------------------------
+
+boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig)
+boards := $(notdir $(boards))
+
+help:
+       @echo  'Cleaning targets:'
+       @echo  '  clean           - remove most generated files but keep the config'
+       @echo  '  mrproper        - remove all generated files + config + various backup files'
+       @echo  ''
+       @echo  'Configuration targets:'
+       @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help
+       @echo  ''
+       @echo  'Other generic targets:'
+       @echo  '  all             - Build all targets marked with [*]'
+       @echo  '* vmllwk          - Build the bare kernel'
+       @echo  '* modules         - Build all modules'
+       @echo  '  modules_install - Install all modules to INSTALL_MOD_PATH (default: /)'
+       @echo  '  dir/            - Build all files in dir and below'
+       @echo  '  dir/file.[ois]  - Build specified target only'
+       @echo  '  dir/file.ko     - Build module including final link'
+       @echo  '  rpm             - Build a kernel as an RPM package'
+       @echo  '  tags/TAGS       - Generate tags file for editors'
+       @echo  '  cscope          - Generate cscope index'
+       @echo  '  kernelrelease   - Output the release version string'
+       @echo  '  kernelversion   - Output the version stored in Makefile'
+       @echo  '  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'
+       @echo  '                    (default: /lib/modules/$$VERSION/abi)'
+       @echo  ''
+       @echo  'Static analysers'
+       @echo  '  checkstack      - Generate a list of stack hogs'
+       @echo  '  namespacecheck  - Name space analysis on compiled kernel'
+       @echo  ''
+       @echo  'Kernel packaging:'
+       @$(MAKE) $(build)=$(package-dir) help
+       @echo  ''
+       @echo  'Documentation targets:'
+       @$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp
+       @echo  ''
+       @echo  'Architecture specific targets ($(ARCH)):'
+       @$(if $(archhelp),$(archhelp),\
+               echo '  No architecture specific help defined for $(ARCH)')
+       @echo  ''
+       @$(if $(boards), \
+               $(foreach b, $(boards), \
+               printf "  %-24s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \
+               echo '')
+
+       @echo  '  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
+       @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
+       @echo  '  make C=1   [targets] Check all c source with $$CHECK (sparse)'
+       @echo  '  make C=2   [targets] Force check of all c source with $$CHECK (sparse)'
+       @echo  ''
+       @echo  'Execute "make" or "make all" to build all targets marked with [*] '
+       @echo  'For further info see the ./README file'
+
+
+# Documentation targets
+# ---------------------------------------------------------------------------
+%docs: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=Documentation/DocBook $@
+
+else # KBUILD_EXTMOD
+
+###
+# External module support.
+# When building external modules the kernel used as basis is considered
+# read-only, and no consistency checks are made and the make
+# system is not used on the basis kernel. If updates are required
+# in the basis kernel ordinary make commands (without M=...) must
+# be used.
+#
+# The following are the only valid targets when building external
+# modules.
+# make M=dir clean     Delete all automatically generated files
+# make M=dir modules   Make all modules in specified dir
+# make M=dir          Same as 'make M=dir modules'
+# make M=dir modules_install
+#                      Install the modules build in the module directory
+#                      Assumes install directory is already created
+
+# We are always building modules
+KBUILD_MODULES := 1
+PHONY += crmodverdir
+crmodverdir:
+       $(Q)mkdir -p $(MODVERDIR)
+       $(Q)rm -f $(MODVERDIR)/*
+
+PHONY += $(objtree)/Module.symvers
+$(objtree)/Module.symvers:
+       @test -e $(objtree)/Module.symvers || ( \
+       echo; \
+       echo "  WARNING: Symbol version dump $(objtree)/Module.symvers"; \
+       echo "           is missing; modules will have no dependencies and modversions."; \
+       echo )
+
+module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
+PHONY += $(module-dirs) modules
+$(module-dirs): crmodverdir $(objtree)/Module.symvers
+       $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
+
+modules: $(module-dirs)
+       @echo '  Building modules, stage 2.';
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
+
+PHONY += modules_install
+modules_install: _emodinst_ _emodinst_post
+
+install-dir := $(if $(INSTALL_MOD_DIR),$(INSTALL_MOD_DIR),extra)
+PHONY += _emodinst_
+_emodinst_:
+       $(Q)mkdir -p $(MODLIB)/$(install-dir)
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst
+
+# Run depmod only is we have System.map and depmod is executable
+quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
+      cmd_depmod = if [ -r System.map -a -x $(DEPMOD) ]; then \
+                      $(DEPMOD) -ae -F System.map             \
+                      $(if $(strip $(INSTALL_MOD_PATH)),      \
+                     -b $(INSTALL_MOD_PATH) -r)              \
+                     $(KERNELRELEASE);                       \
+                   fi
+
+PHONY += _emodinst_post
+_emodinst_post: _emodinst_
+       $(call cmd,depmod)
+
+clean-dirs := $(addprefix _clean_,$(KBUILD_EXTMOD))
+
+PHONY += $(clean-dirs) clean
+$(clean-dirs):
+       $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
+
+clean: rm-dirs := $(MODVERDIR)
+clean: $(clean-dirs)
+       $(call cmd,rmdirs)
+       @find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \
+               \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+               -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
+               -type f -print | xargs rm -f
+
+help:
+       @echo  '  Building external modules.'
+       @echo  '  Syntax: make -C path/to/kernel/src M=$$PWD target'
+       @echo  ''
+       @echo  '  modules         - default target, build the module(s)'
+       @echo  '  modules_install - install the module'
+       @echo  '  clean           - remove generated files in module directory only'
+       @echo  ''
+
+# Dummies...
+PHONY += prepare scripts
+prepare: ;
+scripts: ;
+endif # KBUILD_EXTMOD
+
+# Generate tags for editors
+# ---------------------------------------------------------------------------
+
+#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set
+#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
+#Adding $(srctree) adds about 20M on i386 to the size of the output file!
+
+ifeq ($(src),$(obj))
+__srctree =
+else
+__srctree = $(srctree)/
+endif
+
+ifeq ($(ALLSOURCE_ARCHS),)
+ifeq ($(ARCH),um)
+ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH)
+else
+ALLINCLUDE_ARCHS := $(ARCH)
+endif
+else
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
+ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
+endif
+
+ALLSOURCE_ARCHS := $(ARCH)
+
+define all-sources
+       ( find $(__srctree) $(RCS_FIND_IGNORE) \
+              \( -name include -o -name arch \) -prune -o \
+              -name '*.[chS]' -print; \
+         for ARCH in $(ALLSOURCE_ARCHS) ; do \
+              find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
+                   -name '*.[chS]' -print; \
+         done ; \
+         find $(__srctree)include $(RCS_FIND_IGNORE) \
+              \( -name config -o -name 'arch-*' \) -prune \
+              -o -name '*.[chS]' -print; \
+         for ARCH in $(ALLINCLUDE_ARCHS) ; do \
+              find $(__srctree)include/arch-$${ARCH} $(RCS_FIND_IGNORE) \
+                   -name '*.[chS]' -print; \
+         done ; \
+         find $(__srctree)include/arch-generic $(RCS_FIND_IGNORE) \
+              -name '*.[chS]' -print )
+endef
+
+quiet_cmd_cscope-file = FILELST cscope.files
+      cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files
+
+quiet_cmd_cscope = MAKE    cscope.out
+      cmd_cscope = cscope -b
+
+cscope: FORCE
+       $(call cmd,cscope-file)
+       $(call cmd,cscope)
+
+quiet_cmd_TAGS = MAKE   $@
+define cmd_TAGS
+       rm -f $@; \
+       ETAGSF=`etags --version | grep -i exuberant >/dev/null &&     \
+                echo "-I __initdata,__exitdata,__acquires,__releases  \
+                      -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL              \
+                      --extra=+f --c-kinds=+px"`;                     \
+                $(all-sources) | xargs etags $$ETAGSF -a
+endef
+
+TAGS: FORCE
+       $(call cmd,TAGS)
+
+
+quiet_cmd_tags = MAKE   $@
+define cmd_tags
+       rm -f $@; \
+       CTAGSF=`ctags --version | grep -i exuberant >/dev/null &&     \
+                echo "-I __initdata,__exitdata,__acquires,__releases  \
+                      -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL              \
+                      --extra=+f --c-kinds=+px"`;                     \
+                $(all-sources) | xargs ctags $$CTAGSF -a
+endef
+
+tags: FORCE
+       $(call cmd,tags)
+
+
+# Scripts to check various things for consistency
+# ---------------------------------------------------------------------------
+
+includecheck:
+       find * $(RCS_FIND_IGNORE) \
+               -name '*.[hcS]' -type f -print | sort \
+               | xargs $(PERL) -w scripts/checkincludes.pl
+
+versioncheck:
+       find * $(RCS_FIND_IGNORE) \
+               -name '*.[hcS]' -type f -print | sort \
+               | xargs $(PERL) -w scripts/checkversion.pl
+
+namespacecheck:
+       $(PERL) $(srctree)/scripts/namespace.pl
+
+endif #ifeq ($(config-targets),1)
+endif #ifeq ($(mixed-targets),1)
+
+PHONY += checkstack
+checkstack:
+       $(OBJDUMP) -d vmlwk $$(find . -name '*.ko') | \
+       $(PERL) $(src)/scripts/checkstack.pl $(ARCH)
+
+kernelrelease:
+       $(if $(wildcard .kernelrelease), $(Q)echo $(KERNELRELEASE), \
+       $(error kernelrelease not valid - run 'make *config' to update it))
+kernelversion:
+       @echo $(KERNELVERSION)
+
+# Single targets
+# ---------------------------------------------------------------------------
+# Single targets are compatible with:
+# - build whith mixed source and output
+# - build with separate output dir 'make O=...'
+# - external modules
+#
+#  target-dir => where to store outputfile
+#  build-dir  => directory in kernel source tree to use
+
+ifeq ($(KBUILD_EXTMOD),)
+        build-dir  = $(patsubst %/,%,$(dir $@))
+        target-dir = $(dir $@)
+else
+        zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@)))
+        build-dir  = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash))
+        target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@))
+endif
+
+%.s: %.c prepare scripts FORCE
+       $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.i: %.c prepare scripts FORCE
+       $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.o: %.c prepare scripts FORCE
+       $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.lst: %.c prepare scripts FORCE
+       $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.s: %.S prepare scripts FORCE
+       $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.o: %.S prepare scripts FORCE
+       $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+
+# Modules
+/ %/: prepare scripts FORCE
+       $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
+       $(build)=$(build-dir)
+%.ko: prepare scripts FORCE
+       $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1)   \
+       $(build)=$(build-dir) $(@:.ko=.o)
+       $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
+
+# FIXME Should go into a make.lib or something 
+# ===========================================================================
+
+quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN   $(wildcard $(rm-dirs)))
+      cmd_rmdirs = rm -rf $(rm-dirs)
+
+quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN   $(wildcard $(rm-files)))
+      cmd_rmfiles = rm -f $(rm-files)
+
+
+a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(AFLAGS_KERNEL) \
+         $(NOSTDINC_FLAGS) $(CPPFLAGS) \
+         $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+
+quiet_cmd_as_o_S = AS      $@
+cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
+
+# read all saved command lines
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  $(cmd_files): ;      # Do not try to update included dependency files
+  include $(cmd_files)
+endif
+
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+endif  # skip-makefile
+
+# Build LWK user-space libraries and example programs
+user: FORCE
+       cd user/; $(MAKE) all
+
+# A simple user-space app for the LWK to launch at boot
+init_task: user FORCE
+       cp user/hello_world/hello_world ./init_task
+
+PHONY += FORCE
+FORCE:
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+.PHONY: $(PHONY)
diff --git a/kitten/README b/kitten/README
new file mode 100644 (file)
index 0000000..f89f6c0
--- /dev/null
@@ -0,0 +1,41 @@
+make config
+make
+make isoimage
+qemu-system-x86_64 -cdrom arch/x86_64/boot/image.iso -serial stdio
+
+(Can add -smp 4 option as well, but the BIOS my version of QEMU is using
+ doesn't appear to provide an MP table, which Kitten depends on.  KVM seems
+ to work fine with -smp 4 arg... all cpus are detected and initialized.)
+
+----------------------------------------------------------------------------
+
+Scripts for building cross-compiler toolchains are in scripts/toolchain.
+E.g., to build an x86-64 toolchain:
+
+       cd scripts/toolchain
+       ./build-x86_64.sh
+
+By default, the toolchain will be installed in /opt/toolchain/x86_64.
+Edit PREFIX in build-x86_64.sh to change this.
+
+To build a x86_64 Kitten using a cross-compiler:
+
+       export PATH=/opt/toolchain/x86_64/bin:$PATH
+       make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- config
+       make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu-
+
+The resulting kernel image is at:
+
+       arch/x86_64/boot/bzImage
+
+This is a drop in replacement for a Linux bzImage.
+
+If you have syslinux installed ('syslinux' Debian package), a bootable
+iso cdrom image can be built with:
+
+       make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- isoimage
+
+and booted under the Qemu full-system simulator ('qemu' Debian package):
+
+       qemu-system-x86_64 -cdrom arch/x86_64/boot/image.iso
+
diff --git a/kitten/arch/x86_64/Kconfig b/kitten/arch/x86_64/Kconfig
new file mode 100644 (file)
index 0000000..ba47c68
--- /dev/null
@@ -0,0 +1,117 @@
+mainmenu "Kitten Kernel Configuration"
+
+config x86_64
+       bool
+       default y
+       help
+         Support for the x86-64 architecture.
+
+source "init/Kconfig"
+
+menu "Target Configuration"
+
+choice
+       prompt "System Architecture"
+       default PC
+
+config PC
+        bool "PC-compatible"
+        help
+         Support for standard PC compatible systems.
+
+config CRAY_XT
+        bool "Red Storm (Cray XT3/XT4)"
+         help
+         Support for Cray XT3 and XT4 systems.
+
+endchoice
+
+
+choice
+       prompt "Processor Family"
+       default MK8
+
+config MK8
+       bool "AMD-Opteron/Athlon64"
+       help
+         Optimize for AMD Opteron/Athlon64/Hammer/K8 CPUs.
+
+config MPSC
+       bool "Intel-64/Core2"
+       help
+         Optimize for Intel 64 architecture.
+
+config GENERIC_CPU
+       bool "Generic-x86-64"
+       help
+         Generic x86-64 CPU.
+
+endchoice
+
+config V3VEE
+       bool "V3Vee abstraction layer"
+       default "n"
+       help
+         V3Vee guest OS instead of ELF image
+
+#
+# Define implied options from the CPU selection
+#
+
+config X86_L1_CACHE_BYTES
+        int
+        default "128" if GENERIC_CPU || MPSC
+        default "64" if MK8
+
+config X86_L1_CACHE_SHIFT
+        int
+        default "7" if GENERIC_CPU || MPSC
+        default "6" if MK8
+
+config X86_INTERNODE_CACHE_BYTES
+       int
+       default X86_L1_CACHE_BYTES
+
+config X86_INTERNODE_CACHE_SHIFT
+       int
+       default X86_L1_CACHE_SHIFT
+
+config NR_CPUS
+        int "Maximum number of CPUs (2-256)"
+        range 1 255
+        default "8"
+        help
+          This allows you to specify the maximum number of CPUs which this
+          kernel will support. Current maximum is 256 CPUs due to
+          APIC addressing limits. Less depending on the hardware.
+
+          This is purely to save memory - each supported CPU requires
+          memory in the static kernel configuration.
+
+#
+# Physical address where the kernel is loaded
+#
+config PHYSICAL_START
+       hex "Physical address for kernel load"
+       default "0x200000"
+
+
+
+config VGA_CONSOLE
+       bool "VGA console"
+       default "y" if PC
+
+config SERIAL_CONSOLE
+       bool "Serial console support"
+       default "y" if PC
+
+config RCAL0_CONSOLE
+       bool "Cray XT3 L0 console support"
+       default "y" if CRAY_XT
+       default "n"
+
+
+
+endmenu
+
+source "arch/x86_64/Kconfig.debug"
diff --git a/kitten/arch/x86_64/Kconfig.debug b/kitten/arch/x86_64/Kconfig.debug
new file mode 100644 (file)
index 0000000..7ad592c
--- /dev/null
@@ -0,0 +1,15 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_RODATA
+       bool "Write protect kernel read-only data structures"
+       depends on DEBUG_KERNEL
+       help
+        Mark the kernel read-only data as write-protected in the pagetables,
+        in order to catch accidental (and incorrect) writes to such const data.
+        This option may have a slight performance impact because a portion
+        of the kernel code won't be covered by a 2MB TLB anymore.
+        If in doubt, say "N".
+
+endmenu
diff --git a/kitten/arch/x86_64/Makefile b/kitten/arch/x86_64/Makefile
new file mode 100644 (file)
index 0000000..669168c
--- /dev/null
@@ -0,0 +1,85 @@
+# x86_64/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+# 19990713  Artur Skawina <skawina@geocities.com>
+#           Added '-march' and '-mpreferred-stack-boundary' support
+# 20000913  Pavel Machek <pavel@suse.cz>
+#          Converted for x86_64 architecture
+# 20010105  Andi Kleen, add IA32 compiler.
+#           ....and later removed it again....
+# 20070816  Kevin Pedretti <ktpedre@sandia.gov>
+#           Modifications for Kitten. Remove unneeded stuff.
+#
+
+LDFLAGS                := -m elf_x86_64
+OBJCOPYFLAGS   := -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux :=
+CHECKFLAGS      += -D__x86_64__ -m64
+
+cflags-y       :=
+cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
+cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
+cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
+
+cflags-y += -m64
+cflags-y += -mno-red-zone
+cflags-y += -mcmodel=kernel
+cflags-y += -pipe
+cflags-y += -ffunction-sections
+# this makes reading assembly source easier, but produces worse code
+# actually it makes the kernel smaller too.
+cflags-y += -fno-reorder-blocks
+cflags-y += -Wno-sign-compare
+cflags-y += -Wno-unused-parameter
+# -funit-at-a-time shrinks the kernel .text considerably
+# unfortunately it makes reading oopses harder.
+cflags-y += $(call cc-option,-funit-at-a-time)
+# prevent gcc from generating any FP code by mistake
+cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
+
+CFLAGS += $(cflags-y)
+AFLAGS += -m64
+
+head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
+
+libs-y += arch/x86_64/lib/
+core-y += arch/x86_64/kernel/  \
+          arch/x86_64/mm/
+
+boot := arch/x86_64/boot
+
+PHONY += bzImage archmrproper isoimage archclean
+
+#Default target when executing "make"
+all: bzImage
+
+BOOTIMAGE                     := arch/x86_64/boot/bzImage
+KBUILD_IMAGE                  := $(BOOTIMAGE)
+
+bzImage: vmlwk $(DEFAULT_EXTRA_TARGETS)
+       $(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
+
+isoimage: vmlwk $(DEFAULT_EXTRA_TARGETS)
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
+
+archclean:
+       $(Q)$(MAKE) $(clean)=$(boot)
+
+define archhelp
+  echo  '* bzImage     - Compressed kernel image (arch/$(ARCH)/boot/bzImage)'
+  echo  '  isoimage     - Create a boot CD-ROM image'
+endef
+
+CLEAN_FILES += arch/$(ARCH)/boot/image.iso
+
+
diff --git a/kitten/arch/x86_64/boot/Makefile b/kitten/arch/x86_64/boot/Makefile
new file mode 100644 (file)
index 0000000..783f48d
--- /dev/null
@@ -0,0 +1,88 @@
+#
+# arch/x86_64/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+# 2007 by Linus Torvalds
+#
+# 20070816  Kevin Pedretti <ktpedre@sandia.gov>
+#           Modifications for Kitten. Remove unneeded stuff.
+#
+
+# ROOT_DEV specifies the default root-device when making the image.
+# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
+# the default of FLOPPY is used by 'build'.
+
+ROOT_DEV := CURRENT
+
+targets                := vmlwk.bin bootsect bootsect.o \
+                  setup setup.o bzImage
+
+EXTRA_CFLAGS := -m32
+
+hostprogs-y    := tools/build
+HOST_EXTRACFLAGS += $(LWKINCLUDE)
+subdir-                := compressed/  #Let make clean descend in compressed/
+# ---------------------------------------------------------------------------
+
+$(obj)/bzImage: IMAGE_OFFSET := 0x100000
+$(obj)/bzImage: EXTRA_AFLAGS := -traditional -D__BIG_KERNEL__
+$(obj)/bzImage: BUILDFLAGS   := -b
+
+quiet_cmd_image = BUILD   $@
+cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
+           $(obj)/vmlwk.bin $(ROOT_DEV) > $@
+
+$(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
+                             $(obj)/vmlwk.bin $(obj)/tools/build FORCE
+       $(call if_changed,image)
+       @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+
+$(obj)/vmlwk.bin: $(obj)/compressed/vmlwk FORCE
+       $(call if_changed,objcopy)
+
+LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
+LDFLAGS_setup   := -Ttext 0x0 -s --oformat binary -e begtext
+
+$(obj)/setup $(obj)/bootsect: %: %.o FORCE
+       $(call if_changed,ld)
+
+$(obj)/compressed/vmlwk: FORCE
+       $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
+
+# Set this if you want to pass append arguments to the isoimage kernel
+FDARGS = console=serial debug_mptable=1 init_argv="one two three" init_envp="one=1 two=2 three=3"
+# Set this if you want an initrd included with the isoimage kernel
+ifdef CONFIG_V3VEE
+FDINITRD = /opt/vmm-tools/isos/puppy.iso
+else
+FDINITRD = init_task
+endif
+
+image_cmdline = default lwk $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
+
+# This requires being root or having syslinux 2.02 or higher installed
+isoimage: $(BOOTIMAGE) $(FDINITRD)
+       -rm -rf $(obj)/isoimage
+       mkdir $(obj)/isoimage
+       for i in lib lib64 share end ; do \
+               if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
+                       cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
+                       break ; \
+               fi ; \
+               if [ $$i = end ] ; then exit 1 ; fi ; \
+       done
+       cp $(BOOTIMAGE) $(obj)/isoimage/lwk
+       echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
+       if [ -f '$(FDINITRD)' ] ; then \
+               cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
+       fi
+       mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
+               -no-emul-boot -boot-load-size 4 -boot-info-table \
+               $(obj)/isoimage
+       rm -rf $(obj)/isoimage
+
diff --git a/kitten/arch/x86_64/boot/bootsect.S b/kitten/arch/x86_64/boot/bootsect.S
new file mode 100644 (file)
index 0000000..d6ddeb8
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *     bootsect.S              Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *     modified by Drew Eckhardt
+ *     modified by Bruce Evans (bde)
+ *     modified by Chris Noe (May 1999) (as86 -> gas)
+ *     gutted by H. Peter Anvin (Jan 2003)
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
+ *
+ */
+
+#include <arch/boot.h>
+
+SETUPSECTS     = 4                     /* default nr of setup-sectors */
+BOOTSEG                = 0x07C0                /* original address of boot-sector */
+INITSEG                = DEF_INITSEG           /* we move boot here - out of the way */
+SETUPSEG       = DEF_SETUPSEG          /* setup starts here */
+SYSSEG         = DEF_SYSSEG            /* system loaded at 0x10000 (65536) */
+SYSSIZE                = DEF_SYSSIZE           /* system size: # of 16-byte clicks */
+                                       /* to be loaded */
+ROOT_DEV       = 0                     /* ROOT_DEV is now written by "build" */
+SWAP_DEV       = 0                     /* SWAP_DEV is now written by "build" */
+
+#define SVGA_MODE 0
+
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+
+#ifndef ROOT_RDONLY
+#define ROOT_RDONLY 1
+#endif
+
+.code16
+.text
+
+.global _start
+_start:
+
+       # Normalize the start address
+       jmpl    $BOOTSEG, $start2
+
+start2:
+       movw    %cs, %ax
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %ss
+       movw    $0x7c00, %sp
+       sti
+       cld
+
+       movw    $bugger_off_msg, %si
+
+msg_loop:
+       lodsb
+       andb    %al, %al
+       jz      die
+       movb    $0xe, %ah
+       movw    $7, %bx
+       int     $0x10
+       jmp     msg_loop
+
+die:
+       # Allow the user to press a key, then reboot
+       xorw    %ax, %ax
+       int     $0x16
+       int     $0x19
+
+       # int 0x19 should never return.  In case it does anyway,
+       # invoke the BIOS reset code...
+       ljmp    $0xf000,$0xfff0
+
+
+bugger_off_msg:
+       .ascii  "Direct booting from floppy is no longer supported.\r\n"
+       .ascii  "Please use a boot loader program instead.\r\n"
+       .ascii  "\n"
+       .ascii  "Remove disk and press any key to reboot . . .\r\n"
+       .byte   0
+
+
+       # Kernel attributes; used by setup
+
+       .org 497
+setup_sects:   .byte SETUPSECTS
+root_flags:    .word ROOT_RDONLY
+syssize:       .word SYSSIZE
+swap_dev:      .word SWAP_DEV
+ram_size:      .word RAMDISK
+vid_mode:      .word SVGA_MODE
+root_dev:      .word ROOT_DEV
+boot_flag:     .word 0xAA55
diff --git a/kitten/arch/x86_64/boot/compressed/Makefile b/kitten/arch/x86_64/boot/compressed/Makefile
new file mode 100644 (file)
index 0000000..03a119e
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# lwk/arch/x86_64/boot/compressed/Makefile
+#
+# create a compressed vmlwk image from the original vmlwk
+#
+# Note all the files here are compiled/linked as 32bit executables.
+#
+
+targets                := vmlwk vmlwk.bin vmlwk.bin.gz head.o misc.o piggy.o
+EXTRA_AFLAGS   := -traditional
+
+# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
+# -m32
+CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2  -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin
+LDFLAGS := -m elf_x86_64
+
+LDFLAGS_vmlwk := -T
+$(obj)/vmlwk: $(src)/vmlwk.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
+       $(call if_changed,ld)
+       @:
+
+$(obj)/vmlwk.bin: vmlwk FORCE
+       $(call if_changed,objcopy)
+
+$(obj)/vmlwk.bin.gz: $(obj)/vmlwk.bin FORCE
+       $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
+
+$(obj)/piggy.o: $(obj)/vmlwk.scr $(obj)/vmlwk.bin.gz FORCE
+       $(call if_changed,ld)
diff --git a/kitten/arch/x86_64/boot/compressed/head.S b/kitten/arch/x86_64/boot/compressed/head.S
new file mode 100644 (file)
index 0000000..ec90f27
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  linux/boot/head.S
+ *
+ *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
+ */
+
+/*
+ *  head.S contains the 32-bit startup code.
+ *
+ * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
+ * the page directory will exist. The startup code will be overwritten by
+ * the page directory. [According to comments etc elsewhere on a compressed
+ * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
+ *
+ * Page 0 is deliberately kept safe, since System Management Mode code in 
+ * laptops may need to access the BIOS data stored there.  This is also
+ * useful for future device drivers that either access the BIOS via VM86 
+ * mode.
+ */
+
+/*
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ */
+.code32
+.text
+
+#include <lwk/linkage.h>
+#include <arch/segment.h>
+#include <arch/pgtable.h>
+#include <arch/page.h>
+#include <arch/msr.h>
+
+.section ".text.head"
+       .code32
+       .globl startup_32
+
+startup_32:
+       cld
+       cli
+       movl    $(__KERNEL_DS), %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %ss
+
+/* Calculate the delta between where we were compiled to run
+ * at and where we were actually loaded at.  This can only be done
+ * with a short local call on x86.  Nothing  else will tell us what
+ * address we are running at.  The reserved chunk of the real-mode
+ * data at 0x34-0x3f are used as the stack for this calculation.
+ * Only 4 bytes are needed.
+ */
+       leal    0x40(%esi), %esp
+       call    1f
+1:     popl    %ebp
+       subl    $1b, %ebp
+
+/* setup a stack and make sure cpu supports long mode. */
+       movl    $user_stack_end, %eax
+       addl    %ebp, %eax
+       movl    %eax, %esp
+
+       call    verify_cpu
+       testl   %eax, %eax
+       jnz     no_longmode
+
+/* Compute the delta between where we were compiled to run at
+ * and where the code will actually run at.
+ */
+/* %ebp contains the address we are loaded at by the boot loader and %ebx
+ * contains the address where we should move the kernel image temporarily
+ * for safe in-place decompression.
+ */
+
+#ifdef CONFIG_RELOCATABLE
+       movl    %ebp, %ebx
+       addl    $(LARGE_PAGE_SIZE -1), %ebx
+       andl    $LARGE_PAGE_MASK, %ebx
+#else
+       movl    $CONFIG_PHYSICAL_START, %ebx
+#endif
+
+       /* Replace the compressed data size with the uncompressed size */
+       subl    input_len(%ebp), %ebx
+       movl    output_len(%ebp), %eax
+       addl    %eax, %ebx
+       /* Add 8 bytes for every 32K input block */
+       shrl    $12, %eax
+       addl    %eax, %ebx
+       /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
+       addl    $(32768 + 18 + 4095), %ebx
+       andl    $~4095, %ebx
+
+/*
+ * Prepare for entering 64 bit mode
+ */
+
+       /* Load new GDT with the 64bit segments using 32bit descriptor */
+       leal    gdt(%ebp), %eax
+       movl    %eax, gdt+2(%ebp)
+       lgdt    gdt(%ebp)
+
+       /* Enable PAE mode */
+       xorl    %eax, %eax
+       orl     $(1 << 5), %eax
+       movl    %eax, %cr4
+
+ /*
+  * Build early 4G boot pagetable
+  */
+       /* Initialize Page tables to 0*/
+       leal    pgtable(%ebx), %edi
+       xorl    %eax, %eax
+       movl    $((4096*6)/4), %ecx
+       rep     stosl
+
+       /* Build Level 4 */
+       leal    pgtable + 0(%ebx), %edi
+       leal    0x1007 (%edi), %eax
+       movl    %eax, 0(%edi)
+
+       /* Build Level 3 */
+       leal    pgtable + 0x1000(%ebx), %edi
+       leal    0x1007(%edi), %eax
+       movl    $4, %ecx
+1:     movl    %eax, 0x00(%edi)
+       addl    $0x00001000, %eax
+       addl    $8, %edi
+       decl    %ecx
+       jnz     1b
+
+       /* Build Level 2 */
+       leal    pgtable + 0x2000(%ebx), %edi
+       movl    $0x00000183, %eax
+       movl    $2048, %ecx
+1:     movl    %eax, 0(%edi)
+       addl    $0x00200000, %eax
+       addl    $8, %edi
+       decl    %ecx
+       jnz     1b
+
+       /* Enable the boot page tables */
+       leal    pgtable(%ebx), %eax
+       movl    %eax, %cr3
+
+       /* Enable Long mode in EFER (Extended Feature Enable Register) */
+       movl    $MSR_EFER, %ecx
+       rdmsr
+       btsl    $_EFER_LME, %eax
+       wrmsr
+
+       /* Setup for the jump to 64bit mode
+        *
+        * When the jump is performend we will be in long mode but
+        * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
+        * (and in turn EFER.LMA = 1).  To jump into 64bit mode we use
+        * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+        * We place all of the values on our mini stack so lret can
+        * used to perform that far jump.
+        */
+       pushl   $__KERNEL_CS
+       leal    startup_64(%ebp), %eax
+       pushl   %eax
+
+       /* Enter paged protected Mode, activating Long Mode */
+       movl    $0x80000001, %eax /* Enable Paging and Protected mode */
+       movl    %eax, %cr0
+
+       /* Jump from 32bit compatibility mode into 64bit mode. */
+       lret
+
+no_longmode:
+       /* This isn't an x86-64 CPU so hang */
+1:
+       hlt
+       jmp     1b
+
+#include "../../kernel/verify_cpu.S"
+
+       /* Be careful here startup_64 needs to be at a predictable
+        * address so I can export it in an ELF header.  Bootloaders
+        * should look at the ELF header to find this address, as
+        * it may change in the future.
+        */
+       .code64
+       .org 0x200
+ENTRY(startup_64)
+       /* We come here either from startup_32 or directly from a
+        * 64bit bootloader.  If we come here from a bootloader we depend on
+        * an identity mapped page table being provied that maps our
+        * entire text+data+bss and hopefully all of memory.
+        */
+
+       /* Setup data segments. */
+       xorl    %eax, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %ss
+
+       /* Compute the decompressed kernel start address.  It is where
+        * we were loaded at aligned to a 2M boundary. %rbp contains the
+        * decompressed kernel start address.
+        *
+        * If it is a relocatable kernel then decompress and run the kernel
+        * from load address aligned to 2MB addr, otherwise decompress and
+        * run the kernel from CONFIG_PHYSICAL_START
+        */
+
+       /* Start with the delta to where the kernel will run at. */
+#ifdef CONFIG_RELOCATABLE
+       leaq    startup_32(%rip) /* - $startup_32 */, %rbp
+       addq    $(LARGE_PAGE_SIZE - 1), %rbp
+       andq    $LARGE_PAGE_MASK, %rbp
+       movq    %rbp, %rbx
+#else
+       movq    $CONFIG_PHYSICAL_START, %rbp
+       movq    %rbp, %rbx
+#endif
+
+       /* Replace the compressed data size with the uncompressed size */
+       movl    input_len(%rip), %eax
+       subq    %rax, %rbx
+       movl    output_len(%rip), %eax
+       addq    %rax, %rbx
+       /* Add 8 bytes for every 32K input block */
+       shrq    $12, %rax
+       addq    %rax, %rbx
+       /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
+       addq    $(32768 + 18 + 4095), %rbx
+       andq    $~4095, %rbx
+
+/* Copy the compressed kernel to the end of our buffer
+ * where decompression in place becomes safe.
+ */
+       leaq    _end(%rip), %r8
+       leaq    _end(%rbx), %r9
+       movq    $_end /* - $startup_32 */, %rcx
+1:     subq    $8, %r8
+       subq    $8, %r9
+       movq    0(%r8), %rax
+       movq    %rax, 0(%r9)
+       subq    $8, %rcx
+       jnz     1b
+
+/*
+ * Jump to the relocated address.
+ */
+       leaq    relocated(%rbx), %rax
+       jmp     *%rax
+
+.section ".text"
+relocated:
+
+/*
+ * Clear BSS
+ */
+       xorq    %rax, %rax
+       leaq    _edata(%rbx), %rdi
+       leaq    _end(%rbx), %rcx
+       subq    %rdi, %rcx
+       cld
+       rep
+       stosb
+
+       /* Setup the stack */
+       leaq    user_stack_end(%rip), %rsp
+
+       /* zero EFLAGS after setting rsp */
+       pushq   $0
+       popfq
+
+/*
+ * Do the decompression, and jump to the new kernel..
+ */
+       pushq   %rsi                    # Save the real mode argument
+       movq    %rsi, %rdi              # real mode address
+       leaq    _heap(%rip), %rsi       # _heap
+       leaq    input_data(%rip), %rdx  # input_data
+       movl    input_len(%rip), %eax
+       movq    %rax, %rcx              # input_len
+       movq    %rbp, %r8               # output
+       call    decompress_kernel
+       popq    %rsi
+
+
+/*
+ * Jump to the decompressed kernel.
+ */
+       jmp     *%rbp
+
+       .data
+gdt:
+       .word   gdt_end - gdt
+       .long   gdt
+       .word   0
+       .quad   0x0000000000000000      /* NULL descriptor */
+       .quad   0x00af9a000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf92000000ffff      /* __KERNEL_DS */
+gdt_end:
+       .bss
+/* Stack for uncompression */
+       .balign 4
+user_stack:
+       .fill 4096,4,0
+user_stack_end:
diff --git a/kitten/arch/x86_64/boot/compressed/misc.c b/kitten/arch/x86_64/boot/compressed/misc.c
new file mode 100644 (file)
index 0000000..ecb4ccf
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * misc.c
+ * 
+ * This is a collection of several routines from gzip-1.0.3 
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ */
+
+#define _LWK_STRING_H 1
+#define _LWK_BITMAP_H 1
+
+#include <lwk/linkage.h>
+#include <lwk/screen_info.h>
+#include <arch/page.h>
+#include <arch/io.h>
+
+/* WARNING!!
+ * This code is compiled with -fPIC and it is relocated dynamically
+ * at run time, but no relocation processing is performed.
+ * This means that it is not safe to place pointers in static structures.
+ */
+
+/*
+ * Getting to provable safe in place decompression is hard.
+ * Worst case behaviours need to be analized.
+ * Background information:
+ *
+ * The file layout is:
+ *    magic[2]
+ *    method[1]
+ *    flags[1]
+ *    timestamp[4]
+ *    extraflags[1]
+ *    os[1]
+ *    compressed data blocks[N]
+ *    crc[4] orig_len[4]
+ *
+ * resulting in 18 bytes of non compressed data overhead.
+ *
+ * Files divided into blocks
+ * 1 bit (last block flag)
+ * 2 bits (block type)
+ *
+ * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved.
+ * The smallest block type encoding is always used.
+ *
+ * stored:
+ *    32 bits length in bytes.
+ *
+ * fixed:
+ *    magic fixed tree.
+ *    symbols.
+ *
+ * dynamic:
+ *    dynamic tree encoding.
+ *    symbols.
+ *
+ *
+ * The buffer for decompression in place is the length of the
+ * uncompressed data, plus a small amount extra to keep the algorithm safe.
+ * The compressed data is placed at the end of the buffer.  The output
+ * pointer is placed at the start of the buffer and the input pointer
+ * is placed where the compressed data starts.  Problems will occur
+ * when the output pointer overruns the input pointer.
+ *
+ * The output pointer can only overrun the input pointer if the input
+ * pointer is moving faster than the output pointer.  A condition only
+ * triggered by data whose compressed form is larger than the uncompressed
+ * form.
+ *
+ * The worst case at the block level is a growth of the compressed data
+ * of 5 bytes per 32767 bytes.
+ *
+ * The worst case internal to a compressed block is very hard to figure.
+ * The worst case can at least be boundined by having one bit that represents
+ * 32764 bytes and then all of the rest of the bytes representing the very
+ * very last byte.
+ *
+ * All of which is enough to compute an amount of extra data that is required
+ * to be safe.  To avoid problems at the block level allocating 5 extra bytes
+ * per 32767 bytes of data is sufficient.  To avoind problems internal to a block
+ * adding an extra 32767 bytes (the worst case uncompressed block size) is
+ * sufficient, to ensure that in the worst case the decompressed data for
+ * block will stop the byte before the compressed data for a block begins.
+ * To avoid problems with the compressed data's meta information an extra 18
+ * bytes are needed.  Leading to the formula:
+ *
+ * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
+ *
+ * Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
+ * Adding 32768 instead of 32767 just makes for round numbers.
+ * Adding the decompressor_size is necessary as it musht live after all
+ * of the data as well.  Last I measured the decompressor is about 14K.
+ * 10K of actuall data and 4K of bss.
+ *
+ */
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x80000000       /* Window size must be at least 32k,
+                                * and a power of two
+                                * We don't actually have a window just
+                                * a huge output buffer so I report
+                                * a 2G windows size, as that should
+                                * always be larger than our output buffer.
+                                */
+
+static uch *inbuf;     /* input buffer */
+static uch *window;    /* Sliding window buffer, (and final output buffer) */
+
+static unsigned insize;  /* valid bytes in inbuf */
+static unsigned inptr;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+               
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+  
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+static unsigned char *real_mode; /* Pointer to real-mode data */
+
+#define RM_EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
+#ifndef STANDARD_MEMORY_BIOS_CALL
+#define RM_ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
+#endif
+#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
+
+extern unsigned char input_data[];
+extern int input_len;
+
+static long bytes_out = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+
+static void *memset(void *s, int c, unsigned n);
+static void *memcpy(void *dest, const void *src, unsigned n);
+
+static void putstr(const char *);
+
+static long free_mem_ptr;
+static long free_mem_end_ptr;
+
+#define HEAP_SIZE             0x7000
+
+static char *vidmem = (char *)0xb8000;
+static int vidport;
+static int lines, cols;
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+       void *p;
+
+       if (size <0) error("Malloc error");
+       if (free_mem_ptr <= 0) error("Memory error");
+
+       free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+       p = (void *)free_mem_ptr;
+       free_mem_ptr += size;
+
+       if (free_mem_ptr >= free_mem_end_ptr)
+               error("Out of memory");
+
+       return p;
+}
+
+static void free(void *where)
+{      /* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+       *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+       free_mem_ptr = (long) *ptr;
+}
+static void scroll(void)
+{
+       int i;
+
+       memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+       for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
+               vidmem[i] = ' ';
+}
+
+static void putstr(const char *s)
+{
+       int x,y,pos;
+       char c;
+
+       x = RM_SCREEN_INFO.orig_x;
+       y = RM_SCREEN_INFO.orig_y;
+
+       while ( ( c = *s++ ) != '\0' ) {
+               if ( c == '\n' ) {
+                       x = 0;
+                       if ( ++y >= lines ) {
+                               scroll();
+                               y--;
+                       }
+               } else {
+                       vidmem [ ( x + cols * y ) * 2 ] = c; 
+                       if ( ++x >= cols ) {
+                               x = 0;
+                               if ( ++y >= lines ) {
+                                       scroll();
+                                       y--;
+                               }
+                       }
+               }
+       }
+
+       RM_SCREEN_INFO.orig_x = x;
+       RM_SCREEN_INFO.orig_y = y;
+
+       pos = (x + cols * y) * 2;       /* Update cursor position */
+       outb_p(14, vidport);
+       outb_p(0xff & (pos >> 9), vidport+1);
+       outb_p(15, vidport);
+       outb_p(0xff & (pos >> 1), vidport+1);
+}
+
+static void* memset(void* s, int c, unsigned n)
+{
+       int i;
+       char *ss = (char*)s;
+
+       for (i=0;i<n;i++) ss[i] = c;
+       return s;
+}
+
+static void* memcpy(void* dest, const void* src, unsigned n)
+{
+       int i;
+       char *d = (char *)dest, *s = (char *)src;
+
+       for (i=0;i<n;i++) d[i] = s[i];
+       return dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+       error("ran out of input data");
+       return 0;
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+       /* With my window equal to my output buffer
+        * I only need to compute the crc here.
+        */
+       ulg c = crc;         /* temporary variable */
+       unsigned n;
+       uch *in, ch;
+
+       in = window;
+       for (n = 0; n < outcnt; n++) {
+               ch = *in++;
+               c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+       }
+       crc = c;
+       bytes_out += (ulg)outcnt;
+       outcnt = 0;
+}
+
+static void error(char *x)
+{
+       putstr("\n\n");
+       putstr(x);
+       putstr("\n\n -- System halted");
+
+       while(1);       /* Halt */
+}
+
+asmlinkage void decompress_kernel(void *rmode, unsigned long heap,
+       uch *input_data, unsigned long input_len, uch *output)
+{
+       real_mode = rmode;
+
+       if (RM_SCREEN_INFO.orig_video_mode == 7) {
+               vidmem = (char *) 0xb0000;
+               vidport = 0x3b4;
+       } else {
+               vidmem = (char *) 0xb8000;
+               vidport = 0x3d4;
+       }
+
+       lines = RM_SCREEN_INFO.orig_video_lines;
+       cols = RM_SCREEN_INFO.orig_video_cols;
+
+       window = output;                /* Output buffer (Normally at 1M) */
+       free_mem_ptr     = heap;        /* Heap  */
+       free_mem_end_ptr = heap + HEAP_SIZE;
+       inbuf  = input_data;            /* Input buffer */
+       insize = input_len;
+       inptr  = 0;
+
+       if ((ulg)output & (__KERNEL_ALIGN - 1))
+               error("Destination address not 2M aligned");
+       if ((ulg)output >= 0xffffffffffUL)
+               error("Destination address too large");
+
+       makecrc();
+       putstr(".\nDecompressing LWK...");
+       gunzip();
+       putstr("done.\nBooting the kernel.\n");
+       return;
+}
diff --git a/kitten/arch/x86_64/boot/compressed/vmlwk.lds b/kitten/arch/x86_64/boot/compressed/vmlwk.lds
new file mode 100644 (file)
index 0000000..94c13e5
--- /dev/null
@@ -0,0 +1,44 @@
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(startup_64)
+SECTIONS
+{
+       /* Be careful parts of head.S assume startup_32 is at
+        * address 0.
+        */
+       . = 0;
+       .text : {
+               _head = . ;
+               *(.text.head)
+               _ehead = . ;
+               *(.text.compressed)
+               _text = .;      /* Text */
+               *(.text)
+               *(.text.*)
+               _etext = . ;
+       }
+       .rodata : {
+               _rodata = . ;
+               *(.rodata)       /* read-only data */
+               *(.rodata.*)
+               _erodata = . ;
+       }
+       .data : {
+               _data = . ;
+               *(.data)
+               *(.data.*)
+               _edata = . ;
+       }
+       .bss : {
+               _bss = . ;
+               *(.bss)
+               *(.bss.*)
+               *(COMMON)
+               . = ALIGN(8);
+               _end = . ;
+               . = ALIGN(4096);
+               pgtable = . ;
+               . = . + 4096 * 6;
+               _heap = .;
+       }
+}
diff --git a/kitten/arch/x86_64/boot/compressed/vmlwk.scr b/kitten/arch/x86_64/boot/compressed/vmlwk.scr
new file mode 100644 (file)
index 0000000..bd1429c
--- /dev/null
@@ -0,0 +1,10 @@
+SECTIONS
+{
+  .text.compressed : {
+       input_len = .;
+       LONG(input_data_end - input_data) input_data = .;
+       *(.data)
+       output_len = . - 4;
+       input_data_end = .;
+       }
+}
diff --git a/kitten/arch/x86_64/boot/setup.S b/kitten/arch/x86_64/boot/setup.S
new file mode 100644 (file)
index 0000000..5092de5
--- /dev/null
@@ -0,0 +1,824 @@
+/*
+ *     setup.S         Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * setup.s is responsible for getting the system data from the BIOS,
+ * and putting them into the appropriate places in system memory.
+ * both setup.s and system has been loaded by the bootblock.
+ *
+ * This code asks the bios for memory/disk/other parameters, and
+ * puts them in a "safe" place: 0x90000-0x901FF, ie where the
+ * boot-block used to be. It is then up to the protected mode
+ * system to read them from there before the area is overwritten
+ * for buffer-blocks.
+ *
+ * Move PS/2 aux init code to psaux.c
+ * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
+ *
+ * some changes and additional features by Christoph Niemann,
+ * March 1993/June 1994 (Christoph.Niemann@linux.org)
+ *
+ * add APM BIOS checking by Stephen Rothwell, May 1994
+ * (sfr@canb.auug.org.au)
+ *
+ * High load stuff, initrd support and position independency
+ * by Hans Lermen & Werner Almesberger, February 1996
+ * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
+ *
+ * Video handling moved to video.S by Martin Mares, March 1996
+ * <mj@k332.feld.cvut.cz>
+ *
+ * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
+ * parsons) to avoid loadlin confusion, July 1997
+ *
+ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
+ * <stiker@northlink.com>
+ *
+ * Fix to work around buggy BIOSes which don't use carry bit correctly
+ * and/or report extended memory in CX/DX for e801h memory size detection 
+ * call.  As a result the kernel got wrong figures.  The int15/e801h docs
+ * from Ralf Brown interrupt list seem to indicate AX/BX should be used
+ * anyway.  So to avoid breaking many machines (presumably there was a reason
+ * to orginally use CX/DX instead of AX/BX), we do a kludge to see
+ * if CX/DX have been changed in the e801 call and if so use AX/BX .
+ * Michael Miller, April 2001 <michaelm@mjmm.org>
+ *
+ * Added long mode checking and SSE force. March 2003, Andi Kleen.             
+ */
+
+#include <arch/segment.h>
+#include <lwk/version.h>
+#include <lwk/compile.h>
+#include <lwk/init.h>
+#include <arch/boot.h>
+#include <arch/e820.h>
+#include <arch/page.h>
+
+/* Signature words to ensure LILO loaded us right */
+#define SIG1   0xAA55
+#define SIG2   0x5A5A
+
+INITSEG  = DEF_INITSEG         # 0x9000, we move boot here, out of the way
+SYSSEG   = DEF_SYSSEG          # 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG                # 0x9020, this is the current segment
+                               # ... and the former contents of CS
+
+DELTA_INITSEG = SETUPSEG - INITSEG     # 0x0020
+
+.code16
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+start:
+       jmp     trampoline
+
+# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
+
+               .ascii  "HdrS"          # header signature
+               .word   0x0206          # header version number (>= 0x0105)
+                                       # or else old loadlin-1.5 will fail)
+realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
+start_sys_seg: .word   SYSSEG
+               .word   kernel_version  # pointing to kernel version string
+                                       # above section of header is compatible
+                                       # with loadlin-1.5 (header v1.5). Don't
+                                       # change it.
+
+type_of_loader:        .byte   0               # = 0, old one (LILO, Loadlin,
+                                       #      Bootlin, SYSLX, bootsect...)
+                                       # See Documentation/i386/boot.txt for
+                                       # assigned ids
+       
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH    = 1                     # If set, the kernel is loaded high
+CAN_USE_HEAP   = 0x80                  # If set, the loader also has set
+                                       # heap_end_ptr to tell how much
+                                       # space behind setup.S can be used for
+                                       # heap purposes.
+                                       # Only the loader knows what is free
+#ifndef __BIG_KERNEL__
+               .byte   0
+#else
+               .byte   LOADED_HIGH
+#endif
+
+setup_move_size: .word  0x8000         # size to move, when setup is not
+                                       # loaded at 0x90000. We will move setup 
+                                       # to 0x90000 then just before jumping
+                                       # into the kernel. However, only the
+                                       # loader knows how much data behind
+                                       # us also needs to be loaded.
+
+code32_start:                          # here loaders can put a different
+                                       # start address for 32-bit code.
+#ifndef __BIG_KERNEL__
+               .long   0x1000          #   0x1000 = default for zImage
+#else
+               .long   0x100000        # 0x100000 = default for big kernel
+#endif
+
+ramdisk_image: .long   0               # address of loaded ramdisk image
+                                       # Here the loader puts the 32-bit
+                                       # address where it loaded the image.
+                                       # This only will be read by the kernel.
+
+ramdisk_size:  .long   0               # its size in bytes
+
+bootsect_kludge:
+               .long   0               # obsolete
+
+heap_end_ptr:  .word   modelist+1024   # (Header version 0x0201 or later)
+                                       # space from here (exclusive) down to
+                                       # end of setup code can be used by setup
+                                       # for local heap purposes.
+
+pad1:          .word   0
+cmd_line_ptr:  .long 0                 # (Header version 0x0202 or later)
+                                       # If nonzero, a 32-bit pointer
+                                       # to the kernel command line.
+                                       # The command line should be
+                                       # located between the start of
+                                       # setup and the end of low
+                                       # memory (0xa0000), or it may
+                                       # get overwritten before it
+                                       # gets read.  If this field is
+                                       # used, there is no longer
+                                       # anything magical about the
+                                       # 0x90000 segment; the setup
+                                       # can be located anywhere in
+                                       # low memory 0x10000 or higher.
+
+ramdisk_max:   .long 0xffffffff
+kernel_alignment:  .long 0x200000       # physical addr alignment required for
+                                       # protected mode relocatable kernel
+#ifdef CONFIG_RELOCATABLE
+relocatable_kernel:    .byte 1
+#else
+relocatable_kernel:    .byte 0
+#endif
+pad2:                  .byte 0
+pad3:                  .word 0
+
+cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
+                                                #added with boot protocol
+                                                #version 2.06
+
+trampoline:    call    start_of_setup
+               .align 16
+                                       # The offset at this point is 0x240
+               .space  (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff)
+# End of setup header #####################################################
+
+start_of_setup:
+# Bootlin depends on this being done early
+       movw    $0x01500, %ax
+       movb    $0x81, %dl
+       int     $0x13
+
+#ifdef SAFE_RESET_DISK_CONTROLLER
+# Reset the disk controller.
+       movw    $0x0000, %ax
+       movb    $0x80, %dl
+       int     $0x13
+#endif
+
+# Set %ds = %cs, we know that SETUPSEG = %cs at this point
+       movw    %cs, %ax                # aka SETUPSEG
+       movw    %ax, %ds
+# Check signature at end of setup
+       cmpw    $SIG1, setup_sig1
+       jne     bad_sig
+
+       cmpw    $SIG2, setup_sig2
+       jne     bad_sig
+
+       jmp     good_sig1
+
+# Routine to print asciiz string at ds:si
+prtstr:
+       lodsb
+       andb    %al, %al
+       jz      fin
+
+       call    prtchr
+       jmp     prtstr
+
+fin:   ret
+
+# Space printing
+prtsp2:        call    prtspc          # Print double space
+prtspc:        movb    $0x20, %al      # Print single space (note: fall-thru)
+
+prtchr:        
+       pushw   %ax
+       pushw   %cx
+       movw    $0007,%bx
+       movw    $0x01, %cx
+       movb    $0x0e, %ah
+       int     $0x10
+       popw    %cx
+       popw    %ax
+       ret
+
+beep:  movb    $0x07, %al
+       jmp     prtchr
+       
+no_sig_mess: .string   "No setup signature found ..."
+
+good_sig1:
+       jmp     good_sig
+
+# We now have to find the rest of the setup code/data
+bad_sig:
+       movw    %cs, %ax                        # SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # INITSEG
+       movw    %ax, %ds
+       xorb    %bh, %bh
+       movb    (497), %bl                      # get setup sect from bootsect
+       subw    $4, %bx                         # LILO loads 4 sectors of setup
+       shlw    $8, %bx                         # convert to words (1sect=2^8 words)
+       movw    %bx, %cx
+       shrw    $3, %bx                         # convert to segment
+       addw    $SYSSEG, %bx
+       movw    %bx, %cs:start_sys_seg
+# Move rest of setup code/data to here
+       movw    $2048, %di                      # four sectors loaded by LILO
+       subw    %si, %si
+       movw    %cs, %ax                        # aka SETUPSEG
+       movw    %ax, %es
+       movw    $SYSSEG, %ax
+       movw    %ax, %ds
+       rep
+       movsw
+       movw    %cs, %ax                        # aka SETUPSEG
+       movw    %ax, %ds
+       cmpw    $SIG1, setup_sig1
+       jne     no_sig
+
+       cmpw    $SIG2, setup_sig2
+       jne     no_sig
+
+       jmp     good_sig
+
+no_sig:
+       lea     no_sig_mess, %si
+       call    prtstr
+
+no_sig_loop:
+       jmp     no_sig_loop
+
+good_sig:
+       movw    %cs, %ax                        # aka SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       movw    %ax, %ds
+# Check if an old loader tries to load a big-kernel
+       testb   $LOADED_HIGH, %cs:loadflags     # Do we have a big kernel?
+       jz      loader_ok                       # No, no danger for old loaders.
+
+       cmpb    $0, %cs:type_of_loader          # Do we have a loader that
+                                               # can deal with us?
+       jnz     loader_ok                       # Yes, continue.
+
+       pushw   %cs                             # No, we have an old loader,
+       popw    %ds                             # die. 
+       lea     loader_panic_mess, %si
+       call    prtstr
+
+       jmp     no_sig_loop
+
+loader_panic_mess: .string "Wrong loader, giving up..."
+
+loader_ok:
+       /* check for long mode. */
+       /* we have to do this before the VESA setup, otherwise the user
+          can't see the error message. */
+       
+       pushw   %ds
+       movw    %cs,%ax
+       movw    %ax,%ds
+       
+       call verify_cpu
+       testl %eax,%eax
+       jz sse_ok
+
+no_longmode:
+       call    beep
+       lea     long_mode_panic,%si
+       call    prtstr
+no_longmode_loop:              
+       jmp     no_longmode_loop
+long_mode_panic:
+       .string "BOOT FAILURE: This system does not support x86_64 long mode."
+       .byte 0
+
+#include "../kernel/verify_cpu.S"
+sse_ok:
+       popw    %ds
+       
+# tell BIOS we want to go to long mode
+       movl  $0xec00,%eax      # declare target operating mode
+       movl  $2,%ebx           # long mode
+       int $0x15                       
+       
+# Get memory size (extended mem, kB)
+
+       xorl    %eax, %eax
+       movl    %eax, (0x1e0)
+#ifndef STANDARD_MEMORY_BIOS_CALL
+       movb    %al, (E820NR)
+# Try three different memory detection schemes.  First, try
+# e820h, which lets us assemble a memory map, then try e801h,
+# which returns a 32-bit memory size, and finally 88h, which
+# returns 0-64m
+
+# method E820H:
+# the memory map from hell.  e820h returns memory classified into
+# a whole bunch of different types, and allows memory holes and
+# everything.  We scan through this memory map and build a list
+# of the first 32 memory areas, which we return at [E820MAP].
+# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
+
+#define SMAP  0x534d4150
+
+meme820:
+       xorl    %ebx, %ebx                      # continuation counter
+       movw    $E820MAP, %di                   # point into the whitelist
+                                               # so we can have the bios
+                                               # directly write into it.
+
+jmpe820:
+       movl    $0x0000e820, %eax               # e820, upper word zeroed
+       movl    $SMAP, %edx                     # ascii 'SMAP'
+       movl    $20, %ecx                       # size of the e820rec
+       pushw   %ds                             # data record.
+       popw    %es
+       int     $0x15                           # make the call
+       jc      bail820                         # fall to e801 if it fails
+
+       cmpl    $SMAP, %eax                     # check the return is `SMAP'
+       jne     bail820                         # fall to e801 if it fails
+
+#      cmpl    $1, 16(%di)                     # is this usable memory?
+#      jne     again820
+
+       # If this is usable memory, we save it by simply advancing %di by
+       # sizeof(e820rec).
+       #
+good820:
+       movb    (E820NR), %al                   # up to 128 entries
+       cmpb    $E820MAX, %al
+       jae     bail820
+
+       incb    (E820NR)
+       movw    %di, %ax
+       addw    $20, %ax
+       movw    %ax, %di
+again820:
+       cmpl    $0, %ebx                        # check to see if
+       jne     jmpe820                         # %ebx is set to EOF
+bail820:
+
+
+# method E801H:
+# memory size is in 1k chunksizes, to avoid confusing loadlin.
+# we store the 0xe801 memory size in a completely different place,
+# because it will most likely be longer than 16 bits.
+# (use 1e0 because that's what Larry Augustine uses in his
+# alternative new memory detection scheme, and it's sensible
+# to write everything into the same place.)
+
+meme801:
+       stc                                     # fix to work around buggy
+       xorw    %cx,%cx                         # BIOSes which don't clear/set
+       xorw    %dx,%dx                         # carry on pass/error of
+                                               # e801h memory size call
+                                               # or merely pass cx,dx though
+                                               # without changing them.
+       movw    $0xe801, %ax
+       int     $0x15
+       jc      mem88
+
+       cmpw    $0x0, %cx                       # Kludge to handle BIOSes
+       jne     e801usecxdx                     # which report their extended
+       cmpw    $0x0, %dx                       # memory in AX/BX rather than
+       jne     e801usecxdx                     # CX/DX.  The spec I have read
+       movw    %ax, %cx                        # seems to indicate AX/BX 
+       movw    %bx, %dx                        # are more reasonable anyway...
+
+e801usecxdx:
+       andl    $0xffff, %edx                   # clear sign extend
+       shll    $6, %edx                        # and go from 64k to 1k chunks
+       movl    %edx, (0x1e0)                   # store extended memory size
+       andl    $0xffff, %ecx                   # clear sign extend
+       addl    %ecx, (0x1e0)                   # and add lower memory into
+                                               # total size.
+
+# Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+# 64mb, depending on the bios) in ax.
+mem88:
+
+#endif
+       movb    $0x88, %ah
+       int     $0x15
+       movw    %ax, (2)
+
+# Set the keyboard repeat rate to the max
+       movw    $0x0305, %ax
+       xorw    %bx, %bx
+       int     $0x16
+
+# Check for video adapter and its parameters and allow the
+# user to browse video modes.
+       call    video                           # NOTE: we need %ds pointing
+                                               # to bootsector
+
+# Get hd0 data...
+       xorw    %ax, %ax
+       movw    %ax, %ds
+       ldsw    (4 * 0x41), %si
+       movw    %cs, %ax                        # aka SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       pushw   %ax
+       movw    %ax, %es
+       movw    $0x0080, %di
+       movw    $0x10, %cx
+       pushw   %cx
+       cld
+       rep
+       movsb
+# Get hd1 data...
+       xorw    %ax, %ax
+       movw    %ax, %ds
+       ldsw    (4 * 0x46), %si
+       popw    %cx
+       popw    %es
+       movw    $0x0090, %di
+       rep
+       movsb
+# Check that there IS a hd1 :-)
+       movw    $0x01500, %ax
+       movb    $0x81, %dl
+       int     $0x13
+       jc      no_disk1
+       
+       cmpb    $3, %ah
+       je      is_disk1
+
+no_disk1:
+       movw    %cs, %ax                        # aka SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       movw    %ax, %es
+       movw    $0x0090, %di
+       movw    $0x10, %cx
+       xorw    %ax, %ax
+       cld
+       rep
+       stosb
+is_disk1:
+
+# Check for PS/2 pointing device
+       movw    %cs, %ax                        # aka SETUPSEG
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       movw    %ax, %ds
+       movb    $0, (0x1ff)                     # default is no pointing device
+       int     $0x11                           # int 0x11: equipment list
+       testb   $0x04, %al                      # check if mouse installed
+       jz      no_psmouse
+
+       movb    $0xAA, (0x1ff)                  # device present
+no_psmouse:
+
+# Now we want to move to protected mode ...
+       cmpw    $0, %cs:realmode_swtch
+       jz      rmodeswtch_normal
+
+       lcall   *%cs:realmode_swtch
+
+       jmp     rmodeswtch_end
+
+rmodeswtch_normal:
+        pushw  %cs
+       call    default_switch
+
+rmodeswtch_end:
+# we get the code32 start address and modify the below 'jmpi'
+# (loader may have changed it)
+       movl    %cs:code32_start, %eax
+       movl    %eax, %cs:code32
+
+# Now we move the system to its rightful place ... but we check if we have a
+# big-kernel. In that case we *must* not move it ...
+       testb   $LOADED_HIGH, %cs:loadflags
+       jz      do_move0                        # .. then we have a normal low
+                                               # loaded zImage
+                                               # .. or else we have a high
+                                               # loaded bzImage
+       jmp     end_move                        # ... and we skip moving
+
+do_move0:
+       movw    $0x100, %ax                     # start of destination segment
+       movw    %cs, %bp                        # aka SETUPSEG
+       subw    $DELTA_INITSEG, %bp             # aka INITSEG
+       movw    %cs:start_sys_seg, %bx          # start of source segment
+       cld
+do_move:
+       movw    %ax, %es                        # destination segment
+       incb    %ah                             # instead of add ax,#0x100
+       movw    %bx, %ds                        # source segment
+       addw    $0x100, %bx
+       subw    %di, %di
+       subw    %si, %si
+       movw    $0x800, %cx
+       rep
+       movsw
+       cmpw    %bp, %bx                        # assume start_sys_seg > 0x200,
+                                               # so we will perhaps read one
+                                               # page more than needed, but
+                                               # never overwrite INITSEG
+                                               # because destination is a
+                                               # minimum one page below source
+       jb      do_move
+
+end_move:
+# then we load the segment descriptors
+       movw    %cs, %ax                        # aka SETUPSEG
+       movw    %ax, %ds
+               
+# Check whether we need to be downward compatible with version <=201
+       cmpl    $0, cmd_line_ptr
+       jne     end_move_self           # loader uses version >=202 features
+       cmpb    $0x20, type_of_loader
+       je      end_move_self           # bootsect loader, we know of it
+
+# Boot loader doesnt support boot protocol version 2.02.
+# If we have our code not at 0x90000, we need to move it there now.
+# We also then need to move the params behind it (commandline)
+# Because we would overwrite the code on the current IP, we move
+# it in two steps, jumping high after the first one.
+       movw    %cs, %ax
+       cmpw    $SETUPSEG, %ax
+       je      end_move_self
+
+       cli                                     # make sure we really have
+                                               # interrupts disabled !
+                                               # because after this the stack
+                                               # should not be used
+       subw    $DELTA_INITSEG, %ax             # aka INITSEG
+       movw    %ss, %dx
+       cmpw    %ax, %dx
+       jb      move_self_1
+
+       addw    $INITSEG, %dx
+       subw    %ax, %dx                        # this will go into %ss after
+                                               # the move
+move_self_1:
+       movw    %ax, %ds
+       movw    $INITSEG, %ax                   # real INITSEG
+       movw    %ax, %es
+       movw    %cs:setup_move_size, %cx
+       std                                     # we have to move up, so we use
+                                               # direction down because the
+                                               # areas may overlap
+       movw    %cx, %di
+       decw    %di
+       movw    %di, %si
+       subw    $move_self_here+0x200, %cx
+       rep
+       movsb
+       ljmp    $SETUPSEG, $move_self_here
+
+move_self_here:
+       movw    $move_self_here+0x200, %cx
+       rep
+       movsb
+       movw    $SETUPSEG, %ax
+       movw    %ax, %ds
+       movw    %dx, %ss
+end_move_self:                                 # now we are at the right place
+       lidt    idt_48                          # load idt with 0,0
+       xorl    %eax, %eax                      # Compute gdt_base
+       movw    %ds, %ax                        # (Convert %ds:gdt to a linear ptr)
+       shll    $4, %eax
+       addl    $gdt, %eax
+       movl    %eax, (gdt_48+2)
+       lgdt    gdt_48                          # load gdt with whatever is
+                                               # appropriate
+
+# that was painless, now we enable a20
+       call    empty_8042
+
+       movb    $0xD1, %al                      # command write
+       outb    %al, $0x64
+       call    empty_8042
+
+       movb    $0xDF, %al                      # A20 on
+       outb    %al, $0x60
+       call    empty_8042
+
+#
+#      You must preserve the other bits here. Otherwise embarrasing things
+#      like laptops powering off on boot happen. Corrected version by Kira
+#      Brown from Linux 2.2
+#
+       inb     $0x92, %al                      # 
+       orb     $02, %al                        # "fast A20" version
+       outb    %al, $0x92                      # some chips have only this
+
+# wait until a20 really *is* enabled; it can take a fair amount of
+# time on certain systems; Toshiba Tecras are known to have this
+# problem.  The memory location used here (0x200) is the int 0x80
+# vector, which should be safe to use.
+
+       xorw    %ax, %ax                        # segment 0x0000
+       movw    %ax, %fs
+       decw    %ax                             # segment 0xffff (HMA)
+       movw    %ax, %gs
+a20_wait:
+       incw    %ax                             # unused memory location <0xfff0
+       movw    %ax, %fs:(0x200)                # we use the "int 0x80" vector
+       cmpw    %gs:(0x210), %ax                # and its corresponding HMA addr
+       je      a20_wait                        # loop until no longer aliased
+
+# make sure any possible coprocessor is properly reset..
+       xorw    %ax, %ax
+       outb    %al, $0xf0
+       call    delay
+
+       outb    %al, $0xf1
+       call    delay
+
+# well, that went ok, I hope. Now we mask all interrupts - the rest
+# is done in init_IRQ().
+       movb    $0xFF, %al                      # mask all interrupts for now
+       outb    %al, $0xA1
+       call    delay
+       
+       movb    $0xFB, %al                      # mask all irq's but irq2 which
+       outb    %al, $0x21                      # is cascaded
+
+# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+# need no steenking BIOS anyway (except for the initial loading :-).
+# The BIOS-routine wants lots of unnecessary data, and it's less
+# "interesting" anyway. This is how REAL programmers do it.
+#
+# Well, now's the time to actually move into protected mode. To make
+# things as simple as possible, we do no register set-up or anything,
+# we let the gnu-compiled 32-bit programs do that. We just jump to
+# absolute address 0x1000 (or the loader supplied one),
+# in 32-bit protected mode.
+#
+# Note that the short jump isn't strictly needed, although there are
+# reasons why it might be a good idea. It won't hurt in any case.
+       movw    $1, %ax                         # protected mode (PE) bit
+       lmsw    %ax                             # This is it!
+       jmp     flush_instr
+
+flush_instr:
+       xorw    %bx, %bx                        # Flag to indicate a boot
+       xorl    %esi, %esi                      # Pointer to real-mode code
+       movw    %cs, %si
+       subw    $DELTA_INITSEG, %si
+       shll    $4, %esi                        # Convert to 32-bit pointer
+# NOTE: For high loaded big kernels we need a
+#      jmpi    0x100000,__KERNEL_CS
+#
+#      but we yet haven't reloaded the CS register, so the default size 
+#      of the target offset still is 16 bit.
+#      However, using an operand prefix (0x66), the CPU will properly
+#      take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+#      Manual, Mixing 16-bit and 32-bit code, page 16-6)
+
+       .byte 0x66, 0xea                        # prefix + jmpi-opcode
+code32:        .long   0x1000                          # will be set to 0x100000
+                                               # for big kernels
+       .word   __KERNEL_CS
+
+# Here's a bunch of information about your current kernel..
+kernel_version:        .ascii  UTS_RELEASE
+               .ascii  " ("
+               .ascii  LWK_COMPILE_BY
+               .ascii  "@"
+               .ascii  LWK_COMPILE_HOST
+               .ascii  ") "
+               .ascii  UTS_VERSION
+               .byte   0
+
+# This is the default real mode switch routine.
+# to be called just before protected mode transition
+default_switch:
+       cli                                     # no interrupts allowed !
+       movb    $0x80, %al                      # disable NMI for bootup
+                                               # sequence
+       outb    %al, $0x70
+       lret
+
+
+# This routine checks that the keyboard command queue is empty
+# (after emptying the output buffers)
+#
+# Some machines have delusions that the keyboard buffer is always full
+# with no keyboard attached...
+#
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads.  With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
+
+empty_8042:
+       pushl   %ecx
+       movl    $100000, %ecx
+
+empty_8042_loop:
+       decl    %ecx
+       jz      empty_8042_end_loop
+
+       call    delay
+
+       inb     $0x64, %al                      # 8042 status port
+       testb   $1, %al                         # output buffer?
+       jz      no_output
+
+       call    delay
+       inb     $0x60, %al                      # read it
+       jmp     empty_8042_loop
+
+no_output:
+       testb   $2, %al                         # is input buffer full?
+       jnz     empty_8042_loop                 # yes - loop
+empty_8042_end_loop:
+       popl    %ecx
+       ret
+
+# Read the cmos clock. Return the seconds in al
+gettime:
+       pushw   %cx
+       movb    $0x02, %ah
+       int     $0x1a
+       movb    %dh, %al                        # %dh contains the seconds
+       andb    $0x0f, %al
+       movb    %dh, %ah
+       movb    $0x04, %cl
+       shrb    %cl, %ah
+       aad
+       popw    %cx
+       ret
+
+# Delay is needed after doing I/O
+delay:
+       outb    %al,$0x80
+       ret
+
+# Descriptor tables
+gdt:
+       .word   0, 0, 0, 0                      # dummy
+
+       .word   0, 0, 0, 0                      # unused
+
+       .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
+       .word   0                               # base address = 0
+       .word   0x9A00                          # code read/exec
+       .word   0x00CF                          # granularity = 4096, 386
+                                               #  (+5th nibble of limit)
+
+       .word   0xFFFF                          # 4Gb - (0x100000*0x1000 = 4Gb)
+       .word   0                               # base address = 0
+       .word   0x9200                          # data read/write
+       .word   0x00CF                          # granularity = 4096, 386
+                                               #  (+5th nibble of limit)
+gdt_end:
+idt_48:
+       .word   0                               # idt limit = 0
+       .word   0, 0                            # idt base = 0L
+gdt_48:
+       .word   gdt_end-gdt-1                   # gdt limit
+       .word   0, 0                            # gdt base (filled in later)
+
+# Include video setup & detection code
+
+#include "video.S"
+
+# Setup signature -- must be last
+setup_sig1:    .word   SIG1
+setup_sig2:    .word   SIG2
+
+# After this point, there is some free space which is used by the video mode
+# handling code to store the temporary mode table (not used by the kernel).
+
+modelist:
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
diff --git a/kitten/arch/x86_64/boot/tools/build.c b/kitten/arch/x86_64/boot/tools/build.c
new file mode 100644 (file)
index 0000000..b196722
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1997 Martin Mares
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect:  Compatibility mbr which prints an error message if
+ *              someone tries to boot the kernel directly.
+ * - setup:     8086 machine code, sets up system parm
+ * - vmlwk.bin: The "piggy" LWK kernel image.  The first part of the
+ *              image is the decompression code (compressed/head.o),
+ *              which begins executing at startup_32.  startup_32 then
+ *              uncompresses the real kernel image that follows it.
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
+/*
+ * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
+ * Rewritten by Martin Mares, April 1997
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <asm/boot.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long u32;
+
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
+
+/* Minimal number of setup sectors (see also bootsect.S) */
+#define SETUP_SECTS 4
+
+byte buf[1024];
+int fd;
+int is_big_kernel;
+
+void die(const char * str, ...)
+{
+       va_list args;
+       va_start(args, str);
+       vfprintf(stderr, str, args);
+       fputc('\n', stderr);
+       exit(1);
+}
+
+void file_open(const char *name)
+{
+       if ((fd = open(name, O_RDONLY, 0)) < 0)
+               die("Unable to open `%s': %m", name);
+}
+
+void usage(void)
+{
+       die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+}
+
+int main(int argc, char ** argv)
+{
+       unsigned int i, c, sz, setup_sectors;
+       u32 sys_size;
+       byte major_root, minor_root;
+       struct stat sb;
+
+       if (argc > 2 && !strcmp(argv[1], "-b"))
+         {
+           is_big_kernel = 1;
+           argc--, argv++;
+         }
+       if ((argc < 4) || (argc > 5))
+               usage();
+       if (argc > 4) {
+               if (!strcmp(argv[4], "CURRENT")) {
+                       if (stat("/", &sb)) {
+                               perror("/");
+                               die("Couldn't stat /");
+                       }
+                       major_root = major(sb.st_dev);
+                       minor_root = minor(sb.st_dev);
+               } else if (strcmp(argv[4], "FLOPPY")) {
+                       if (stat(argv[4], &sb)) {
+                               perror(argv[4]);
+                               die("Couldn't stat root device.");
+                       }
+                       major_root = major(sb.st_rdev);
+                       minor_root = minor(sb.st_rdev);
+               } else {
+                       major_root = 0;
+                       minor_root = 0;
+               }
+       } else {
+               major_root = DEFAULT_MAJOR_ROOT;
+               minor_root = DEFAULT_MINOR_ROOT;
+       }
+       fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+
+       file_open(argv[1]);
+       i = read(fd, buf, sizeof(buf));
+       fprintf(stderr,"Boot sector %d bytes.\n",i);
+       if (i != 512)
+               die("Boot block must be exactly 512 bytes");
+       if (buf[510] != 0x55 || buf[511] != 0xaa)
+               die("Boot block hasn't got boot flag (0xAA55)");
+       buf[508] = minor_root;
+       buf[509] = major_root;
+       if (write(1, buf, 512) != 512)
+               die("Write call failed");
+       close (fd);
+
+       file_open(argv[2]);                                 /* Copy the setup code */
+       for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
+               if (write(1, buf, c) != c)
+                       die("Write call failed");
+       if (c != 0)
+               die("read-error on `setup'");
+       close (fd);
+
+       setup_sectors = (i + 511) / 512;        /* Pad unused space with zeros */
+       /* for compatibility with ancient versions of LILO. */
+       if (setup_sectors < SETUP_SECTS)
+               setup_sectors = SETUP_SECTS;
+       fprintf(stderr, "Setup is %d bytes.\n", i);
+       memset(buf, 0, sizeof(buf));
+       while (i < setup_sectors * 512) {
+               c = setup_sectors * 512 - i;
+               if (c > sizeof(buf))
+                       c = sizeof(buf);
+               if (write(1, buf, c) != c)
+                       die("Write call failed");
+               i += c;
+       }
+
+       file_open(argv[3]);
+       if (fstat (fd, &sb))
+               die("Unable to stat `%s': %m", argv[3]);
+       sz = sb.st_size;
+       fprintf (stderr, "System is %d kB\n", sz/1024);
+       sys_size = (sz + 15) / 16;
+       /* 0x40000*16 = 4.0 MB, reasonable estimate for the current maximum */
+       if (sys_size > (is_big_kernel ? 0x40000 : DEF_SYSSIZE))
+               die("System is too big. Try using %smodules.",
+                       is_big_kernel ? "" : "bzImage or ");
+       while (sz > 0) {
+               int l, n;
+
+               l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
+               if ((n=read(fd, buf, l)) != l) {
+                       if (n < 0)
+                               die("Error reading %s: %m", argv[3]);
+                       else
+                               die("%s: Unexpected EOF", argv[3]);
+               }
+               if (write(1, buf, l) != l)
+                       die("Write failed");
+               sz -= l;
+       }
+       close(fd);
+
+       if (lseek(1, 497, SEEK_SET) != 497)                 /* Write sizes to the bootsector */
+               die("Output: seek failed");
+       buf[0] = setup_sectors;
+       if (write(1, buf, 1) != 1)
+               die("Write of setup sector count failed");
+       if (lseek(1, 500, SEEK_SET) != 500)
+               die("Output: seek failed");
+       buf[0] = (sys_size & 0xff);
+       buf[1] = ((sys_size >> 8) & 0xff);
+       buf[2] = ((sys_size >> 16) & 0xff);
+       buf[3] = ((sys_size >> 24) & 0xff);
+       if (write(1, buf, 4) != 4)
+               die("Write of image length failed");
+
+       return 0;                                           /* Everything is OK */
+}
diff --git a/kitten/arch/x86_64/boot/video.S b/kitten/arch/x86_64/boot/video.S
new file mode 100644 (file)
index 0000000..95bfcd3
--- /dev/null
@@ -0,0 +1,2010 @@
+/*     video.S
+ *
+ *     Display adapter & video mode setup, version 2.13 (14-May-99)
+ *
+ *     Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
+ *     Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
+ *
+ *     Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
+ *
+ *     For further information, look at Documentation/svga.txt.
+ *
+ */
+
+/* Enable autodetection of SVGA adapters and modes. */
+#undef CONFIG_VIDEO_SVGA
+
+/* Enable autodetection of VESA modes */
+#define CONFIG_VIDEO_VESA
+
+/* Enable compacting of mode table */
+#define CONFIG_VIDEO_COMPACT
+
+/* Retain screen contents when switching modes */
+#define CONFIG_VIDEO_RETAIN
+
+/* Enable local mode list */
+#undef CONFIG_VIDEO_LOCAL
+
+/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
+#undef CONFIG_VIDEO_400_HACK
+
+/* Hack that lets you force specific BIOS mode ID and specific dimensions */
+#undef CONFIG_VIDEO_GFX_HACK
+#define VIDEO_GFX_BIOS_AX 0x4f02       /* 800x600 on ThinkPad */
+#define VIDEO_GFX_BIOS_BX 0x0102
+#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425      /* 100x37 */
+
+/* This code uses an extended set of video mode numbers. These include:
+ * Aliases for standard modes
+ *     NORMAL_VGA (-1)
+ *     EXTENDED_VGA (-2)
+ *     ASK_VGA (-3)
+ * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+ * of compatibility when extending the table. These are between 0x00 and 0xff.
+ */
+#define VIDEO_FIRST_MENU 0x0000
+
+/* Standard BIOS video modes (BIOS number + 0x0100) */
+#define VIDEO_FIRST_BIOS 0x0100
+
+/* VESA BIOS video modes (VESA number + 0x0200) */
+#define VIDEO_FIRST_VESA 0x0200
+
+/* Video7 special modes (BIOS number + 0x0900) */
+#define VIDEO_FIRST_V7 0x0900
+
+/* Special video modes */
+#define VIDEO_FIRST_SPECIAL 0x0f00
+#define VIDEO_80x25 0x0f00
+#define VIDEO_8POINT 0x0f01
+#define VIDEO_80x43 0x0f02
+#define VIDEO_80x28 0x0f03
+#define VIDEO_CURRENT_MODE 0x0f04
+#define VIDEO_80x30 0x0f05
+#define VIDEO_80x34 0x0f06
+#define VIDEO_80x60 0x0f07
+#define VIDEO_GFX_HACK 0x0f08
+#define VIDEO_LAST_SPECIAL 0x0f09
+
+/* Video modes given by resolution */
+#define VIDEO_FIRST_RESOLUTION 0x1000
+
+/* The "recalculate timings" flag */
+#define VIDEO_RECALC 0x8000
+
+/* Positions of various video parameters passed to the kernel */
+/* (see also include/linux/tty.h) */
+#define PARAM_CURSOR_POS       0x00
+#define PARAM_VIDEO_PAGE       0x04
+#define PARAM_VIDEO_MODE       0x06
+#define PARAM_VIDEO_COLS       0x07
+#define PARAM_VIDEO_EGA_BX     0x0a
+#define PARAM_VIDEO_LINES      0x0e
+#define PARAM_HAVE_VGA         0x0f
+#define PARAM_FONT_POINTS      0x10
+
+#define PARAM_LFB_WIDTH                0x12
+#define PARAM_LFB_HEIGHT       0x14
+#define PARAM_LFB_DEPTH                0x16
+#define PARAM_LFB_BASE         0x18
+#define PARAM_LFB_SIZE         0x1c
+#define PARAM_LFB_LINELENGTH   0x24
+#define PARAM_LFB_COLORS       0x26
+#define PARAM_VESAPM_SEG       0x2e
+#define PARAM_VESAPM_OFF       0x30
+#define PARAM_LFB_PAGES                0x32
+#define PARAM_VESA_ATTRIB      0x34
+#define PARAM_CAPABILITIES     0x36
+
+/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
+#ifdef CONFIG_VIDEO_RETAIN
+#define DO_STORE call store_screen
+#else
+#define DO_STORE
+#endif /* CONFIG_VIDEO_RETAIN */
+
+# This is the main entry point called by setup.S
+# %ds *must* be pointing to the bootsector
+video: pushw   %ds             # We use different segments
+       pushw   %ds             # FS contains original DS
+       popw    %fs
+       pushw   %cs             # DS is equal to CS
+       popw    %ds
+       pushw   %cs             # ES is equal to CS
+       popw    %es
+       xorw    %ax, %ax
+       movw    %ax, %gs        # GS is zero
+       cld
+       call    basic_detect    # Basic adapter type testing (EGA/VGA/MDA/CGA)
+#ifdef CONFIG_VIDEO_SELECT
+       movw    %fs:(0x01fa), %ax               # User selected video mode
+       cmpw    $ASK_VGA, %ax                   # Bring up the menu
+       jz      vid2
+
+       call    mode_set                        # Set the mode
+       jc      vid1
+
+       leaw    badmdt, %si                     # Invalid mode ID
+       call    prtstr
+vid2:  call    mode_menu
+vid1:
+#ifdef CONFIG_VIDEO_RETAIN
+       call    restore_screen                  # Restore screen contents
+#endif /* CONFIG_VIDEO_RETAIN */
+       call    store_edid
+#endif /* CONFIG_VIDEO_SELECT */
+       call    mode_params                     # Store mode parameters
+       popw    %ds                             # Restore original DS
+       ret
+
+# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
+basic_detect:
+       movb    $0, %fs:(PARAM_HAVE_VGA)
+       movb    $0x12, %ah      # Check EGA/VGA
+       movb    $0x10, %bl
+       int     $0x10
+       movw    %bx, %fs:(PARAM_VIDEO_EGA_BX)   # Identifies EGA to the kernel
+       cmpb    $0x10, %bl                      # No, it's a CGA/MDA/HGA card.
+       je      basret
+
+       incb    adapter
+       movw    $0x1a00, %ax                    # Check EGA or VGA?
+       int     $0x10
+       cmpb    $0x1a, %al                      # 1a means VGA...
+       jne     basret                          # anything else is EGA.
+       
+       incb    %fs:(PARAM_HAVE_VGA)            # We've detected a VGA
+       incb    adapter
+basret:        ret
+
+# Store the video mode parameters for later usage by the kernel.
+# This is done by asking the BIOS except for the rows/columns
+# parameters in the default 80x25 mode -- these are set directly,
+# because some very obscure BIOSes supply insane values.
+mode_params:
+#ifdef CONFIG_VIDEO_SELECT
+       cmpb    $0, graphic_mode
+       jnz     mopar_gr
+#endif
+       movb    $0x03, %ah                      # Read cursor position
+       xorb    %bh, %bh
+       int     $0x10
+       movw    %dx, %fs:(PARAM_CURSOR_POS)
+       movb    $0x0f, %ah                      # Read page/mode/width
+       int     $0x10
+       movw    %bx, %fs:(PARAM_VIDEO_PAGE)
+       movw    %ax, %fs:(PARAM_VIDEO_MODE)     # Video mode and screen width
+       cmpb    $0x7, %al                       # MDA/HGA => segment differs
+       jnz     mopar0
+
+       movw    $0xb000, video_segment
+mopar0: movw   %gs:(0x485), %ax                # Font size
+       movw    %ax, %fs:(PARAM_FONT_POINTS)    # (valid only on EGA/VGA)
+       movw    force_size, %ax                 # Forced size?
+       orw     %ax, %ax
+       jz      mopar1
+
+       movb    %ah, %fs:(PARAM_VIDEO_COLS)
+       movb    %al, %fs:(PARAM_VIDEO_LINES)
+       ret
+
+mopar1:        movb    $25, %al
+       cmpb    $0, adapter                     # If we are on CGA/MDA/HGA, the
+       jz      mopar2                          # screen must have 25 lines.
+
+       movb    %gs:(0x484), %al                # On EGA/VGA, use the EGA+ BIOS
+       incb    %al                             # location of max lines.
+mopar2: movb   %al, %fs:(PARAM_VIDEO_LINES)
+       ret
+
+#ifdef CONFIG_VIDEO_SELECT
+# Fetching of VESA frame buffer parameters
+mopar_gr:
+       leaw    modelist+1024, %di
+       movb    $0x23, %fs:(PARAM_HAVE_VGA)
+       movw    16(%di), %ax
+       movw    %ax, %fs:(PARAM_LFB_LINELENGTH)
+       movw    18(%di), %ax
+       movw    %ax, %fs:(PARAM_LFB_WIDTH)
+       movw    20(%di), %ax
+       movw    %ax, %fs:(PARAM_LFB_HEIGHT)
+       movb    25(%di), %al
+       movb    $0, %ah
+       movw    %ax, %fs:(PARAM_LFB_DEPTH)
+       movb    29(%di), %al    
+       movb    $0, %ah
+       movw    %ax, %fs:(PARAM_LFB_PAGES)
+       movl    40(%di), %eax
+       movl    %eax, %fs:(PARAM_LFB_BASE)
+       movl    31(%di), %eax
+       movl    %eax, %fs:(PARAM_LFB_COLORS)
+       movl    35(%di), %eax
+       movl    %eax, %fs:(PARAM_LFB_COLORS+4)
+       movw    0(%di), %ax
+       movw    %ax, %fs:(PARAM_VESA_ATTRIB)
+
+# get video mem size
+       leaw    modelist+1024, %di
+       movw    $0x4f00, %ax
+       int     $0x10
+       xorl    %eax, %eax
+       movw    18(%di), %ax
+       movl    %eax, %fs:(PARAM_LFB_SIZE)
+
+# store mode capabilities
+       movl 10(%di), %eax
+       movl %eax, %fs:(PARAM_CAPABILITIES)
+
+# switching the DAC to 8-bit is for <= 8 bpp only
+       movw    %fs:(PARAM_LFB_DEPTH), %ax
+       cmpw    $8, %ax
+       jg      dac_done
+
+# get DAC switching capability
+       xorl    %eax, %eax
+       movb    10(%di), %al
+       testb   $1, %al
+       jz      dac_set
+
+# attempt to switch DAC to 8-bit
+       movw    $0x4f08, %ax
+       movw    $0x0800, %bx
+       int     $0x10
+       cmpw    $0x004f, %ax
+       jne     dac_set
+       movb    %bh, dac_size           # store actual DAC size
+
+dac_set:
+# set color size to DAC size
+       movb    dac_size, %al
+       movb    %al, %fs:(PARAM_LFB_COLORS+0)
+       movb    %al, %fs:(PARAM_LFB_COLORS+2)
+       movb    %al, %fs:(PARAM_LFB_COLORS+4)
+       movb    %al, %fs:(PARAM_LFB_COLORS+6)
+
+# set color offsets to 0
+       movb    $0, %fs:(PARAM_LFB_COLORS+1)
+       movb    $0, %fs:(PARAM_LFB_COLORS+3)
+       movb    $0, %fs:(PARAM_LFB_COLORS+5)
+       movb    $0, %fs:(PARAM_LFB_COLORS+7)
+
+dac_done:
+# get protected mode interface informations
+       movw    $0x4f0a, %ax
+       xorw    %bx, %bx
+       xorw    %di, %di
+       int     $0x10
+       cmp     $0x004f, %ax
+       jnz     no_pm
+
+       movw    %es, %fs:(PARAM_VESAPM_SEG)
+       movw    %di, %fs:(PARAM_VESAPM_OFF)
+no_pm: ret
+
+# The video mode menu
+mode_menu:
+       leaw    keymsg, %si                     # "Return/Space/Timeout" message
+       call    prtstr
+       call    flush
+nokey: call    getkt
+
+       cmpb    $0x0d, %al                      # ENTER ?
+       je      listm                           # yes - manual mode selection
+
+       cmpb    $0x20, %al                      # SPACE ?
+       je      defmd1                          # no - repeat
+
+       call    beep
+       jmp     nokey
+
+defmd1:        ret                                     # No mode chosen? Default 80x25
+
+listm: call    mode_table                      # List mode table
+listm0:        leaw    name_bann, %si                  # Print adapter name
+       call    prtstr
+       movw    card_name, %si
+       orw     %si, %si
+       jnz     an2
+
+       movb    adapter, %al
+       leaw    old_name, %si
+       orb     %al, %al
+       jz      an1
+
+       leaw    ega_name, %si
+       decb    %al
+       jz      an1
+
+       leaw    vga_name, %si
+       jmp     an1
+
+an2:   call    prtstr
+       leaw    svga_name, %si
+an1:   call    prtstr
+       leaw    listhdr, %si                    # Table header
+       call    prtstr
+       movb    $0x30, %dl                      # DL holds mode number
+       leaw    modelist, %si
+lm1:   cmpw    $ASK_VGA, (%si)                 # End?
+       jz      lm2
+
+       movb    %dl, %al                        # Menu selection number
+       call    prtchr
+       call    prtsp2
+       lodsw
+       call    prthw                           # Mode ID
+       call    prtsp2
+       movb    0x1(%si), %al
+       call    prtdec                          # Rows
+       movb    $0x78, %al                      # the letter 'x'
+       call    prtchr
+       lodsw
+       call    prtdec                          # Columns
+       movb    $0x0d, %al                      # New line
+       call    prtchr
+       movb    $0x0a, %al
+       call    prtchr
+       incb    %dl                             # Next character
+       cmpb    $0x3a, %dl
+       jnz     lm1
+
+       movb    $0x61, %dl
+       jmp     lm1
+
+lm2:   leaw    prompt, %si                     # Mode prompt
+       call    prtstr
+       leaw    edit_buf, %di                   # Editor buffer
+lm3:   call    getkey
+       cmpb    $0x0d, %al                      # Enter?
+       jz      lment
+
+       cmpb    $0x08, %al                      # Backspace?
+       jz      lmbs
+
+       cmpb    $0x20, %al                      # Printable?
+       jc      lm3
+
+       cmpw    $edit_buf+4, %di                # Enough space?
+       jz      lm3
+
+       stosb
+       call    prtchr
+       jmp     lm3
+
+lmbs:  cmpw    $edit_buf, %di                  # Backspace
+       jz      lm3
+
+       decw    %di
+       movb    $0x08, %al
+       call    prtchr
+       call    prtspc
+       movb    $0x08, %al
+       call    prtchr
+       jmp     lm3
+       
+lment: movb    $0, (%di)
+       leaw    crlft, %si
+       call    prtstr
+       leaw    edit_buf, %si
+       cmpb    $0, (%si)                       # Empty string = default mode
+       jz      lmdef
+
+       cmpb    $0, 1(%si)                      # One character = menu selection
+       jz      mnusel
+
+       cmpw    $0x6373, (%si)                  # "scan" => mode scanning
+       jnz     lmhx
+
+       cmpw    $0x6e61, 2(%si)
+       jz      lmscan
+
+lmhx:  xorw    %bx, %bx                        # Else => mode ID in hex
+lmhex: lodsb
+       orb     %al, %al
+       jz      lmuse1
+
+       subb    $0x30, %al
+       jc      lmbad
+
+       cmpb    $10, %al
+       jc      lmhx1
+
+       subb    $7, %al
+       andb    $0xdf, %al
+       cmpb    $10, %al
+       jc      lmbad
+
+       cmpb    $16, %al
+       jnc     lmbad
+
+lmhx1: shlw    $4, %bx
+       orb     %al, %bl
+       jmp     lmhex
+
+lmuse1:        movw    %bx, %ax
+       jmp     lmuse
+
+mnusel:        lodsb                                   # Menu selection
+       xorb    %ah, %ah
+       subb    $0x30, %al
+       jc      lmbad
+
+       cmpb    $10, %al
+       jc      lmuse
+       
+       cmpb    $0x61-0x30, %al
+       jc      lmbad
+       
+       subb    $0x61-0x30-10, %al
+       cmpb    $36, %al
+       jnc     lmbad
+
+lmuse: call    mode_set
+       jc      lmdef
+
+lmbad: leaw    unknt, %si
+       call    prtstr
+       jmp     lm2
+lmscan:        cmpb    $0, adapter                     # Scanning only on EGA/VGA
+       jz      lmbad
+
+       movw    $0, mt_end                      # Scanning of modes is
+       movb    $1, scanning                    # done as new autodetection.
+       call    mode_table
+       jmp     listm0
+lmdef: ret
+
+# Additional parts of mode_set... (relative jumps, you know)
+setv7:                                         # Video7 extended modes
+       DO_STORE
+       subb    $VIDEO_FIRST_V7>>8, %bh
+       movw    $0x6f05, %ax
+       int     $0x10
+       stc
+       ret
+
+_setrec:       jmp     setrec                  # Ugly...
+_set_80x25:    jmp     set_80x25
+
+# Aliases for backward compatibility.
+setalias:
+       movw    $VIDEO_80x25, %ax
+       incw    %bx
+       jz      mode_set
+
+       movb    $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
+       incw    %bx
+       jnz     setbad                          # Fall-through!
+
+# Setting of user mode (AX=mode ID) => CF=success
+mode_set:
+       movw    %ax, %fs:(0x01fa)               # Store mode for use in acpi_wakeup.S
+       movw    %ax, %bx
+       cmpb    $0xff, %ah
+       jz      setalias
+
+       testb   $VIDEO_RECALC>>8, %ah
+       jnz     _setrec
+
+       cmpb    $VIDEO_FIRST_RESOLUTION>>8, %ah
+       jnc     setres
+       
+       cmpb    $VIDEO_FIRST_SPECIAL>>8, %ah
+       jz      setspc
+       
+       cmpb    $VIDEO_FIRST_V7>>8, %ah
+       jz      setv7
+       
+       cmpb    $VIDEO_FIRST_VESA>>8, %ah
+       jnc     check_vesa
+       
+       orb     %ah, %ah
+       jz      setmenu
+       
+       decb    %ah
+       jz      setbios
+
+setbad:        clc
+       movb    $0, do_restore                  # The screen needn't be restored
+       ret
+
+setvesa:
+       DO_STORE
+       subb    $VIDEO_FIRST_VESA>>8, %bh
+       movw    $0x4f02, %ax                    # VESA BIOS mode set call
+       int     $0x10
+       cmpw    $0x004f, %ax                    # AL=4f if implemented
+       jnz     setbad                          # AH=0 if OK
+
+       stc
+       ret
+
+setbios:
+       DO_STORE
+       int     $0x10                           # Standard BIOS mode set call
+       pushw   %bx
+       movb    $0x0f, %ah                      # Check if really set
+       int     $0x10
+       popw    %bx
+       cmpb    %bl, %al
+       jnz     setbad
+       
+       stc
+       ret
+
+setspc:        xorb    %bh, %bh                        # Set special mode
+       cmpb    $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
+       jnc     setbad
+       
+       addw    %bx, %bx
+       jmp     *spec_inits(%bx)
+
+setmenu:
+       orb     %al, %al                        # 80x25 is an exception
+       jz      _set_80x25
+       
+       pushw   %bx                             # Set mode chosen from menu
+       call    mode_table                      # Build the mode table
+       popw    %ax
+       shlw    $2, %ax
+       addw    %ax, %si
+       cmpw    %di, %si
+       jnc     setbad
+       
+       movw    (%si), %ax                      # Fetch mode ID
+_m_s:  jmp     mode_set
+
+setres:        pushw   %bx                             # Set mode chosen by resolution
+       call    mode_table
+       popw    %bx
+       xchgb   %bl, %bh
+setr1: lodsw
+       cmpw    $ASK_VGA, %ax                   # End of the list?
+       jz      setbad
+       
+       lodsw
+       cmpw    %bx, %ax
+       jnz     setr1
+       
+       movw    -4(%si), %ax                    # Fetch mode ID
+       jmp     _m_s
+
+check_vesa:
+       leaw    modelist+1024, %di
+       subb    $VIDEO_FIRST_VESA>>8, %bh
+       movw    %bx, %cx                        # Get mode information structure
+       movw    $0x4f01, %ax
+       int     $0x10
+       addb    $VIDEO_FIRST_VESA>>8, %bh
+       cmpw    $0x004f, %ax
+       jnz     setbad
+
+       movb    (%di), %al                      # Check capabilities.
+       andb    $0x19, %al
+       cmpb    $0x09, %al
+       jz      setvesa                         # This is a text mode
+
+       movb    (%di), %al                      # Check capabilities.
+       andb    $0x99, %al
+       cmpb    $0x99, %al
+       jnz     _setbad                         # Doh! No linear frame buffer.
+
+       subb    $VIDEO_FIRST_VESA>>8, %bh
+       orw     $0x4000, %bx                    # Use linear frame buffer
+       movw    $0x4f02, %ax                    # VESA BIOS mode set call
+       int     $0x10
+       cmpw    $0x004f, %ax                    # AL=4f if implemented
+       jnz     _setbad                         # AH=0 if OK
+
+       movb    $1, graphic_mode                # flag graphic mode
+       movb    $0, do_restore                  # no screen restore
+       stc
+       ret
+
+_setbad:       jmp     setbad                  # Ugly...
+
+# Recalculate vertical display end registers -- this fixes various
+# inconsistencies of extended modes on many adapters. Called when
+# the VIDEO_RECALC flag is set in the mode ID.
+
+setrec:        subb    $VIDEO_RECALC>>8, %ah           # Set the base mode
+       call    mode_set
+       jnc     rct3
+
+       movw    %gs:(0x485), %ax                # Font size in pixels
+       movb    %gs:(0x484), %bl                # Number of rows
+       incb    %bl
+       mulb    %bl                             # Number of visible
+       decw    %ax                             # scan lines - 1
+       movw    $0x3d4, %dx
+       movw    %ax, %bx
+       movb    $0x12, %al                      # Lower 8 bits
+       movb    %bl, %ah
+       outw    %ax, %dx
+       movb    $0x07, %al              # Bits 8 and 9 in the overflow register
+       call    inidx
+       xchgb   %al, %ah
+       andb    $0xbd, %ah
+       shrb    %bh
+       jnc     rct1
+       orb     $0x02, %ah
+rct1:  shrb    %bh
+       jnc     rct2
+       orb     $0x40, %ah
+rct2:  movb    $0x07, %al
+       outw    %ax, %dx
+       stc
+rct3:  ret
+
+# Table of routines for setting of the special modes.
+spec_inits:
+       .word   set_80x25
+       .word   set_8pixel
+       .word   set_80x43
+       .word   set_80x28
+       .word   set_current
+       .word   set_80x30
+       .word   set_80x34
+       .word   set_80x60
+       .word   set_gfx
+
+# Set the 80x25 mode. If already set, do nothing.
+set_80x25:
+       movw    $0x5019, force_size             # Override possibly broken BIOS
+use_80x25:
+#ifdef CONFIG_VIDEO_400_HACK
+       movw    $0x1202, %ax                    # Force 400 scan lines
+       movb    $0x30, %bl
+       int     $0x10
+#else
+       movb    $0x0f, %ah                      # Get current mode ID
+       int     $0x10
+       cmpw    $0x5007, %ax    # Mode 7 (80x25 mono) is the only one available
+       jz      st80            # on CGA/MDA/HGA and is also available on EGAM
+
+       cmpw    $0x5003, %ax    # Unknown mode, force 80x25 color
+       jnz     force3
+
+st80:  cmpb    $0, adapter     # CGA/MDA/HGA => mode 3/7 is always 80x25
+       jz      set80
+
+       movb    %gs:(0x0484), %al       # This is EGA+ -- beware of 80x50 etc.
+       orb     %al, %al                # Some buggy BIOS'es set 0 rows
+       jz      set80
+       
+       cmpb    $24, %al                # It's hopefully correct
+       jz      set80
+#endif /* CONFIG_VIDEO_400_HACK */
+force3:        DO_STORE
+       movw    $0x0003, %ax                    # Forced set
+       int     $0x10
+set80: stc
+       ret
+
+# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
+set_8pixel:
+       DO_STORE
+       call    use_80x25                       # The base is 80x25
+set_8pt:
+       movw    $0x1112, %ax                    # Use 8x8 font
+       xorb    %bl, %bl
+       int     $0x10
+       movw    $0x1200, %ax                    # Use alternate print screen
+       movb    $0x20, %bl
+       int     $0x10
+       movw    $0x1201, %ax                    # Turn off cursor emulation
+       movb    $0x34, %bl
+       int     $0x10
+       movb    $0x01, %ah                      # Define cursor scan lines 6-7
+       movw    $0x0607, %cx
+       int     $0x10
+set_current:
+       stc
+       ret
+
+# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
+# 80x25 mode with 14-point fonts instead of 16-point.
+set_80x28:
+       DO_STORE
+       call    use_80x25                       # The base is 80x25
+set14: movw    $0x1111, %ax                    # Use 9x14 font
+       xorb    %bl, %bl
+       int     $0x10
+       movb    $0x01, %ah                      # Define cursor scan lines 11-12
+       movw    $0x0b0c, %cx
+       int     $0x10
+       stc
+       ret
+
+# Set the 80x43 mode. This mode is works on all VGA's.
+# It's a 350-scanline mode with 8-pixel font.
+set_80x43:
+       DO_STORE
+       movw    $0x1201, %ax                    # Set 350 scans
+       movb    $0x30, %bl
+       int     $0x10
+       movw    $0x0003, %ax                    # Reset video mode
+       int     $0x10
+       jmp     set_8pt                         # Use 8-pixel font
+
+# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
+set_80x30:
+       call    use_80x25                       # Start with real 80x25
+       DO_STORE
+       movw    $0x3cc, %dx                     # Get CRTC port
+       inb     %dx, %al
+       movb    $0xd4, %dl
+       rorb    %al                             # Mono or color?
+       jc      set48a
+
+       movb    $0xb4, %dl
+set48a:        movw    $0x0c11, %ax            # Vertical sync end (also unlocks CR0-7)
+       call    outidx
+       movw    $0x0b06, %ax                    # Vertical total
+       call    outidx
+       movw    $0x3e07, %ax                    # (Vertical) overflow
+       call    outidx
+       movw    $0xea10, %ax                    # Vertical sync start
+       call    outidx
+       movw    $0xdf12, %ax                    # Vertical display end
+       call    outidx
+       movw    $0xe715, %ax                    # Vertical blank start
+       call    outidx
+       movw    $0x0416, %ax                    # Vertical blank end
+       call    outidx
+       pushw   %dx
+       movb    $0xcc, %dl                      # Misc output register (read)
+       inb     %dx, %al
+       movb    $0xc2, %dl                      # (write)
+       andb    $0x0d, %al      # Preserve clock select bits and color bit
+       orb     $0xe2, %al                      # Set correct sync polarity
+       outb    %al, %dx
+       popw    %dx
+       movw    $0x501e, force_size
+       stc                                     # That's all.
+       ret
+
+# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
+set_80x34:
+       call    set_80x30                       # Set 480 scans
+       call    set14                           # And 14-pt font
+       movw    $0xdb12, %ax                    # VGA vertical display end
+       movw    $0x5022, force_size
+setvde:        call    outidx
+       stc
+       ret
+
+# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
+set_80x60:
+       call    set_80x30                       # Set 480 scans
+       call    set_8pt                         # And 8-pt font
+       movw    $0xdf12, %ax                    # VGA vertical display end
+       movw    $0x503c, force_size
+       jmp     setvde
+
+# Special hack for ThinkPad graphics
+set_gfx:
+#ifdef CONFIG_VIDEO_GFX_HACK
+       movw    $VIDEO_GFX_BIOS_AX, %ax
+       movw    $VIDEO_GFX_BIOS_BX, %bx
+       int     $0x10
+       movw    $VIDEO_GFX_DUMMY_RESOLUTION, force_size
+       stc
+#endif
+       ret
+
+#ifdef CONFIG_VIDEO_RETAIN
+
+# Store screen contents to temporary buffer.
+store_screen:
+       cmpb    $0, do_restore                  # Already stored?
+       jnz     stsr
+
+       testb   $CAN_USE_HEAP, loadflags        # Have we space for storing?
+       jz      stsr
+       
+       pushw   %ax
+       pushw   %bx
+       pushw   force_size                      # Don't force specific size
+       movw    $0, force_size
+       call    mode_params                     # Obtain params of current mode
+       popw    force_size
+       movb    %fs:(PARAM_VIDEO_LINES), %ah
+       movb    %fs:(PARAM_VIDEO_COLS), %al
+       movw    %ax, %bx                        # BX=dimensions
+       mulb    %ah
+       movw    %ax, %cx                        # CX=number of characters
+       addw    %ax, %ax                        # Calculate image size
+       addw    $modelist+1024+4, %ax
+       cmpw    heap_end_ptr, %ax
+       jnc     sts1                            # Unfortunately, out of memory
+
+       movw    %fs:(PARAM_CURSOR_POS), %ax     # Store mode params
+       leaw    modelist+1024, %di
+       stosw
+       movw    %bx, %ax
+       stosw
+       pushw   %ds                             # Store the screen
+       movw    video_segment, %ds
+       xorw    %si, %si
+       rep
+       movsw
+       popw    %ds
+       incb    do_restore                      # Screen will be restored later
+sts1:  popw    %bx
+       popw    %ax
+stsr:  ret
+
+# Restore screen contents from temporary buffer.
+restore_screen:
+       cmpb    $0, do_restore                  # Has the screen been stored?
+       jz      res1
+
+       call    mode_params                     # Get parameters of current mode
+       movb    %fs:(PARAM_VIDEO_LINES), %cl
+       movb    %fs:(PARAM_VIDEO_COLS), %ch
+       leaw    modelist+1024, %si              # Screen buffer
+       lodsw                                   # Set cursor position
+       movw    %ax, %dx
+       cmpb    %cl, %dh
+       jc      res2
+       
+       movb    %cl, %dh
+       decb    %dh
+res2:  cmpb    %ch, %dl
+       jc      res3
+       
+       movb    %ch, %dl
+       decb    %dl
+res3:  movb    $0x02, %ah
+       movb    $0x00, %bh
+       int     $0x10
+       lodsw                                   # Display size
+       movb    %ah, %dl                        # DL=number of lines
+       movb    $0, %ah                         # BX=phys. length of orig. line
+       movw    %ax, %bx
+       cmpb    %cl, %dl                        # Too many?
+       jc      res4
+
+       pushw   %ax
+       movb    %dl, %al
+       subb    %cl, %al
+       mulb    %bl
+       addw    %ax, %si
+       addw    %ax, %si
+       popw    %ax
+       movb    %cl, %dl
+res4:  cmpb    %ch, %al                        # Too wide?
+       jc      res5
+       
+       movb    %ch, %al                        # AX=width of src. line
+res5:  movb    $0, %cl
+       xchgb   %ch, %cl
+       movw    %cx, %bp                        # BP=width of dest. line
+       pushw   %es
+       movw    video_segment, %es
+       xorw    %di, %di                        # Move the data
+       addw    %bx, %bx                        # Convert BX and BP to _bytes_
+       addw    %bp, %bp
+res6:  pushw   %si
+       pushw   %di
+       movw    %ax, %cx
+       rep
+       movsw
+       popw    %di
+       popw    %si
+       addw    %bp, %di
+       addw    %bx, %si
+       decb    %dl
+       jnz     res6
+       
+       popw    %es                             # Done
+res1:  ret
+#endif /* CONFIG_VIDEO_RETAIN */
+
+# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
+outidx:        outb    %al, %dx
+       pushw   %ax
+       movb    %ah, %al
+       incw    %dx
+       outb    %al, %dx
+       decw    %dx
+       popw    %ax
+       ret
+
+# Build the table of video modes (stored after the setup.S code at the
+# `modelist' label. Each video mode record looks like:
+#      .word   MODE-ID         (our special mode ID (see above))
+#      .byte   rows            (number of rows)
+#      .byte   columns         (number of columns)
+# Returns address of the end of the table in DI, the end is marked
+# with a ASK_VGA ID.
+mode_table:
+       movw    mt_end, %di                     # Already filled?
+       orw     %di, %di
+       jnz     mtab1x
+       
+       leaw    modelist, %di                   # Store standard modes:
+       movl    $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
+       stosl
+       movb    adapter, %al                    # CGA/MDA/HGA -- no more modes
+       orb     %al, %al
+       jz      mtabe
+       
+       decb    %al
+       jnz     mtabv
+       
+       movl    $VIDEO_8POINT + 0x502b0000, %eax        # The 80x43 EGA mode
+       stosl
+       jmp     mtabe
+
+mtab1x:        jmp     mtab1
+
+mtabv: leaw    vga_modes, %si                  # All modes for std VGA
+       movw    $vga_modes_end-vga_modes, %cx
+       rep     # I'm unable to use movsw as I don't know how to store a half
+       movsb   # of the expression above to cx without using explicit shr.
+
+       cmpb    $0, scanning                    # Mode scan requested?
+       jz      mscan1
+       
+       call    mode_scan
+mscan1:
+
+#ifdef CONFIG_VIDEO_LOCAL
+       call    local_modes
+#endif /* CONFIG_VIDEO_LOCAL */
+
+#ifdef CONFIG_VIDEO_VESA
+       call    vesa_modes                      # Detect VESA VGA modes
+#endif /* CONFIG_VIDEO_VESA */
+
+#ifdef CONFIG_VIDEO_SVGA
+       cmpb    $0, scanning                    # Bypass when scanning
+       jnz     mscan2
+       
+       call    svga_modes                      # Detect SVGA cards & modes
+mscan2:
+#endif /* CONFIG_VIDEO_SVGA */
+
+mtabe:
+
+#ifdef CONFIG_VIDEO_COMPACT
+       leaw    modelist, %si
+       movw    %di, %dx
+       movw    %si, %di
+cmt1:  cmpw    %dx, %si                        # Scan all modes
+       jz      cmt2
+
+       leaw    modelist, %bx                   # Find in previous entries
+       movw    2(%si), %cx
+cmt3:  cmpw    %bx, %si
+       jz      cmt4
+
+       cmpw    2(%bx), %cx                     # Found => don't copy this entry
+       jz      cmt5
+
+       addw    $4, %bx
+       jmp     cmt3
+
+cmt4:  movsl                                   # Copy entry
+       jmp     cmt1
+
+cmt5:  addw    $4, %si                         # Skip entry
+       jmp     cmt1
+
+cmt2:
+#endif /* CONFIG_VIDEO_COMPACT */
+
+       movw    $ASK_VGA, (%di)                 # End marker
+       movw    %di, mt_end
+mtab1: leaw    modelist, %si                   # SI=mode list, DI=list end
+ret0:  ret
+
+# Modes usable on all standard VGAs
+vga_modes:
+       .word   VIDEO_8POINT
+       .word   0x5032                          # 80x50
+       .word   VIDEO_80x43
+       .word   0x502b                          # 80x43
+       .word   VIDEO_80x28
+       .word   0x501c                          # 80x28
+       .word   VIDEO_80x30
+       .word   0x501e                          # 80x30
+       .word   VIDEO_80x34
+       .word   0x5022                          # 80x34
+       .word   VIDEO_80x60
+       .word   0x503c                          # 80x60
+#ifdef CONFIG_VIDEO_GFX_HACK
+       .word   VIDEO_GFX_HACK
+       .word   VIDEO_GFX_DUMMY_RESOLUTION
+#endif
+
+vga_modes_end:
+# Detect VESA modes.
+
+#ifdef CONFIG_VIDEO_VESA
+vesa_modes:
+       cmpb    $2, adapter                     # VGA only
+       jnz     ret0
+
+       movw    %di, %bp                        # BP=original mode table end
+       addw    $0x200, %di                     # Buffer space
+       movw    $0x4f00, %ax                    # VESA Get card info call
+       int     $0x10
+       movw    %bp, %di
+       cmpw    $0x004f, %ax                    # Successful?
+       jnz     ret0
+       
+       cmpw    $0x4556, 0x200(%di)
+       jnz     ret0
+       
+       cmpw    $0x4153, 0x202(%di)
+       jnz     ret0
+       
+       movw    $vesa_name, card_name           # Set name to "VESA VGA"
+       pushw   %gs
+       lgsw    0x20e(%di), %si                 # GS:SI=mode list
+       movw    $128, %cx                       # Iteration limit
+vesa1:
+# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
+# XXX: lodsw   %gs:(%si), %ax                  # Get next mode in the list
+       gs; lodsw
+       cmpw    $0xffff, %ax                    # End of the table?
+       jz      vesar
+       
+       cmpw    $0x0080, %ax                    # Check validity of mode ID
+       jc      vesa2
+       
+       orb     %ah, %ah                # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
+       jz      vesan                   # Certain BIOSes report 0x80-0xff!
+
+       cmpw    $0x0800, %ax
+       jnc     vesae
+
+vesa2: pushw   %cx
+       movw    %ax, %cx                        # Get mode information structure
+       movw    $0x4f01, %ax
+       int     $0x10
+       movw    %cx, %bx                        # BX=mode number
+       addb    $VIDEO_FIRST_VESA>>8, %bh
+       popw    %cx
+       cmpw    $0x004f, %ax
+       jnz     vesan                   # Don't report errors (buggy BIOSES)
+
+       movb    (%di), %al                      # Check capabilities. We require
+       andb    $0x19, %al                      # a color text mode.
+       cmpb    $0x09, %al
+       jnz     vesan
+       
+       cmpw    $0xb800, 8(%di)         # Standard video memory address required
+       jnz     vesan
+
+       testb   $2, (%di)                       # Mode characteristics supplied?
+       movw    %bx, (%di)                      # Store mode number
+       jz      vesa3
+       
+       xorw    %dx, %dx
+       movw    0x12(%di), %bx                  # Width
+       orb     %bh, %bh
+       jnz     vesan
+       
+       movb    %bl, 0x3(%di)
+       movw    0x14(%di), %ax                  # Height
+       orb     %ah, %ah
+       jnz     vesan
+       
+       movb    %al, 2(%di)
+       mulb    %bl
+       cmpw    $8193, %ax              # Small enough for Linux console driver?
+       jnc     vesan
+
+       jmp     vesaok
+
+vesa3: subw    $0x8108, %bx    # This mode has no detailed info specified,
+       jc      vesan           # so it must be a standard VESA mode.
+
+       cmpw    $5, %bx
+       jnc     vesan
+
+       movw    vesa_text_mode_table(%bx), %ax
+       movw    %ax, 2(%di)
+vesaok:        addw    $4, %di                         # The mode is valid. Store it.
+vesan: loop    vesa1                   # Next mode. Limit exceeded => error
+vesae: leaw    vesaer, %si
+       call    prtstr
+       movw    %bp, %di                        # Discard already found modes.
+vesar: popw    %gs
+       ret
+
+# Dimensions of standard VESA text modes
+vesa_text_mode_table:
+       .byte   60, 80                          # 0108
+       .byte   25, 132                         # 0109
+       .byte   43, 132                         # 010A
+       .byte   50, 132                         # 010B
+       .byte   60, 132                         # 010C
+#endif /* CONFIG_VIDEO_VESA */
+
+# Scan for video modes. A bit dirty, but should work.
+mode_scan:
+       movw    $0x0100, %cx                    # Start with mode 0
+scm1:  movb    $0, %ah                         # Test the mode
+       movb    %cl, %al
+       int     $0x10
+       movb    $0x0f, %ah
+       int     $0x10
+       cmpb    %cl, %al
+       jnz     scm2                            # Mode not set
+
+       movw    $0x3c0, %dx                     # Test if it's a text mode
+       movb    $0x10, %al                      # Mode bits
+       call    inidx
+       andb    $0x03, %al
+       jnz     scm2
+       
+       movb    $0xce, %dl                      # Another set of mode bits
+       movb    $0x06, %al
+       call    inidx
+       shrb    %al
+       jc      scm2
+       
+       movb    $0xd4, %dl                      # Cursor location
+       movb    $0x0f, %al
+       call    inidx
+       orb     %al, %al
+       jnz     scm2
+       
+       movw    %cx, %ax                        # Ok, store the mode
+       stosw
+       movb    %gs:(0x484), %al                # Number of rows
+       incb    %al
+       stosb
+       movw    %gs:(0x44a), %ax                # Number of columns
+       stosb
+scm2:  incb    %cl
+       jns     scm1
+       
+       movw    $0x0003, %ax                    # Return back to mode 3
+       int     $0x10
+       ret
+
+tstidx:        outw    %ax, %dx                        # OUT DX,AX and inidx
+inidx: outb    %al, %dx                        # Read from indexed VGA register
+       incw    %dx                     # AL=index, DX=index reg port -> AL=data
+       inb     %dx, %al
+       decw    %dx
+       ret
+
+# Try to detect type of SVGA card and supply (usually approximate) video
+# mode table for it.
+
+#ifdef CONFIG_VIDEO_SVGA
+svga_modes:
+       leaw    svga_table, %si                 # Test all known SVGA adapters
+dosvga:        lodsw
+       movw    %ax, %bp                        # Default mode table
+       orw     %ax, %ax
+       jz      didsv1
+
+       lodsw                                   # Pointer to test routine
+       pushw   %si
+       pushw   %di
+       pushw   %es
+       movw    $0xc000, %bx
+       movw    %bx, %es
+       call    *%ax                            # Call test routine
+       popw    %es
+       popw    %di
+       popw    %si
+       orw     %bp, %bp
+       jz      dosvga
+       
+       movw    %bp, %si                        # Found, copy the modes
+       movb    svga_prefix, %ah
+cpsvga:        lodsb
+       orb     %al, %al
+       jz      didsv
+       
+       stosw
+       movsw
+       jmp     cpsvga
+
+didsv: movw    %si, card_name                  # Store pointer to card name
+didsv1:        ret
+
+# Table of all known SVGA cards. For each card, we store a pointer to
+# a table of video modes supported by the card and a pointer to a routine
+# used for testing of presence of the card. The video mode table is always
+# followed by the name of the card or the chipset.
+svga_table:
+       .word   ati_md, ati_test
+       .word   oak_md, oak_test
+       .word   paradise_md, paradise_test
+       .word   realtek_md, realtek_test
+       .word   s3_md, s3_test
+       .word   chips_md, chips_test
+       .word   video7_md, video7_test
+       .word   cirrus5_md, cirrus5_test
+       .word   cirrus6_md, cirrus6_test
+       .word   cirrus1_md, cirrus1_test
+       .word   ahead_md, ahead_test
+       .word   everex_md, everex_test
+       .word   genoa_md, genoa_test
+       .word   trident_md, trident_test
+       .word   tseng_md, tseng_test
+       .word   0
+
+# Test routines and mode tables:
+
+# S3 - The test algorithm was taken from the SuperProbe package
+# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
+s3_test:
+       movw    $0x0f35, %cx    # we store some constants in cl/ch
+       movw    $0x03d4, %dx
+       movb    $0x38, %al
+       call    inidx
+       movb    %al, %bh        # store current CRT-register 0x38
+       movw    $0x0038, %ax
+       call    outidx          # disable writing to special regs
+       movb    %cl, %al        # check whether we can write special reg 0x35
+       call    inidx
+       movb    %al, %bl        # save the current value of CRT reg 0x35
+       andb    $0xf0, %al      # clear bits 0-3
+       movb    %al, %ah
+       movb    %cl, %al        # and write it to CRT reg 0x35
+       call    outidx
+       call    inidx           # now read it back
+       andb    %ch, %al        # clear the upper 4 bits
+       jz      s3_2            # the first test failed. But we have a
+
+       movb    %bl, %ah        # second chance
+       movb    %cl, %al
+       call    outidx
+       jmp     s3_1            # do the other tests
+
+s3_2:  movw    %cx, %ax        # load ah with 0xf and al with 0x35
+       orb     %bl, %ah        # set the upper 4 bits of ah with the orig value
+       call    outidx          # write ...
+       call    inidx           # ... and reread 
+       andb    %cl, %al        # turn off the upper 4 bits
+       pushw   %ax
+       movb    %bl, %ah        # restore old value in register 0x35
+       movb    %cl, %al
+       call    outidx
+       popw    %ax
+       cmpb    %ch, %al        # setting lower 4 bits was successful => bad
+       je      no_s3           # writing is allowed => this is not an S3
+
+s3_1:  movw    $0x4838, %ax    # allow writing to special regs by putting
+       call    outidx          # magic number into CRT-register 0x38
+       movb    %cl, %al        # check whether we can write special reg 0x35
+       call    inidx
+       movb    %al, %bl
+       andb    $0xf0, %al
+       movb    %al, %ah
+       movb    %cl, %al
+       call    outidx
+       call    inidx
+       andb    %ch, %al
+       jnz     no_s3           # no, we can't write => no S3
+
+       movw    %cx, %ax
+       orb     %bl, %ah
+       call    outidx
+       call    inidx
+       andb    %ch, %al
+       pushw   %ax
+       movb    %bl, %ah        # restore old value in register 0x35
+       movb    %cl, %al
+       call    outidx
+       popw    %ax
+       cmpb    %ch, %al
+       jne     no_s31          # writing not possible => no S3
+       movb    $0x30, %al
+       call    inidx           # now get the S3 id ...
+       leaw    idS3, %di
+       movw    $0x10, %cx
+       repne
+       scasb
+       je      no_s31
+
+       movb    %bh, %ah
+       movb    $0x38, %al
+       jmp     s3rest
+
+no_s3: movb    $0x35, %al      # restore CRT register 0x35
+       movb    %bl, %ah
+       call    outidx
+no_s31:        xorw    %bp, %bp        # Detection failed
+s3rest:        movb    %bh, %ah
+       movb    $0x38, %al      # restore old value of CRT register 0x38
+       jmp     outidx
+
+idS3:  .byte   0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
+       .byte   0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
+
+s3_md: .byte   0x54, 0x2b, 0x84
+       .byte   0x55, 0x19, 0x84
+       .byte   0
+       .ascii  "S3"
+       .byte   0
+
+# ATI cards.
+ati_test:
+       leaw    idati, %si
+       movw    $0x31, %di
+       movw    $0x09, %cx
+       repe
+       cmpsb
+       je      atiok
+
+       xorw    %bp, %bp
+atiok: ret
+
+idati: .ascii  "761295520"
+
+ati_md:        .byte   0x23, 0x19, 0x84
+       .byte   0x33, 0x2c, 0x84
+       .byte   0x22, 0x1e, 0x64
+       .byte   0x21, 0x19, 0x64
+       .byte   0x58, 0x21, 0x50
+       .byte   0x5b, 0x1e, 0x50
+       .byte   0
+       .ascii  "ATI"
+       .byte   0
+
+# AHEAD
+ahead_test:
+       movw    $0x200f, %ax
+       movw    $0x3ce, %dx
+       outw    %ax, %dx
+       incw    %dx
+       inb     %dx, %al
+       cmpb    $0x20, %al
+       je      isahed
+
+       cmpb    $0x21, %al
+       je      isahed
+       
+       xorw    %bp, %bp
+isahed:        ret
+
+ahead_md:
+       .byte   0x22, 0x2c, 0x84
+       .byte   0x23, 0x19, 0x84
+       .byte   0x24, 0x1c, 0x84
+       .byte   0x2f, 0x32, 0xa0
+       .byte   0x32, 0x22, 0x50
+       .byte   0x34, 0x42, 0x50
+       .byte   0
+       .ascii  "Ahead"
+       .byte   0
+
+# Chips & Tech.
+chips_test:
+       movw    $0x3c3, %dx
+       inb     %dx, %al
+       orb     $0x10, %al
+       outb    %al, %dx
+       movw    $0x104, %dx
+       inb     %dx, %al
+       movb    %al, %bl
+       movw    $0x3c3, %dx
+       inb     %dx, %al
+       andb    $0xef, %al
+       outb    %al, %dx
+       cmpb    $0xa5, %bl
+       je      cantok
+       
+       xorw    %bp, %bp
+cantok:        ret
+
+chips_md:
+       .byte   0x60, 0x19, 0x84
+       .byte   0x61, 0x32, 0x84
+       .byte   0
+       .ascii  "Chips & Technologies"
+       .byte   0
+
+# Cirrus Logic 5X0
+cirrus1_test:
+       movw    $0x3d4, %dx
+       movb    $0x0c, %al
+       outb    %al, %dx
+       incw    %dx
+       inb     %dx, %al
+       movb    %al, %bl
+       xorb    %al, %al
+       outb    %al, %dx
+       decw    %dx
+       movb    $0x1f, %al
+       outb    %al, %dx
+       incw    %dx
+       inb     %dx, %al
+       movb    %al, %bh
+       xorb    %ah, %ah
+       shlb    $4, %al
+       movw    %ax, %cx
+       movb    %bh, %al
+       shrb    $4, %al
+       addw    %ax, %cx
+       shlw    $8, %cx
+       addw    $6, %cx
+       movw    %cx, %ax
+       movw    $0x3c4, %dx
+       outw    %ax, %dx
+       incw    %dx
+       inb     %dx, %al
+       andb    %al, %al
+       jnz     nocirr
+       
+       movb    %bh, %al
+       outb    %al, %dx
+       inb     %dx, %al
+       cmpb    $0x01, %al
+       je      iscirr
+
+nocirr:        xorw    %bp, %bp
+iscirr: movw   $0x3d4, %dx
+       movb    %bl, %al
+       xorb    %ah, %ah
+       shlw    $8, %ax
+       addw    $0x0c, %ax
+       outw    %ax, %dx
+       ret
+
+cirrus1_md:
+       .byte   0x1f, 0x19, 0x84
+       .byte   0x20, 0x2c, 0x84
+       .byte   0x22, 0x1e, 0x84
+       .byte   0x31, 0x25, 0x64
+       .byte   0
+       .ascii  "Cirrus Logic 5X0"
+       .byte   0
+
+# Cirrus Logic 54XX
+cirrus5_test:
+       movw    $0x3c4, %dx
+       movb    $6, %al
+       call    inidx
+       movb    %al, %bl                        # BL=backup
+       movw    $6, %ax
+       call    tstidx
+       cmpb    $0x0f, %al
+       jne     c5fail
+       
+       movw    $0x1206, %ax
+       call    tstidx
+       cmpb    $0x12, %al
+       jne     c5fail
+       
+       movb    $0x1e, %al
+       call    inidx
+       movb    %al, %bh
+       movb    %bh, %ah
+       andb    $0xc0, %ah
+       movb    $0x1e, %al
+       call    tstidx
+       andb    $0x3f, %al
+       jne     c5xx
+       
+       movb    $0x1e, %al
+       movb    %bh, %ah
+       orb     $0x3f, %ah
+       call    tstidx
+       xorb    $0x3f, %al
+       andb    $0x3f, %al
+c5xx:  pushf
+       movb    $0x1e, %al
+       movb    %bh, %ah
+       outw    %ax, %dx
+       popf
+       je      c5done
+
+c5fail:        xorw    %bp, %bp
+c5done:        movb    $6, %al
+       movb    %bl, %ah
+       outw    %ax, %dx
+       ret
+
+cirrus5_md:
+       .byte   0x14, 0x19, 0x84
+       .byte   0x54, 0x2b, 0x84
+       .byte   0
+       .ascii  "Cirrus Logic 54XX"
+       .byte   0
+
+# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
+# it's misidentified by the Ahead test.
+cirrus6_test:
+       movw    $0x3ce, %dx
+       movb    $0x0a, %al
+       call    inidx
+       movb    %al, %bl        # BL=backup
+       movw    $0xce0a, %ax
+       call    tstidx
+       orb     %al, %al
+       jne     c2fail
+       
+       movw    $0xec0a, %ax
+       call    tstidx
+       cmpb    $0x01, %al
+       jne     c2fail
+       
+       movb    $0xaa, %al
+       call    inidx           # 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
+       shrb    $4, %al
+       subb    $4, %al
+       jz      c6done
+       
+       decb    %al
+       jz      c6done
+       
+       subb    $2, %al
+       jz      c6done
+       
+       decb    %al
+       jz      c6done
+       
+c2fail:        xorw    %bp, %bp
+c6done:        movb    $0x0a, %al
+       movb    %bl, %ah
+       outw    %ax, %dx
+       ret
+
+cirrus6_md:
+       .byte   0
+       .ascii  "Cirrus Logic 64XX"
+       .byte   0
+
+# Everex / Trident
+everex_test:
+       movw    $0x7000, %ax
+       xorw    %bx, %bx
+       int     $0x10
+       cmpb    $0x70, %al
+       jne     noevrx
+       
+       shrw    $4, %dx
+       cmpw    $0x678, %dx
+       je      evtrid
+       
+       cmpw    $0x236, %dx
+       jne     evrxok
+
+evtrid:        leaw    trident_md, %bp
+evrxok:        ret
+
+noevrx:        xorw    %bp, %bp
+       ret
+
+everex_md:
+       .byte   0x03, 0x22, 0x50
+       .byte   0x04, 0x3c, 0x50
+       .byte   0x07, 0x2b, 0x64
+       .byte   0x08, 0x4b, 0x64
+       .byte   0x0a, 0x19, 0x84
+       .byte   0x0b, 0x2c, 0x84
+       .byte   0x16, 0x1e, 0x50
+       .byte   0x18, 0x1b, 0x64
+       .byte   0x21, 0x40, 0xa0
+       .byte   0x40, 0x1e, 0x84
+       .byte   0
+       .ascii  "Everex/Trident"
+       .byte   0
+
+# Genoa.
+genoa_test:
+       leaw    idgenoa, %si                    # Check Genoa 'clues'
+       xorw    %ax, %ax
+       movb    %es:(0x37), %al
+       movw    %ax, %di
+       movw    $0x04, %cx
+       decw    %si
+       decw    %di
+l1:    incw    %si
+       incw    %di
+       movb    (%si), %al
+       testb   %al, %al
+       jz      l2
+
+       cmpb    %es:(%di), %al
+l2:    loope   l1
+       orw     %cx, %cx
+       je      isgen
+       
+       xorw    %bp, %bp
+isgen: ret
+
+idgenoa: .byte 0x77, 0x00, 0x99, 0x66
+
+genoa_md:
+       .byte   0x58, 0x20, 0x50
+       .byte   0x5a, 0x2a, 0x64
+       .byte   0x60, 0x19, 0x84
+       .byte   0x61, 0x1d, 0x84
+       .byte   0x62, 0x20, 0x84
+       .byte   0x63, 0x2c, 0x84
+       .byte   0x64, 0x3c, 0x84
+       .byte   0x6b, 0x4f, 0x64
+       .byte   0x72, 0x3c, 0x50
+       .byte   0x74, 0x42, 0x50
+       .byte   0x78, 0x4b, 0x64
+       .byte   0
+       .ascii  "Genoa"
+       .byte   0
+
+# OAK
+oak_test:
+       leaw    idoakvga, %si
+       movw    $0x08, %di
+       movw    $0x08, %cx
+       repe
+       cmpsb
+       je      isoak
+       
+       xorw    %bp, %bp
+isoak: ret
+
+idoakvga: .ascii  "OAK VGA "
+
+oak_md: .byte  0x4e, 0x3c, 0x50
+       .byte   0x4f, 0x3c, 0x84
+       .byte   0x50, 0x19, 0x84
+       .byte   0x51, 0x2b, 0x84
+       .byte   0
+       .ascii  "OAK"
+       .byte   0
+
+# WD Paradise.
+paradise_test:
+       leaw    idparadise, %si
+       movw    $0x7d, %di
+       movw    $0x04, %cx
+       repe
+       cmpsb
+       je      ispara
+       
+       xorw    %bp, %bp
+ispara:        ret
+
+idparadise:    .ascii  "VGA="
+
+paradise_md:
+       .byte   0x41, 0x22, 0x50
+       .byte   0x47, 0x1c, 0x84
+       .byte   0x55, 0x19, 0x84
+       .byte   0x54, 0x2c, 0x84
+       .byte   0
+       .ascii  "Paradise"
+       .byte   0
+
+# Trident.
+trident_test:
+       movw    $0x3c4, %dx
+       movb    $0x0e, %al
+       outb    %al, %dx
+       incw    %dx
+       inb     %dx, %al
+       xchgb   %al, %ah
+       xorb    %al, %al
+       outb    %al, %dx
+       inb     %dx, %al
+       xchgb   %ah, %al
+       movb    %al, %bl        # Strange thing ... in the book this wasn't
+       andb    $0x02, %bl      # necessary but it worked on my card which
+       jz      setb2           # is a trident. Without it the screen goes
+                               # blurred ...
+       andb    $0xfd, %al
+       jmp     clrb2           
+
+setb2: orb     $0x02, %al      
+clrb2: outb    %al, %dx
+       andb    $0x0f, %ah
+       cmpb    $0x02, %ah
+       je      istrid
+
+       xorw    %bp, %bp
+istrid:        ret
+
+trident_md:
+       .byte   0x50, 0x1e, 0x50
+       .byte   0x51, 0x2b, 0x50
+       .byte   0x52, 0x3c, 0x50
+       .byte   0x57, 0x19, 0x84
+       .byte   0x58, 0x1e, 0x84
+       .byte   0x59, 0x2b, 0x84
+       .byte   0x5a, 0x3c, 0x84
+       .byte   0
+       .ascii  "Trident"
+       .byte   0
+
+# Tseng.
+tseng_test:
+       movw    $0x3cd, %dx
+       inb     %dx, %al        # Could things be this simple ! :-)
+       movb    %al, %bl
+       movb    $0x55, %al
+       outb    %al, %dx
+       inb     %dx, %al
+       movb    %al, %ah
+       movb    %bl, %al
+       outb    %al, %dx
+       cmpb    $0x55, %ah
+       je      istsen
+
+isnot: xorw    %bp, %bp
+istsen:        ret
+
+tseng_md:
+       .byte   0x26, 0x3c, 0x50
+       .byte   0x2a, 0x28, 0x64
+       .byte   0x23, 0x19, 0x84
+       .byte   0x24, 0x1c, 0x84
+       .byte   0x22, 0x2c, 0x84
+       .byte   0x21, 0x3c, 0x84
+       .byte   0
+       .ascii  "Tseng"
+       .byte   0
+
+# Video7.
+video7_test:
+       movw    $0x3cc, %dx
+       inb     %dx, %al
+       movw    $0x3b4, %dx
+       andb    $0x01, %al
+       jz      even7
+
+       movw    $0x3d4, %dx
+even7: movb    $0x0c, %al
+       outb    %al, %dx
+       incw    %dx
+       inb     %dx, %al
+       movb    %al, %bl
+       movb    $0x55, %al
+       outb    %al, %dx
+       inb     %dx, %al
+       decw    %dx
+       movb    $0x1f, %al
+       outb    %al, %dx
+       incw    %dx
+       inb     %dx, %al
+       movb    %al, %bh
+       decw    %dx
+       movb    $0x0c, %al
+       outb    %al, %dx
+       incw    %dx
+       movb    %bl, %al
+       outb    %al, %dx
+       movb    $0x55, %al
+       xorb    $0xea, %al
+       cmpb    %bh, %al
+       jne     isnot
+       
+       movb    $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
+       ret
+
+video7_md:
+       .byte   0x40, 0x2b, 0x50
+       .byte   0x43, 0x3c, 0x50
+       .byte   0x44, 0x3c, 0x64
+       .byte   0x41, 0x19, 0x84
+       .byte   0x42, 0x2c, 0x84
+       .byte   0x45, 0x1c, 0x84
+       .byte   0
+       .ascii  "Video 7"
+       .byte   0
+
+# Realtek VGA
+realtek_test:
+       leaw    idrtvga, %si
+       movw    $0x45, %di
+       movw    $0x0b, %cx
+       repe
+       cmpsb
+       je      isrt
+       
+       xorw    %bp, %bp
+isrt:  ret
+
+idrtvga:       .ascii  "REALTEK VGA"
+
+realtek_md:
+       .byte   0x1a, 0x3c, 0x50
+       .byte   0x1b, 0x19, 0x84
+       .byte   0x1c, 0x1e, 0x84
+       .byte   0x1d, 0x2b, 0x84
+       .byte   0x1e, 0x3c, 0x84
+       .byte   0
+       .ascii  "REALTEK"
+       .byte   0
+
+#endif /* CONFIG_VIDEO_SVGA */
+
+# User-defined local mode table (VGA only)
+#ifdef CONFIG_VIDEO_LOCAL
+local_modes:
+       leaw    local_mode_table, %si
+locm1: lodsw
+       orw     %ax, %ax
+       jz      locm2
+       
+       stosw
+       movsw
+       jmp     locm1
+
+locm2: ret
+
+# This is the table of local video modes which can be supplied manually
+# by the user. Each entry consists of mode ID (word) and dimensions
+# (byte for column count and another byte for row count). These modes
+# are placed before all SVGA and VESA modes and override them if table
+# compacting is enabled. The table must end with a zero word followed
+# by NUL-terminated video adapter name.
+local_mode_table:
+       .word   0x0100                          # Example: 40x25
+       .byte   25,40
+       .word   0
+       .ascii  "Local"
+       .byte   0
+#endif /* CONFIG_VIDEO_LOCAL */
+
+# Read a key and return the ASCII code in al, scan code in ah
+getkey:        xorb    %ah, %ah
+       int     $0x16
+       ret
+
+# Read a key with a timeout of 30 seconds.
+# The hardware clock is used to get the time.
+getkt: call    gettime
+       addb    $30, %al                        # Wait 30 seconds
+       cmpb    $60, %al
+       jl      lminute
+
+       subb    $60, %al
+lminute:
+       movb    %al, %cl
+again: movb    $0x01, %ah
+       int     $0x16
+       jnz     getkey                          # key pressed, so get it
+
+       call    gettime
+       cmpb    %cl, %al
+       jne     again
+
+       movb    $0x20, %al                      # timeout, return `space'
+       ret
+
+# Flush the keyboard buffer
+flush: movb    $0x01, %ah
+       int     $0x16
+       jz      empty
+       
+       xorb    %ah, %ah
+       int     $0x16
+       jmp     flush
+
+empty: ret
+
+# Print hexadecimal number.
+prthw: pushw   %ax
+       movb    %ah, %al
+       call    prthb
+       popw    %ax
+prthb: pushw   %ax
+       shrb    $4, %al
+       call    prthn
+       popw    %ax
+       andb    $0x0f, %al
+prthn: cmpb    $0x0a, %al
+       jc      prth1
+
+       addb    $0x07, %al
+prth1: addb    $0x30, %al
+       jmp     prtchr
+
+# Print decimal number in al
+prtdec:        pushw   %ax
+       pushw   %cx
+       xorb    %ah, %ah
+       movb    $0x0a, %cl
+       idivb   %cl
+       cmpb    $0x09, %al
+       jbe     lt100
+
+       call    prtdec
+       jmp     skip10
+
+lt100: addb    $0x30, %al
+       call    prtchr
+skip10:        movb    %ah, %al
+       addb    $0x30, %al
+       call    prtchr  
+       popw    %cx
+       popw    %ax
+       ret
+
+store_edid:
+       pushw   %es                             # just save all registers
+       pushw   %ax
+       pushw   %bx
+       pushw   %cx
+       pushw   %dx
+       pushw   %di
+
+       pushw   %fs
+       popw    %es
+
+       movl    $0x13131313, %eax               # memset block with 0x13
+       movw    $32, %cx
+       movw    $0x140, %di
+       cld
+       rep
+       stosl
+
+       movw    $0x4f15, %ax                    # do VBE/DDC
+       movw    $0x01, %bx
+       movw    $0x00, %cx
+       movw    $0x01, %dx
+       movw    $0x140, %di
+       int     $0x10
+
+       popw    %di                             # restore all registers
+       popw    %dx
+       popw    %cx
+       popw    %bx
+       popw    %ax
+       popw    %es
+       ret
+
+# VIDEO_SELECT-only variables
+mt_end:                .word   0       # End of video mode table if built
+edit_buf:      .space  6       # Line editor buffer
+card_name:     .word   0       # Pointer to adapter name
+scanning:      .byte   0       # Performing mode scan
+do_restore:    .byte   0       # Screen contents altered during mode change
+svga_prefix:   .byte   VIDEO_FIRST_BIOS>>8     # Default prefix for BIOS modes
+graphic_mode:  .byte   0       # Graphic mode with a linear frame buffer
+dac_size:      .byte   6       # DAC bit depth
+
+# Status messages
+keymsg:                .ascii  "Press <RETURN> to see video modes available, "
+               .ascii  "<SPACE> to continue or wait 30 secs"
+               .byte   0x0d, 0x0a, 0
+
+listhdr:       .byte   0x0d, 0x0a
+               .ascii  "Mode:    COLSxROWS:"
+
+crlft:         .byte   0x0d, 0x0a, 0
+
+prompt:                .byte   0x0d, 0x0a
+               .asciz  "Enter mode number or `scan': "
+
+unknt:         .asciz  "Unknown mode ID. Try again."
+
+badmdt:                .ascii  "You passed an undefined mode number."
+               .byte   0x0d, 0x0a, 0
+
+vesaer:                .ascii  "Error: Scanning of VESA modes failed. Please "
+               .ascii  "report to <mj@ucw.cz>."
+               .byte   0x0d, 0x0a, 0
+
+old_name:      .asciz  "CGA/MDA/HGA"
+
+ega_name:      .asciz  "EGA"
+
+svga_name:     .ascii  " "
+
+vga_name:      .asciz  "VGA"
+
+vesa_name:     .asciz  "VESA"
+
+name_bann:     .asciz  "Video adapter: "
+#endif /* CONFIG_VIDEO_SELECT */
+
+# Other variables:
+adapter:       .byte   0       # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
+video_segment: .word   0xb800  # Video memory segment
+force_size:    .word   0       # Use this size instead of the one in BIOS vars
diff --git a/kitten/arch/x86_64/kernel/Makefile b/kitten/arch/x86_64/kernel/Makefile
new file mode 100644 (file)
index 0000000..0956d06
--- /dev/null
@@ -0,0 +1,12 @@
+extra-y                := head.o head64.o init_task.o vmlwk.lds
+EXTRA_FLAGS    := -traditional
+obj-y          := percpu.o setup.o e820.o cpuinfo.o resource.o \
+                  mpparse.o entry.o show.o syscall.o i387.o cpu.o \
+                  lapic.o ioapic.o trampoline.o interrupts.o mpboot.o \
+                  time.o sys_arch_prctl.o vsyscall.o xcall.o \
+                  task.o sched.o
+
+obj-$(CONFIG_CRAY_XT) += rca/
+obj-$(CONFIG_V3VEE) += bios.o
+
+
diff --git a/kitten/arch/x86_64/kernel/asm-offsets.c b/kitten/arch/x86_64/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..c159f89
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#if 0
+#include <linux/sched.h> 
+#include <linux/stddef.h>
+#include <linux/errno.h> 
+#include <linux/hardirq.h>
+#include <linux/suspend.h>
+#include <asm/pda.h>
+#include <asm/processor.h>
+#include <asm/segment.h>
+#include <asm/thread_info.h>
+#endif
+
+#include <lwk/task.h>
+#include <arch/pda.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+/**
+ * This is used to automatically count the number of system calls.
+ * A table is generated with one entry for each system call defined in
+ * arch/unistd.h, which contains the list of system calls.
+ */
+#define __NO_STUBS 1
+#undef __SYSCALL
+#undef _ARCH_X86_64_UNISTD_H
+#define __SYSCALL(nr, sym) [nr] = 1,
+static char syscalls[] = {
+#include <arch/unistd.h>
+};
+
+int main(void)
+{
+#define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry))
+#if 0
+       ENTRY(state);
+       ENTRY(flags); 
+       ENTRY(thread); 
+#endif
+       ENTRY(id);
+       BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(tsk_arch_ ## entry, offsetof(struct task_struct, arch) + offsetof(struct arch_task, entry))
+       ENTRY(flags);
+       ENTRY(addr_limit);
+       BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(tsk_arch_ ## entry, offsetof(struct task_struct, arch) + offsetof(struct arch_task, thread) + offsetof(struct thread_struct, entry))
+       ENTRY(rsp);
+       BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry))
+       ENTRY(kernelstack); 
+       ENTRY(oldrsp); 
+       ENTRY(pcurrent); 
+       ENTRY(irqcount);
+       ENTRY(cpunumber);
+       ENTRY(irqstackptr);
+       ENTRY(data_offset);
+       BLANK();
+#undef ENTRY
+#if 0
+       DEFINE(pbe_address, offsetof(struct pbe, address));
+       DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
+       DEFINE(pbe_next, offsetof(struct pbe, next));
+       BLANK();
+       DEFINE(TSS_ist, offsetof(struct tss_struct, ist));
+#endif
+       BLANK();
+       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
+       return 0;
+}
diff --git a/kitten/arch/x86_64/kernel/bios.S b/kitten/arch/x86_64/kernel/bios.S
new file mode 100644 (file)
index 0000000..c753467
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  ROM Bios images for V3Vee emulator
+ */
+
+.data
+.globl rombios_start
+rombios_start:
+.incbin "../palacios/build/rombios"
+.globl rombios_end
+rombios_end:
+
+.globl vgabios_start
+vgabios_start:
+.incbin "../palacios/build/vgabios"
+.globl vgabios_end
+vgabios_end:
diff --git a/kitten/arch/x86_64/kernel/cpu.c b/kitten/arch/x86_64/kernel/cpu.c
new file mode 100644 (file)
index 0000000..7ffe2c5
--- /dev/null
@@ -0,0 +1,272 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/task.h>
+#include <lwk/cpu.h>
+#include <lwk/ptrace.h>
+#include <lwk/string.h>
+#include <lwk/delay.h>
+#include <arch/processor.h>
+#include <arch/desc.h>
+#include <arch/proto.h>
+#include <arch/i387.h>
+#include <arch/apic.h>
+#include <arch/tsc.h>
+
+/**
+ * Bitmap of CPUs that have been initialized.
+ */
+static cpumask_t cpu_initialized_map;
+
+/**
+ * Memory for STACKFAULT stacks, one for each CPU.
+ */
+char stackfault_stack[NR_CPUS][PAGE_SIZE]
+__attribute__((section(".bss.page_aligned")));
+
+/**
+ * Memory for DOUBLEFAULT stacks, one for each CPU.
+ */
+char doublefault_stack[NR_CPUS][PAGE_SIZE]
+__attribute__((section(".bss.page_aligned")));
+
+/**
+ * Memory for NMI stacks, one for each CPU.
+ */
+char nmi_stack[NR_CPUS][PAGE_SIZE]
+__attribute__((section(".bss.page_aligned")));
+
+/**
+ * Memory for DEBUG stacks, one for each CPU.
+ */
+char debug_stack[NR_CPUS][PAGE_SIZE]
+__attribute__((section(".bss.page_aligned")));
+
+/**
+ * Memory for MCE stacks, one for each CPU.
+ */
+char mce_stack[NR_CPUS][PAGE_SIZE]
+__attribute__((section(".bss.page_aligned")));
+
+/**
+ * Initializes the calling CPU's Per-CPU Data Area (PDA).
+ * When in kernel mode, each CPU's GS.base is loaded with the address of the
+ * CPU's PDA. This allows data in the PDA to be accessed using segment relative
+ * accesses, like:
+ *
+ *     movl $gs:pcurrent,%rdi  // move CPU's current task pointer to rdi
+ *
+ * This is similar to thread-local data for user-level programs.
+ */
+void __init
+pda_init(unsigned int cpu, struct task_struct *task)
+{
+       struct x8664_pda *pda = cpu_pda(cpu);
+
+       /* 
+        * Point FS and GS at the NULL segment descriptor (entry 0) in the GDT.
+        * x86_64 does away with a lot of segmentation cruftiness... there's no
+        * need to set up specific GDT entries for FS or GS.
+        */
+       asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
+
+       /*
+        * Load the address of this CPU's PDA into this CPU's GS_BASE model
+        * specific register. Upon entry to the kernel, the SWAPGS instruction
+        * is used to load the value from MSR_GS_BASE into the GS segment
+        * register's base address (GS.base).  The user-level GS.base value
+        * is stored in MSR_GS_BASE.  When the kernel is exited, SWAPGS is
+        * called again.
+        */
+       mb();
+       wrmsrl(MSR_GS_BASE, pda);
+       mb();
+
+       pda->cpunumber     = cpu;
+       pda->pcurrent      = task;
+       pda->active_aspace = task->aspace;
+       pda->kernelstack   = (unsigned long)task - PDA_STACKOFFSET + TASK_SIZE;
+       pda->mmu_state     = 0;
+}
+
+/**
+ * Initializes the calling CPU's Control Register 4 (CR4).
+ * The bootstrap assembly code has already partially setup this register.
+ * We only touch the bits we care about, leaving the others untouched.
+ */
+static void __init
+cr4_init(void)
+{
+       clear_in_cr4(
+               X86_CR4_VME | /* Disable Virtual-8086 support/cruft */
+               X86_CR4_PVI | /* Disable support for VIF flag */
+               X86_CR4_TSD | /* Allow RDTSC instruction at user-level */
+               X86_CR4_DE    /* Disable debugging extensions */
+       );
+}
+
+/**
+ * Initializes and installs the calling CPU's Global Descriptor Table (GDT).
+ * Each CPU has its own GDT.
+ */
+static void __init
+gdt_init(void)
+{
+       unsigned int cpu = this_cpu;
+
+       /* The bootstrap CPU's GDT has already been setup */
+       if (cpu != 0)
+               memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE);
+       cpu_gdt_descr[cpu].size = GDT_SIZE;
+
+       /* Install the CPU's GDT */
+       asm volatile("lgdt %0" :: "m" (cpu_gdt_descr[cpu]));
+
+       /*
+        * Install the CPU's LDT... Local Descriptor Table.
+        * We have no need for a LDT, so we point it at the NULL descriptor.
+        */
+       asm volatile("lldt %w0":: "r" (0));
+}
+
+/**
+ * Installs the calling CPU's Local Descriptor Table (LDT).
+ * All CPUs share the same IDT.
+ */
+static void __init
+idt_init(void)
+{
+       /*
+        * The bootstrap CPU has already filled in the IDT table via the
+        * interrupts_init() call in setup.c. All we need to do is tell the CPU
+        * about it.
+        */
+       asm volatile("lidt %0" :: "m" (idt_descr));
+}
+
+/**
+ * Initializes and installs the calling CPU's Task State Segment (TSS).
+ */
+static void __init
+tss_init(void)
+{
+       unsigned int       cpu  = this_cpu;
+       struct tss_struct  *tss = &per_cpu(tss, cpu);
+       int i;
+
+       /*
+        * Initialize the CPU's Interrupt Stack Table.
+        * Certain exceptions and interrupts are handled with their own,
+        * known good stack. The IST holds the address of these stacks.
+        */
+       tss->ist[STACKFAULT_STACK-1]  = (unsigned long)&stackfault_stack[cpu][0];
+       tss->ist[DOUBLEFAULT_STACK-1] = (unsigned long)&doublefault_stack[cpu][0];
+       tss->ist[NMI_STACK-1]         = (unsigned long)&nmi_stack[cpu][0];
+       tss->ist[DEBUG_STACK-1]       = (unsigned long)&debug_stack[cpu][0];
+       tss->ist[MCE_STACK-1]         = (unsigned long)&mce_stack[cpu][0];
+
+       /*
+        * Initialize the CPU's I/O permission bitmap.
+        * The <= is required because the CPU will access up to 8 bits beyond
+        * the end of the IO permission bitmap.
+        */
+       tss->io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
+       for (i = 0; i <= IO_BITMAP_LONGS; i++) 
+               tss->io_bitmap[i] = ~0UL;
+
+       /*
+        * Install the CPU's TSS and load the CPU's Task Register (TR).
+        * Each CPU has its own TSS.
+        */
+       set_tss_desc(cpu, tss);
+       asm volatile("ltr %w0":: "r" (GDT_ENTRY_TSS*8));
+}
+
+/**
+ * Initializes various Model Specific Registers (MSRs) of the calling CPU.
+ */
+static void __init
+msr_init(void)
+{
+       /*
+        * Setup the MSRs needed to support the SYSCALL and SYSRET
+        * instructions. Really, you should read the manual to understand these
+        * gems. In summary, STAR and LSTAR specify the CS, SS, and RIP to
+        * install when the SYSCALL instruction is issued. They also specify the
+        * CS and SS to install on SYSRET.
+        *
+        * On SYSCALL, the x86_64 CPU control unit uses STAR to load CS and SS and
+        * LSTAR to load RIP. The old RIP is saved in RCX.
+        *
+        * On SYSRET, the control unit uses STAR to restore CS and SS.
+        * RIP is loaded from RCX.
+        *
+        * SYSCALL_MASK specifies the RFLAGS to clear on SYSCALL.
+        */
+       wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48 | /* SYSRET  CS+SS */
+                         ((u64)__KERNEL_CS)<<32); /* SYSCALL CS+SS */
+       wrmsrl(MSR_LSTAR, asm_syscall);            /* SYSCALL RIP */
+       wrmsrl(MSR_CSTAR, asm_syscall_ignore);     /* RIP for compat. mode */
+       wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000);
+
+       /*
+        * Setup MSRs needed to support the PDA.
+        * pda_init() initialized MSR_GS_BASE already. When the SWAPGS
+        * instruction is issued, the x86_64 control unit atomically swaps
+        * MSR_GS_BASE and MSR_KERNEL_GS_BASE. So, when we call SWAPGS to
+        * exit the kernel, the value in MSR_KERNEL_GS_BASE will be loaded.
+        * User-space will see MSR_FS_BASE and MSR_GS_BASE both set to 0.
+        */
+       wrmsrl(MSR_FS_BASE, 0);
+       wrmsrl(MSR_KERNEL_GS_BASE, 0);
+}
+
+/**
+ * Initializes the calling CPU's debug registers.
+ */
+static void __init
+dbg_init(void)
+{
+       /*
+        * Clear the CPU's debug registers.
+        * DR[0-3] are Address-Breakpoint Registers
+        * DR[4-5] are reserved and should not be used by software
+        * DR6 is the Debug Status Register
+        * DR7 is the Debug Control Register
+        */
+       set_debugreg(0UL, 0);
+       set_debugreg(0UL, 1);
+       set_debugreg(0UL, 2);
+       set_debugreg(0UL, 3);
+       set_debugreg(0UL, 6);
+       set_debugreg(0UL, 7);
+}
+
+void __init
+cpu_init(void)
+{
+       /*
+        * Get a reference to the currently executing task and the ID of the
+        * CPU being initialized.  We can't use the normal 'current' mechanism
+        * since it relies on the PDA being initialized, which it isn't for all
+        * CPUs other than the boot CPU (id=0). pda_init() is called below.
+        */
+       struct task_struct *me = get_current_via_RSP();
+       unsigned int       cpu = me->cpu_id; /* logical ID */
+
+       if (cpu_test_and_set(cpu, cpu_initialized_map))
+               panic("CPU#%u already initialized!\n", cpu);
+       printk(KERN_DEBUG "Initializing CPU#%u\n", cpu);
+
+       pda_init(cpu, me);      /* per-cpu data area */
+       identify_cpu();         /* determine cpu features via CPUID */
+       cr4_init();             /* control register 4 */
+       gdt_init();             /* global descriptor table */
+       idt_init();             /* interrupt descriptor table */
+       tss_init();             /* task state segment */
+       msr_init();             /* misc. model specific registers */
+       dbg_init();             /* debug registers */
+       fpu_init();             /* floating point unit */
+       lapic_init();           /* local advanced prog. interrupt controller */
+       time_init();            /* detects CPU frequency, udelay(), etc. */
+       barrier();              /* compiler memory barrier, avoids reordering */
+}
diff --git a/kitten/arch/x86_64/kernel/cpuinfo.c b/kitten/arch/x86_64/kernel/cpuinfo.c
new file mode 100644 (file)
index 0000000..f795d92
--- /dev/null
@@ -0,0 +1,507 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/smp.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/aspace.h>
+#include <arch/processor.h>
+#include <arch/proto.h>
+
+/**
+ * Information about the boot CPU.
+ * The CPU capabilities stored in this structure are the lowest common
+ * denominator for all CPUs in the system... in this sense, boot_cpu_data
+ * is special compared to the corresponding entry in the cpu_info[] array.
+ */
+struct cpuinfo boot_cpu_data;
+
+/**
+ * On AMD multi-core CPUs, the lower bits of the local APIC ID distinquish the
+ * cores. This function assumes the number of cores is a power of two.
+ */
+static void __init
+amd_detect_cmp(struct cpuinfo *c)
+{
+       struct arch_cpuinfo *a = &c->arch;
+       unsigned bits;
+       unsigned ecx = cpuid_ecx(0x80000008);
+
+       a->x86_pkg_cores = (ecx & 0xff) + 1;
+
+       /* CPU telling us the core id bits shift? */
+       bits = (ecx >> 12) & 0xF;
+
+       /* Otherwise recompute */
+       if (bits == 0) {
+               while ((1 << bits) < a->x86_pkg_cores)
+                       bits++;
+       }
+
+       /* Determine the physical socket ID */
+       c->phys_socket_id = c->physical_id >> bits;
+
+       /* Determine the physical core ID (index of core in socket) */
+       c->phys_core_id = c->physical_id & ((1 << bits)-1);
+}
+
+static void __init
+amd_cpu(struct cpuinfo *c)
+{
+       unsigned level;
+       unsigned long value;
+       unsigned int eax, ebx, ecx, edx;
+       struct arch_cpuinfo *a = &c->arch;
+
+       /*
+        * Disable TLB flush filter by setting HWCR.FFDIS on K8
+        * bit 6 of msr C001_0015
+        *
+        * Errata 63 for SH-B3 steppings
+        * Errata 122 for all steppings (F+ have it disabled by default)
+        */
+       if (a->x86_family == 15) {
+               rdmsrl(MSR_K8_HWCR, value);
+               value |= 1 << 6;
+               wrmsrl(MSR_K8_HWCR, value);
+       }
+
+       /*
+        * Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+        * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
+        */
+       clear_bit(0*32+31, &a->x86_capability);
+       
+       /* On C+ stepping K8 rep microcode works well for copy/memset */
+       level = cpuid_eax(1);
+       if (a->x86_family == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
+               set_bit(X86_FEATURE_REP_GOOD, &a->x86_capability);
+       if (a->x86_family == 0x10)
+               set_bit(X86_FEATURE_REP_GOOD, &a->x86_capability);
+
+       /* Enable workaround for FXSAVE leak */
+       if (a->x86_family >= 6)
+               set_bit(X86_FEATURE_FXSAVE_LEAK, &a->x86_capability);
+
+       /* Determine L1 Cache and TLB Information */
+       if (a->extended_cpuid_level >= 0x80000005) {
+               cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+
+               /* 2-MB L1 TLB (inclusive with L2 TLB) */
+               a->x86_tlb_size[INST][L1][PAGE_2MB] = (eax & 0xff);
+               a->x86_tlb_size[DATA][L1][PAGE_2MB] = ((eax >> 16) & 0xff);
+
+               /* 4-KB L1 TLB (inclusive with L2 TLB) */
+               a->x86_tlb_size[INST][L1][PAGE_4KB] = (ebx & 0xff);
+               a->x86_tlb_size[DATA][L1][PAGE_4KB] = ((ebx >> 16) & 0xff);
+
+               /* L1 Instruction Cache */
+               a->x86_cache_size[INST][L1] = (edx >> 24);
+               a->x86_cache_line[INST][L1] = (edx & 0xff);
+
+               /* L1 Data Cache */
+               a->x86_cache_size[DATA][L1] = (ecx >> 24);
+               a->x86_cache_line[DATA][L1] = (ecx & 0xff);
+       }
+
+       /* Determine L2 Cache and TLB Information */
+       if (a->extended_cpuid_level >= 0x80000006) {
+               cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
+
+               /* 2-MB L2 TLB */
+               if ((eax & 0xffff0000) == 0) {
+                       /* Unified I+D 2-MB L2 TLB */
+                       a->x86_tlb_size[UNIF][L2][PAGE_2MB] = eax & 0xfff;
+               } else {
+                       a->x86_tlb_size[INST][L2][PAGE_2MB] = eax & 0xfff;
+                       a->x86_tlb_size[DATA][L2][PAGE_2MB] = (eax>>16) & 0xfff;
+               }
+
+               /* 4-KB L2 TLB */
+               if ((ebx & 0xffff0000) == 0) {
+                       /* Unified I+D 4-KB L2 TLB */
+                       a->x86_tlb_size[UNIF][L2][PAGE_4KB] = ebx & 0xfff;
+               } else {
+                       a->x86_tlb_size[INST][L2][PAGE_4KB] = ebx & 0xfff;
+                       a->x86_tlb_size[DATA][L2][PAGE_4KB] = (ebx>>16) & 0xfff;
+               }
+
+               /* Unified L2 Cache */
+               a->x86_cache_size[UNIF][L2] = ecx >> 16;
+               a->x86_cache_line[UNIF][L2] = ecx & 0xff;
+       }
+
+       /* Determine Advanced Power Management Features */
+       if (a->extended_cpuid_level >= 0x80000007) {
+               a->x86_power = cpuid_edx(0x80000007);
+       }
+
+       /* Determine Maximum Address Sizes */
+       if (a->extended_cpuid_level >= 0x80000008) {
+               cpuid(0x80000008, &eax, &ebx, &ecx, &edx); 
+               a->x86_virt_bits = (eax >> 8) & 0xff;
+               a->x86_phys_bits = eax & 0xff;
+       }
+
+       /* a->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
+       if (a->x86_power & (1<<8))
+               set_bit(X86_FEATURE_CONSTANT_TSC, &a->x86_capability);
+
+       /* Multi core CPU? */
+       if (a->extended_cpuid_level >= 0x80000008)
+               amd_detect_cmp(c);
+
+       if (a->x86_family == 0xf || a->x86_family == 0x10 || a->x86_family == 0x11)
+               set_bit(X86_FEATURE_K8, &a->x86_capability);
+
+       /* RDTSC can be speculated around */
+       clear_bit(X86_FEATURE_SYNC_RDTSC, &a->x86_capability);
+
+       /* Family 10 doesn't support C states in MWAIT so don't use it */
+       if (a->x86_family == 0x10)
+               clear_bit(X86_FEATURE_MWAIT, &a->x86_capability);
+}
+
+static void __init
+intel_cpu(struct cpuinfo *c)
+{
+       /* TODO */
+}
+
+/*
+ * Do some early cpuid on the boot CPU to get some parameter that are
+ * needed before check_bugs. Everything advanced is in identify_cpu
+ * below.
+ */
+void __init
+early_identify_cpu(struct cpuinfo *c)
+{
+       struct arch_cpuinfo *a = &c->arch;
+       uint32_t tfms;
+       uint32_t misc;
+
+       /*
+        * Zero structure, except apic_id should have already been filled in.
+        */
+       uint8_t apic_id = a->apic_id;
+       memset(a, 0, sizeof(*a));
+       a->apic_id = apic_id;
+
+       /*
+        * Set some defaults to begin with.
+        */
+       a->x86_vendor_id[0]     =       '\0';  /* Unset */
+       a->x86_model_id[0]      =       '\0';  /* Unset */
+       a->x86_clflush_size     =       64;
+       a->x86_pkg_cores        =       1;
+       a->max_cpu_khz          =       1000000; /* start out with 1 GHz */
+       a->min_cpu_khz          =       a->max_cpu_khz;
+       a->cur_cpu_khz          =       a->max_cpu_khz;
+       a->tsc_khz              =       a->max_cpu_khz;
+       memset(&a->x86_capability, 0, sizeof(a->x86_capability));
+
+       /* Determine the CPU vendor */
+       cpuid(0x00000000, &a->cpuid_level,
+             (unsigned int *)&a->x86_vendor_id[0],
+             (unsigned int *)&a->x86_vendor_id[8],
+             (unsigned int *)&a->x86_vendor_id[4]);
+
+       /* Derive the vendor ID from the vendor string */
+       if (!strcmp(a->x86_vendor_id, "AuthenticAMD"))
+               a->x86_vendor = X86_VENDOR_AMD;
+       else if (!strcmp(a->x86_vendor_id, "GenuineIntel"))
+               a->x86_vendor = X86_VENDOR_INTEL;
+       else
+               a->x86_vendor = X86_VENDOR_UNKNOWN;
+
+       if (a->cpuid_level == 0)
+               panic("CPU only has CPUID level 0... is your CPU ancient?");
+
+       /*
+        * Determine Intel-defined CPU features and other standard info.
+        * NOTE: Vendor-specific code may override these later.
+        */
+       cpuid(0x00000001,
+               &tfms, /* type, family, model, stepping */
+               &misc, /* brand, cflush sz, logical cpus, apic id */
+               &a->x86_capability[4], /* extended cpu features */
+               &a->x86_capability[0]  /* cpu features */
+       );
+
+       /* Determine the CPU family */
+       a->x86_family = (tfms >> 8) & 0xf;
+       if (a->x86_family == 0xf)
+               a->x86_family += ((tfms >> 20) & 0xff);
+
+       /* Determine the CPU model */
+       a->x86_model = (tfms >> 4) & 0xf;
+       if (a->x86_family >= 0x6)
+               a->x86_model += (((tfms >> 16) & 0xf) << 4);
+
+       /* Determine the CPU stepping */
+       a->x86_stepping = tfms & 0xf;
+
+       /* Determine the CLFLUSH size, if the CPU supports CLFLUSH */
+       if (a->x86_capability[0] & (1 << X86_FEATURE_CLFLSH))
+               a->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+
+       /*
+        * Determine the CPU's initial local APIC ID.
+        * NOTE: The BIOS may change the CPU's Local APIC ID before
+        *       passing control to the OS kernel, however the value
+        *       reported by CPUID will never change. The initial APIC
+        *       ID can sometimes be used to discover CPU topology.
+        */
+       a->initial_lapic_id = (misc >> 24) & 0xff;
+
+       /* TODO: determine page sizes supported via CPUID */
+       c->pagesz_mask = (VM_PAGE_4KB | VM_PAGE_2MB);
+}
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init
+identify_cpu(void)
+{
+       int i;
+       struct cpuinfo *c = &cpu_info[this_cpu];
+       struct arch_cpuinfo *a = &c->arch;
+
+       early_identify_cpu(c);
+
+       /* Determine the extended CPUID level */
+       a->extended_cpuid_level = cpuid_eax(0x80000000);
+
+       /* Parse extended CPUID information */
+       if ((a->extended_cpuid_level & 0xffff0000) == 0x80000000) {
+               /* Determine AMD-defined CPU features: level 0x80000001 */
+               if (a->extended_cpuid_level >= 0x80000001) {
+                       a->x86_capability[1] = cpuid_edx(0x80000001);
+                       a->x86_capability[6] = cpuid_ecx(0x80000001);
+               }
+
+               /* Determine processor brand/model string */
+               if (a->extended_cpuid_level >= 0x80000004) {
+                       unsigned int *v = (unsigned int *) a->x86_model_id;
+                       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+                       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+                       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+                       a->x86_model_id[48] = '\0';
+               } else {
+                       strcpy(a->x86_model_id, "Unknown x86-64 Model");
+               }
+       }
+
+       /*
+        * Vendor-specific initialization.  In this section we
+        * canonicalize the feature flags, meaning if there are
+        * features a certain CPU supports which CPUID doesn't
+        * tell us, CPUID claiming incorrect flags, or other bugs,
+        * we handle them here.
+        *
+        * At the end of this section, c->x86_capability better
+        * indicate the features this CPU genuinely supports!
+        */
+       switch (a->x86_vendor) {
+       case X86_VENDOR_AMD:
+               amd_cpu(c);
+               break;
+
+       case X86_VENDOR_INTEL:
+               intel_cpu(c);
+               break;
+
+       case X86_VENDOR_UNKNOWN:
+       default:
+               panic("Unknown x86 CPU Vendor.");
+       }
+
+       /*
+        * boot_cpu_data holds the common feature set between
+        * all CPUs; so make sure that we indicate which features are
+        * common between the CPUs.  The first time this routine gets
+        * executed, c == &boot_cpu_data.
+        */
+       if (c != &boot_cpu_data) {
+               /* AND the already accumulated flags with these */
+               for (i = 0 ; i < NCAPINTS ; i++)
+                       boot_cpu_data.arch.x86_capability[i] &= c->arch.x86_capability[i];
+       }
+}
+
+/**
+ * Prints architecture specific CPU information to the console.
+ */
+void
+print_arch_cpuinfo(struct cpuinfo *c)
+{
+       int i;
+       struct arch_cpuinfo *a = &c->arch;
+       char buf[1024];
+
+       /* 
+        * These flag bits must match the definitions in <arch/cpufeature.h>.
+        * NULL means this bit is undefined or reserved; either way it doesn't
+        * have meaning as far as the kernel is concerned.
+        */
+       static char *x86_cap_flags[] = {
+               /* Intel-defined */
+               "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+               "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+               "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+               "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
+
+               /* AMD-defined */
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
+               NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
+               "3dnowext", "3dnow",
+
+               /* Transmeta-defined */
+               "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+               /* Other (Linux-defined) */
+               "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+               NULL, NULL, NULL, NULL,
+               "constant_tsc", "up", NULL, "arch_perfmon",
+               "pebs", "bts", NULL, "sync_rdtsc",
+               "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+               /* Intel-defined (#2) */
+               "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+               "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
+               NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+               /* VIA/Cyrix/Centaur-defined */
+               NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
+               "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+               /* AMD-defined (#2) */
+               "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy",
+               "altmovcr8", "abm", "sse4a",
+               "misalignsse", "3dnowprefetch",
+               "osvw", "ibs", NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+               /* Auxiliary (Linux-defined) */
+               "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       };
+       static char *x86_power_flags[] = { 
+               "ts",   /* temperature sensor */
+               "fid",  /* frequency id control */
+               "vid",  /* voltage id control */
+               "ttp",  /* thermal trip */
+               "tm",
+               "stc",
+               "100mhzsteps",
+               "hwpstate",
+               "",     /* tsc invariant mapped to constant_tsc */
+               /* nothing */
+       };
+
+       printk(KERN_DEBUG "  Vendor:         %s\n",      a->x86_vendor_id);
+       printk(KERN_DEBUG "  Family:         %u\n",      a->x86_family);
+       printk(KERN_DEBUG "  Model:          %u (%s)\n", a->x86_model, a->x86_model_id);
+       printk(KERN_DEBUG "  Stepping:       %u\n",      a->x86_stepping);
+       printk(KERN_DEBUG "  Frequency:      %u.%03u MHz (max=%u.%03u, min=%u.%03u)\n",
+                         a->cur_cpu_khz / 1000, (a->cur_cpu_khz % 1000),
+                         a->max_cpu_khz / 1000, (a->max_cpu_khz % 1000),
+                         a->min_cpu_khz / 1000, (a->min_cpu_khz % 1000));
+
+       /* L1 Cache Info */
+       if (a->x86_cache_size[UNIF][L1] == 0) {
+       printk(KERN_DEBUG "  L1 Cache:       I=%u KB, D=%u KB, line size=%u bytes\n",
+                         a->x86_cache_size[INST][L1],
+                         a->x86_cache_size[DATA][L1],
+                         a->x86_cache_line[DATA][L1]);
+       } else {
+       printk(KERN_DEBUG "  L1 Cache:       %u KB (unified I+D), line size=%u bytes\n",
+                         a->x86_cache_size[UNIF][L1],
+                         a->x86_cache_line[UNIF][L1]);
+       }
+
+       /* L2 Cache Info */
+       if (a->x86_cache_size[UNIF][L2] == 0) {
+       printk(KERN_DEBUG "  L2 Cache:       I=%u KB, D=%u KB, line size=%u bytes\n",
+                         a->x86_cache_size[INST][L2],
+                         a->x86_cache_size[DATA][L2],
+                         a->x86_cache_line[DATA][L2]);
+       } else {
+       printk(KERN_DEBUG "  L2 Cache:       %u KB (unified I+D), line size=%u bytes\n",
+                         a->x86_cache_size[UNIF][L2],
+                         a->x86_cache_line[UNIF][L2]);
+       }
+
+       /* 4-KB Page TLB Info */
+       printk(KERN_DEBUG "  4-KB TLB:       I=%u/%u entries D=%d/%d entries\n",
+               a->x86_tlb_size[INST][L1][PAGE_4KB],
+               a->x86_tlb_size[INST][L2][PAGE_4KB],
+               a->x86_tlb_size[DATA][L1][PAGE_4KB],
+               a->x86_tlb_size[DATA][L2][PAGE_4KB]
+       );
+
+       /* 2-MB Page TLB Info */
+       printk(KERN_DEBUG "  2-MB TLB:       I=%u/%u entries D=%d/%d entries\n",
+               a->x86_tlb_size[INST][L1][PAGE_2MB],
+               a->x86_tlb_size[INST][L2][PAGE_2MB],
+               a->x86_tlb_size[DATA][L1][PAGE_2MB],
+               a->x86_tlb_size[DATA][L2][PAGE_2MB]
+       );
+
+       /* 1-GB Page TLB Info */
+       printk(KERN_DEBUG "  1-GB TLB:       I=%u/%u entries D=%d/%d entries\n",
+               a->x86_tlb_size[INST][L1][PAGE_1GB],
+               a->x86_tlb_size[INST][L2][PAGE_1GB],
+               a->x86_tlb_size[DATA][L1][PAGE_1GB],
+               a->x86_tlb_size[DATA][L2][PAGE_1GB]
+       );
+
+       /* Address bits */
+       printk(KERN_DEBUG "  Address bits:   %u bits physical, %u bits virtual\n",
+               a->x86_phys_bits,
+               a->x86_virt_bits);
+
+       /* Bytes flushed by CLFLUSH instruction */
+       printk(KERN_DEBUG "  CLFLUSH size:   %u bytes\n", a->x86_clflush_size);
+
+       /* CPU Features */
+       buf[0] = '\0';
+       for (i = 0; i < 32*NCAPINTS; i++) {
+               if (cpu_has(c, i) && x86_cap_flags[i] != NULL) {
+                       strcat(buf, x86_cap_flags[i]);
+                       strcat(buf, " ");
+               }
+       }
+       printk(KERN_DEBUG "  CPU Features:   %s\n", buf);
+
+       /* Power Management Features */
+       if (a->x86_power == 0) {
+               strcpy(buf, "none");
+       } else {
+               buf[0] = '\0';
+               for (i = 0; i < 32; i++) {
+                       if ((i < ARRAY_SIZE(x86_power_flags)) && x86_power_flags[i]) {
+                               strcat(buf, x86_power_flags[i]);
+                               strcat(buf, " ");
+                       } else {
+                               char bit_str[7];
+                               bit_str[0] = '\0';
+                               sprintf(bit_str, "[%d] ", i);
+                               strcat(buf, bit_str);
+                       }
+               }
+       }
+       printk(KERN_DEBUG "  Power Features: %s\n", buf);
+}
+
diff --git a/kitten/arch/x86_64/kernel/e820.c b/kitten/arch/x86_64/kernel/e820.c
new file mode 100644 (file)
index 0000000..2799607
--- /dev/null
@@ -0,0 +1,698 @@
+/* 
+ * Handle the memory map.
+ * The functions here do the job until bootmem takes over.
+ * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
+ *
+ *  Getting sanitize_e820_map() in sync with i386 version by applying change:
+ *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *     Alex Achenbach <xela@slit.de>, December 2002.
+ *  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ *
+ */
+#include <lwk/kernel.h>
+#include <lwk/types.h>
+#include <lwk/init.h>
+#include <lwk/bootmem.h>
+#include <lwk/resource.h>
+#include <lwk/string.h>
+#include <lwk/linux_compat.h>
+
+#include <arch/page.h>
+#include <arch/pgtable.h>
+#include <arch/e820.h>
+#include <arch/proto.h>
+#include <arch/bootsetup.h>
+#include <arch/sections.h>
+
+/**
+ * The BIOS "e820" map of memory.
+ */
+struct e820map e820;
+
+/* 
+ * PFN of last memory page.
+ */
+unsigned long end_pfn; 
+EXPORT_SYMBOL(end_pfn);
+
+/* 
+ * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
+ * The direct mapping extends to end_pfn_map, so that we can directly access
+ * apertures, ACPI and other tables without having to play with fixmaps.
+ */ 
+unsigned long end_pfn_map; 
+
+/* 
+ * Last pfn which the user wants to use.
+ */
+unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
+
+extern struct resource code_resource, data_resource;
+
+/* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
+static inline int bad_addr(unsigned long *addrp, unsigned long size)
+{ 
+       unsigned long addr = *addrp, last = addr + size; 
+
+       /* various gunk below that needed for SMP startup */
+       if (addr < 0x8000) { 
+               *addrp = 0x8000;
+               return 1; 
+       }
+
+       /* direct mapping tables of the kernel */
+       if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) { 
+               *addrp = table_end << PAGE_SHIFT; 
+               return 1;
+       } 
+
+       /* initrd image */ 
+       if (LOADER_TYPE && INITRD_START && last >= INITRD_START && 
+           addr < INITRD_START+INITRD_SIZE) { 
+               *addrp = INITRD_START + INITRD_SIZE; 
+               return 1;
+       } 
+
+       /* kernel code + 640k memory hole (later should not be needed, but 
+          be paranoid for now) */
+       if (last >= 640*1024 && addr < __pa_symbol(&_end)) { 
+               *addrp = __pa_symbol(&_end);
+               return 1;
+       }
+
+       if (last >= ebda_addr && addr < ebda_addr + ebda_size) {
+               *addrp = ebda_addr + ebda_size;
+               return 1;
+       }
+
+       /* XXX ramdisk image here? */ 
+       return 0;
+} 
+
+/*
+ * This function checks if any part of the range <start,end> is mapped
+ * with type.
+ */
+int __init
+e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
+{ 
+       int i;
+       for (i = 0; i < e820.nr_map; i++) { 
+               struct e820entry *ei = &e820.map[i]; 
+               if (type && ei->type != type) 
+                       continue;
+               if (ei->addr >= end || ei->addr + ei->size <= start)
+                       continue; 
+               return 1; 
+       } 
+       return 0;
+}
+
+/*
+ * This function checks if the entire range <start,end> is mapped with type.
+ *
+ * Note: this function only works correct if the e820 table is sorted and
+ * not-overlapping, which is the case
+ */
+int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type)
+{
+       int i;
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               if (type && ei->type != type)
+                       continue;
+               /* is the region (part) in overlap with the current region ?*/
+               if (ei->addr >= end || ei->addr + ei->size <= start)
+                       continue;
+
+               /* if the region is at the beginning of <start,end> we move
+                * start to the end of the region since it's ok until there
+                */
+               if (ei->addr <= start)
+                       start = ei->addr + ei->size;
+               /* if start is now at or beyond end, we're done, full coverage */
+               if (start >= end)
+                       return 1; /* we're done */
+       }
+       return 0;
+}
+
+/* 
+ * Find a free area in a specific range. 
+ */ 
+unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) 
+{ 
+       int i; 
+       for (i = 0; i < e820.nr_map; i++) { 
+               struct e820entry *ei = &e820.map[i]; 
+               unsigned long addr = ei->addr, last; 
+               if (ei->type != E820_RAM) 
+                       continue; 
+               if (addr < start) 
+                       addr = start;
+               if (addr > ei->addr + ei->size) 
+                       continue; 
+               while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
+                       ;
+               last = addr + size;
+               if (last > ei->addr + ei->size)
+                       continue;
+               if (last > end) 
+                       continue;
+               return addr; 
+       } 
+       return -1UL;            
+} 
+
+/* 
+ * Free bootmem based on the e820 table for a node.
+ */
+void __init e820_bootmem_free(unsigned long start, unsigned long end)
+{
+       int i;
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i]; 
+               unsigned long last, addr;
+
+               if (ei->type != E820_RAM || 
+                   ei->addr+ei->size <= start || 
+                   ei->addr >= end)
+                       continue;
+
+               addr = round_up(ei->addr, PAGE_SIZE);
+               if (addr < start) 
+                       addr = start;
+
+               last = round_down(ei->addr + ei->size, PAGE_SIZE); 
+               if (last >= end)
+                       last = end; 
+
+               if (last > addr && last-addr >= PAGE_SIZE)
+                       free_bootmem(addr, last-addr);
+       }
+}
+
+/*
+ * Find the highest page frame number we have available
+ */
+unsigned long __init e820_end_of_ram(void)
+{
+       int i;
+       unsigned long end_pfn = 0;
+       
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i]; 
+               unsigned long start, end;
+
+               start = round_up(ei->addr, PAGE_SIZE); 
+               end = round_down(ei->addr + ei->size, PAGE_SIZE); 
+               if (start >= end)
+                       continue;
+               if (ei->type == E820_RAM) { 
+               if (end > end_pfn<<PAGE_SHIFT)
+                       end_pfn = end>>PAGE_SHIFT;
+               } else { 
+                       if (end > end_pfn_map<<PAGE_SHIFT) 
+                               end_pfn_map = end>>PAGE_SHIFT;
+               } 
+       }
+
+       if (end_pfn > end_pfn_map) 
+               end_pfn_map = end_pfn;
+       if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
+               end_pfn_map = MAXMEM>>PAGE_SHIFT;
+       if (end_pfn > end_user_pfn)
+               end_pfn = end_user_pfn;
+       if (end_pfn > end_pfn_map) 
+               end_pfn = end_pfn_map; 
+
+       return end_pfn; 
+}
+
+/* 
+ * Compute how much memory is missing in a range.
+ * Unlike the other functions in this file the arguments are in page numbers.
+ */
+unsigned long __init
+e820_hole_size(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned long ram = 0;
+       unsigned long start = start_pfn << PAGE_SHIFT;
+       unsigned long end = end_pfn << PAGE_SHIFT;
+       int i;
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               unsigned long last, addr;
+
+               if (ei->type != E820_RAM ||
+                   ei->addr+ei->size <= start ||
+                   ei->addr >= end)
+                       continue;
+
+               addr = round_up(ei->addr, PAGE_SIZE);
+               if (addr < start)
+                       addr = start;
+
+               last = round_down(ei->addr + ei->size, PAGE_SIZE);
+               if (last >= end)
+                       last = end;
+
+               if (last > addr)
+                       ram += last - addr;
+       }
+       return ((end - start) - ram) >> PAGE_SHIFT;
+}
+
+/*
+ * Mark e820 reserved areas as busy for the resource manager.
+ */
+void __init e820_reserve_resources(void)
+{
+       int i;
+       for (i = 0; i < e820.nr_map; i++) {
+               struct resource *res;
+               res = alloc_bootmem(sizeof(struct resource));
+               switch (e820.map[i].type) {
+               case E820_RAM:  res->name = "System RAM"; break;
+               case E820_ACPI: res->name = "ACPI Tables"; break;
+               case E820_NVS:  res->name = "ACPI Non-volatile Storage"; break;
+               default:        res->name = "reserved";
+               }
+               res->start = e820.map[i].addr;
+               res->end = res->start + e820.map[i].size - 1;
+               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               request_resource(&iomem_resource, res);
+               if (e820.map[i].type == E820_RAM) {
+                       /*
+                        *  We don't know which RAM region contains kernel data,
+                        *  so we try it repeatedly and let the resource manager
+                        *  test it.
+                        */
+                       request_resource(res, &code_resource);
+                       request_resource(res, &data_resource);
+#ifdef CONFIG_KEXEC
+                       request_resource(res, &crashk_res);
+#endif
+               }
+       }
+}
+
+/* 
+ * Add a memory region to the kernel e820 map.
+ */ 
+void __init add_memory_region(unsigned long start, unsigned long size, int type)
+{
+       int x = e820.nr_map;
+
+       if (x == E820MAX) {
+               printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
+               return;
+       }
+
+       e820.map[x].addr = start;
+       e820.map[x].size = size;
+       e820.map[x].type = type;
+       e820.nr_map++;
+}
+
+void __init e820_print_map(char *who)
+{
+       int i;
+       char type[16];
+       size_t total_size = 0;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               const struct e820entry * entry = &e820.map[i];
+               switch (entry->type) {
+               case E820_RAM:  sprintf(type, "(usable)\n");
+                               total_size += entry->size;
+                               break;
+               case E820_RESERVED:
+                               sprintf(type, "(reserved)\n");
+                               break;
+               case E820_ACPI:
+                               sprintf(type, "(ACPI data)\n");
+                               break;
+               case E820_NVS:
+                               sprintf(type, "(ACPI NVS)\n");
+                               break;
+               default:        sprintf(type, "type %u\n", entry->type);
+                               break;
+               }
+
+               printk(KERN_DEBUG
+                       " %s: %016Lx - %016Lx %s",
+                       who,
+                       (unsigned long long) entry->addr,
+                       (unsigned long long) (entry->addr + entry->size),
+                       type);
+       }
+
+       printk( KERN_DEBUG "Total usable memory %ld bytes\n", total_size );
+}
+
+/*
+ * Sanitize the BIOS e820 map.
+ *
+ * Some e820 responses include overlapping entries.  The following 
+ * replaces the original e820 map with a new one, removing overlaps.
+ *
+ */
+static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+{
+       struct change_member {
+               struct e820entry *pbios; /* pointer to original bios entry */
+               unsigned long long addr; /* address for this change point */
+       };
+       static struct change_member change_point_list[2*E820MAX] __initdata;
+       static struct change_member *change_point[2*E820MAX] __initdata;
+       static struct e820entry *overlap_list[E820MAX] __initdata;
+       static struct e820entry new_bios[E820MAX] __initdata;
+       struct change_member *change_tmp;
+       unsigned long current_type, last_type;
+       unsigned long long last_addr;
+       int chgidx, still_changing;
+       int overlap_entries;
+       int new_bios_entry;
+       int old_nr, new_nr, chg_nr;
+       int i;
+
+       /*
+               Visually we're performing the following (1,2,3,4 = memory types)...
+
+               Sample memory map (w/overlaps):
+                  ____22__________________
+                  ______________________4_
+                  ____1111________________
+                  _44_____________________
+                  11111111________________
+                  ____________________33__
+                  ___________44___________
+                  __________33333_________
+                  ______________22________
+                  ___________________2222_
+                  _________111111111______
+                  _____________________11_
+                  _________________4______
+
+               Sanitized equivalent (no overlap):
+                  1_______________________
+                  _44_____________________
+                  ___1____________________
+                  ____22__________________
+                  ______11________________
+                  _________1______________
+                  __________3_____________
+                  ___________44___________
+                  _____________33_________
+                  _______________2________
+                  ________________1_______
+                  _________________4______
+                  ___________________2____
+                  ____________________33__
+                  ______________________4_
+       */
+
+       /* if there's only one memory region, don't bother */
+       if (*pnr_map < 2)
+               return -1;
+
+       old_nr = *pnr_map;
+
+       /* bail out if we find any unreasonable addresses in bios map */
+       for (i=0; i<old_nr; i++)
+               if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
+                       return -1;
+
+       /* create pointers for initial change-point information (for sorting) */
+       for (i=0; i < 2*old_nr; i++)
+               change_point[i] = &change_point_list[i];
+
+       /* record all known change-points (starting and ending addresses),
+          omitting those that are for empty memory regions */
+       chgidx = 0;
+       for (i=0; i < old_nr; i++)      {
+               if (biosmap[i].size != 0) {
+                       change_point[chgidx]->addr = biosmap[i].addr;
+                       change_point[chgidx++]->pbios = &biosmap[i];
+                       change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+                       change_point[chgidx++]->pbios = &biosmap[i];
+               }
+       }
+       chg_nr = chgidx;
+
+       /* sort change-point list by memory addresses (low -> high) */
+       still_changing = 1;
+       while (still_changing)  {
+               still_changing = 0;
+               for (i=1; i < chg_nr; i++)  {
+                       /* if <current_addr> > <last_addr>, swap */
+                       /* or, if current=<start_addr> & last=<end_addr>, swap */
+                       if ((change_point[i]->addr < change_point[i-1]->addr) ||
+                               ((change_point[i]->addr == change_point[i-1]->addr) &&
+                                (change_point[i]->addr == change_point[i]->pbios->addr) &&
+                                (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
+                          )
+                       {
+                               change_tmp = change_point[i];
+                               change_point[i] = change_point[i-1];
+                               change_point[i-1] = change_tmp;
+                               still_changing=1;
+                       }
+               }
+       }
+
+       /* create a new bios memory map, removing overlaps */
+       overlap_entries=0;       /* number of entries in the overlap table */
+       new_bios_entry=0;        /* index for creating new bios map entries */
+       last_type = 0;           /* start with undefined memory type */
+       last_addr = 0;           /* start with 0 as last starting address */
+       /* loop through change-points, determining affect on the new bios map */
+       for (chgidx=0; chgidx < chg_nr; chgidx++)
+       {
+               /* keep track of all overlapping bios entries */
+               if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
+               {
+                       /* add map entry to overlap list (> 1 entry implies an overlap) */
+                       overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
+               }
+               else
+               {
+                       /* remove entry from list (order independent, so swap with last) */
+                       for (i=0; i<overlap_entries; i++)
+                       {
+                               if (overlap_list[i] == change_point[chgidx]->pbios)
+                                       overlap_list[i] = overlap_list[overlap_entries-1];
+                       }
+                       overlap_entries--;
+               }
+               /* if there are overlapping entries, decide which "type" to use */
+               /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
+               current_type = 0;
+               for (i=0; i<overlap_entries; i++)
+                       if (overlap_list[i]->type > current_type)
+                               current_type = overlap_list[i]->type;
+               /* continue building up new bios map based on this information */
+               if (current_type != last_type)  {
+                       if (last_type != 0)      {
+                               new_bios[new_bios_entry].size =
+                                       change_point[chgidx]->addr - last_addr;
+                               /* move forward only if the new size was non-zero */
+                               if (new_bios[new_bios_entry].size != 0)
+                                       if (++new_bios_entry >= E820MAX)
+                                               break;  /* no more space left for new bios entries */
+                       }
+                       if (current_type != 0)  {
+                               new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
+                               new_bios[new_bios_entry].type = current_type;
+                               last_addr=change_point[chgidx]->addr;
+                       }
+                       last_type = current_type;
+               }
+       }
+       new_nr = new_bios_entry;   /* retain count for new bios entries */
+
+       /* copy new bios mapping into original location */
+       memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
+       *pnr_map = new_nr;
+
+       return 0;
+}
+
+/*
+ * Copy the BIOS e820 map into a safe place.
+ *
+ * Sanity-check it while we're at it..
+ *
+ * If we're lucky and live on a modern system, the setup code
+ * will have given us a memory map that we can use to properly
+ * set up memory.  If we aren't, we'll fake a memory map.
+ *
+ * We check to see that the memory map contains at least 2 elements
+ * before we'll use it, because the detection code in setup.S may
+ * not be perfect and most every PC known to man has two memory
+ * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
+ * thinkpad 560x, for example, does not cooperate with the memory
+ * detection code.)
+ */
+static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+{
+       /* Only one memory region (or negative)? Ignore it */
+       if (nr_map < 2)
+               return -1;
+
+       do {
+               unsigned long start = biosmap->addr;
+               unsigned long size = biosmap->size;
+               unsigned long end = start + size;
+               unsigned long type = biosmap->type;
+
+               /* Overflow in 64 bits? Ignore the memory map. */
+               if (start > end)
+                       return -1;
+
+               /*
+                * Some BIOSes claim RAM in the 640k - 1M region.
+                * Not right. Fix it up.
+                * 
+                * This should be removed on Hammer which is supposed to not
+                * have non e820 covered ISA mappings there, but I had some strange
+                * problems so it stays for now.  -AK
+                */
+               if (type == E820_RAM) {
+                       if (start < 0x100000ULL && end > 0xA0000ULL) {
+                               if (start < 0xA0000ULL)
+                                       add_memory_region(start, 0xA0000ULL-start, type);
+                               if (end <= 0x100000ULL)
+                                       continue;
+                               start = 0x100000ULL;
+                               size = end - start;
+                       }
+               }
+
+               add_memory_region(start, size, type);
+       } while (biosmap++,--nr_map);
+       return 0;
+}
+
+void __init setup_memory_region(void)
+{
+       char *who = "BIOS-e820";
+
+       /*
+        * Try to copy the BIOS-supplied E820-map.
+        *
+        * Otherwise fake a memory map; one section from 0k->640k,
+        * the next section from 1mb->appropriate_mem_k
+        */
+       sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+               unsigned long mem_size;
+
+               /* compare results from other methods and take the greater */
+               if (ALT_MEM_K < EXT_MEM_K) {
+                       mem_size = EXT_MEM_K;
+                       who = "BIOS-88";
+               } else {
+                       mem_size = ALT_MEM_K;
+                       who = "BIOS-e801";
+               }
+
+               e820.nr_map = 0;
+               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+       }
+
+       printk(KERN_DEBUG "BIOS-provided physical RAM map:\n");
+       e820_print_map(who);
+
+       /* This also sets end_pfn_map */
+       end_pfn = e820_end_of_ram();
+}
+
+void __init parse_memopt(char *p, char **from) 
+{ 
+       end_user_pfn = memparse(p, from);
+       end_user_pfn >>= PAGE_SHIFT;    
+} 
+
+void __init parse_memmapopt(char *p, char **from)
+{
+       unsigned long long start_at, mem_size;
+
+       mem_size = memparse(p, from);
+       p = *from;
+       if (*p == '@') {
+               start_at = memparse(p+1, from);
+               add_memory_region(start_at, mem_size, E820_RAM);
+       } else if (*p == '#') {
+               start_at = memparse(p+1, from);
+               add_memory_region(start_at, mem_size, E820_ACPI);
+       } else if (*p == '$') {
+               start_at = memparse(p+1, from);
+               add_memory_region(start_at, mem_size, E820_RESERVED);
+       } else {
+               end_user_pfn = (mem_size >> PAGE_SHIFT);
+       }
+       p = *from;
+}
+
+unsigned long pci_mem_start = 0xaeedbabe;
+
+/*
+ * Search for the biggest gap in the low 32 bits of the e820
+ * memory space.  We pass this space to PCI to assign MMIO resources
+ * for hotplug or unconfigured devices in.
+ * Hopefully the BIOS let enough space left.
+ */
+__init void e820_setup_gap(void)
+{
+       unsigned long gapstart, gapsize, round;
+       unsigned long last;
+       int i;
+       int found = 0;
+
+       last = 0x100000000ull;
+       gapstart = 0x10000000;
+       gapsize = 0x400000;
+       i = e820.nr_map;
+       while (--i >= 0) {
+               unsigned long long start = e820.map[i].addr;
+               unsigned long long end = start + e820.map[i].size;
+
+               /*
+                * Since "last" is at most 4GB, we know we'll
+                * fit in 32 bits if this condition is true
+                */
+               if (last > end) {
+                       unsigned long gap = last - end;
+
+                       if (gap > gapsize) {
+                               gapsize = gap;
+                               gapstart = end;
+                               found = 1;
+                       }
+               }
+               if (start < last)
+                       last = start;
+       }
+
+       if (!found) {
+               gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
+               printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n"
+                      KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n");
+       }
+
+       /*
+        * See how much we want to round up: start off with
+        * rounding to the next 1MB area.
+        */
+       round = 0x100000;
+       while ((gapsize >> 4) > round)
+               round += round;
+       /* Fun with two's complement */
+       pci_mem_start = (gapstart + round) & -round;
+
+       printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
+               pci_mem_start, gapstart, gapsize);
+}
diff --git a/kitten/arch/x86_64/kernel/entry.S b/kitten/arch/x86_64/kernel/entry.S
new file mode 100644 (file)
index 0000000..cf15ef8
--- /dev/null
@@ -0,0 +1,386 @@
+#include <lwk/linkage.h>
+#include <lwk/errno.h>
+#include <arch/ptrace.h>
+#include <arch/asm-offsets.h>
+#include <arch/idt_vectors.h>
+#include <arch/dwarf2.h>
+#include <arch/task.h>
+
+
+/**
+ * This performs the architecture-specific portion of a context switch.
+ * Normally, this is called in the context of prev and returns in the
+ * context of next. However, new tasks are handled differently. Since
+ * new tasks do not yet have a kernel context (rather, their kernel
+ * stack just has the pt_regs to use for the new task), execution returns
+ * directly to the new task, rather than context_switch().
+ *
+ * Input Registers: 
+ *     RDI = prev
+ *     RSI = next
+ *
+ * Output Registers::
+ *     RAX = prev (same value as on entry)
+ *
+ * C Prototype:
+ *     struct task_struct *arch_context_switch(struct task_struct *prev,
+ *                                             struct task_struct *next);
+ *     arch_context_switch() returns prev
+ *
+ * NOTE: External interrupts are disabled on entry.
+ */
+ENTRY(arch_context_switch)
+       /* Save prev's callee saved registers (others saved by caller) */
+       pushf
+       pushq %rbp
+       pushq %rbx
+       pushq %r12
+       pushq %r13
+       pushq %r14
+       pushq %r15
+
+       /* Switch to next's stack */
+       movq %rsp, tsk_arch_rsp(%rdi)
+       movq tsk_arch_rsp(%rsi), %rsp
+
+       /* Call C code to do more stuff (save/restore FPU, update PDA, ...) */
+       call __arch_context_switch
+       /* returns with %rax set to prev */
+       movq %rax, %rdi
+       movq %gs:pda_pcurrent, %rsi
+
+       /* New tasks need to be kick-started */
+       lock btr $_TF_NEW_TASK_BIT, tsk_arch_flags(%rsi)
+       jc kickstart_new_task
+
+       /* Restore next's callee saved registers */
+       popq %r15
+       popq %r14
+       popq %r13
+       popq %r12
+       popq %rbx
+       popq %rbp
+       popf;
+
+       /* Return to context_switch(), with new task active */
+       retq
+
+kickstart_new_task:
+       call schedule_new_task_tail /* Finish up schedule(), drop locks, etc. */
+       testl $3, CS(%rsp)          /* Sets ZF=1 if returning to kernel-space */
+       je 1f                       /*     If ZF=1, leave kernel PDA in place */
+       swapgs                      /* Install the user PDA                   */
+       movq $0, %rax               /* Zero all of the segment registers      */
+       movl %eax, %ds
+       movl %eax, %es
+       movl %eax, %fs
+       movl %eax, %gs
+1:
+       movq     (%rsp), %r15       /* Unpack the pt_regs struct that         */
+       movq  1*8(%rsp), %r14       /* __arch_context_switch() put at the top */
+       movq  2*8(%rsp), %r13       /* of the new task's kernel stack.        */
+       movq  3*8(%rsp), %r12
+       movq  4*8(%rsp), %rbp
+       movq  5*8(%rsp), %rbx
+       movq  6*8(%rsp), %r11
+       movq  7*8(%rsp), %r10
+       movq  8*8(%rsp), %r9
+       movq  9*8(%rsp), %r8
+       movq 10*8(%rsp), %rax
+       movq 11*8(%rsp), %rcx
+       movq 12*8(%rsp), %rdx
+       movq 13*8(%rsp), %rsi
+       movq 14*8(%rsp), %rdi
+       add $128, %rsp              /* Bump to point to RIP slot in pt_regs   */
+       iretq                       /* Start the new task running             */
+
+END(arch_context_switch)
+
+
+/**
+ * This is the entry point for system calls. Upon entry we are still running
+ * with the user-level stack and the x86_64 CPU control unit has stashed the
+ * user-level RIP in RCX and RFLAGS in R11. External interrupts are diabled.
+ *
+ * The first thing this function does is generate a partial stack frame
+ * containing all caller-saved registers. After this is done, the system call
+ * number (stored in RAX by user-level) is used to index into the system call
+ * table (sys_call_table) and call the handler function. The handler function
+ * is responsible for saving all callee-saved registers... if it is a C
+ * function, callee-saved registers are saved automatically by the compiler.
+ *
+ * Immediately before calling the handler function, the kernel stack looks
+ * like:
+ *
+ *            RIP      = user-space RIP
+ *            ORIG_RAX = system call number, passed from user-space
+ *            RDI      = ARG0, passed from user-space
+ *            RSI      = ARG1, passed from user-space
+ *            RDX      = ARG2, passed from user-space
+ *            (junk)   = normally RCX, but RCX is clobbered by SYSCALL
+ *            RAX      = system call number, passed from user-space
+ *            R8       = ARG4, passed from user-space
+ *            R9       = ARG5, passed from user-space
+ *            R10      = ARG3, passed from user-space
+ *     RSP -> R11      = user-space RFLAGS
+ *
+ * And the registers are setup as follows:
+ *
+ *            RDI      = ARG0
+ *            RSI      = ARG1
+ *            RDX      = ARG2
+ *            RCX      = ARG3 (was stored on R10 on entry)
+ *            R8       = ARG4
+ *            R9       = ARG5
+ *            RAX      = System call number
+ *
+ * NOTE: RCX and R11 are clobbered by system calls. This is due to the SYSCALL
+ *       instruction using RCX and R11 to store RIP and RFLAGS before
+ *       transfering control to the kernel. User-level will observe different
+ *       values of RCX and R11 after SYSCALL than before.
+ * 
+ * NOTE: External interrupts are disabled on entry.
+ */
+ENTRY(asm_syscall)
+       /*
+        * Enter from user-space
+        */
+       swapgs                          /* Load GS.base with kernel PDA addr */
+       movq %rsp, %gs:pda_oldrsp       /* Backup user-space RSP             */
+       movq %gs:pda_kernelstack, %rsp  /* Load kernel stack                 */
+
+       /*
+        * Save registers to kernel-stack
+        */
+       subq $10*8, %rsp                /* Make room on the stack            */
+       movq %rcx, 10*8(%rsp)           /* Save user-space RIP               */
+       movq %rax,  9*8(%rsp)           /* Save syscall # in ORIG_RAX slot   */
+       movq %rdi,  8*8(%rsp)           /* Save user-space RDI (ARG0)        */
+       movq %rsi,  7*8(%rsp)           /* Save user-space RSI (ARG1)        */
+       movq %rdx,  6*8(%rsp)           /* Save user-space RDX (ARG2)        */
+       movq %rcx,  5*8(%rsp)           /* RCX is clobbered, save anyways    */
+       movq %rax,  4*8(%rsp)           /* Save user-space RAX (syscall #)   */
+       movq %r8,   3*8(%rsp)           /* Save user-space R8  (ARG4)        */
+       movq %r9,   2*8(%rsp)           /* Save user-space R9  (ARG5)        */
+       movq %r10,  1*8(%rsp)           /* Save user-space R10 (ARG3)        */
+       movq %r11,     (%rsp)           /* Save user-space RFLAGS            */
+       sti                             /* Enable external interrupts        */
+
+       /*
+        * Call the system call handler
+        */
+       movq %r10, %rcx                 /* Per x86_64 C ABI, RCX holds ARG3  */
+       cmp $__NR_syscall_max, %rax     /* Make sure syscall # is in range   */
+       jg 1f
+       call *sys_call_table(,%rax,8)   /* Call the system call handler      */
+       jmp 2f
+1:
+       call syscall_not_implemented    /* Print error and return            */
+2:
+       movq %rax, 4*8(%rsp)            /* Save return code in stack frame   */
+
+       /* Reschedule, since we're returning to user space */
+       call schedule
+
+       /*
+        * Return to user-space
+        */
+       cli                             /* Disable external interrupts       */
+       movq     (%rsp), %r11           /* Restore RFLAGS for SYSRET         */
+       movq  1*8(%rsp), %r10           /* Restore user-space R10 (ARG3)     */
+       movq  2*8(%rsp), %r9            /* Restore user-space R9  (ARG5)     */
+       movq  3*8(%rsp), %r8            /* Restore user-space R8  (ARG4)     */
+       movq  4*8(%rsp), %rax           /* Return syscall return code        */
+       movq  6*8(%rsp), %rdx           /* Restore user-space RDX (ARG2)     */
+       movq  7*8(%rsp), %rsi           /* Restore user-space RSI (ARG1)     */
+       movq  8*8(%rsp), %rdi           /* Restore user-space RDI (ARG0)     */
+       movq 10*8(%rsp), %rcx           /* Restore RIP for SYSRET            */
+       movq %gs:pda_oldrsp, %rsp       /* Restore user-space RSP            */
+       swapgs                          /* Restore user-space GS.base        */
+       sysretq                         /* Return to user-space              */
+END(asm_syscall)
+
+
+/**
+ * This is a handler for SYSCALL instructions issued from compatibility mode...
+ * we don't support them.
+ */
+ENTRY(asm_syscall_ignore)
+       mov $-ENOSYS,%eax
+       sysret
+END(asm_syscall_ignore)
+
+
+/**
+ * This is the common entry point for all interrupts. 
+ * 
+ * Before calling the C handler function, the kernel stack looks like:
+ *
+ *            [...]
+ *            SS         (stack segment selector)
+ *            RSP        (stack pointer)
+ *            RFLAGS     (flags register)
+ *            CS         (code segment selector)
+ *            RIP        (instruction pointer)
+ *            ERROR_CODE (0 for interrupts with no error code)
+ *            RDI        (this was the vector # on entry, we move to %rsi/ARG1)
+ *            RSI
+ *            RDX
+ *            RCX
+ *            RAX
+ *            R8
+ *            R9
+ *            R10
+ *            R11
+ *            RBX
+ *            RBP
+ *            R12
+ *            R13
+ *            R14
+ *     RSP -> R15
+ *
+ * And the registers are setup as follows:
+ *
+ *            RDI      = ARG0: A fully populated 'struct pt_regs *'
+ *            RSI      = ARG1: The interrupt vector number 
+ *
+ * NOTE: External interrupts are disabled on entry.
+ */
+ENTRY(asm_interrupt)
+       cld                             /* Clear direction flag              */
+
+       /*
+        * Save registers to kernel-stack
+        */
+       subq $14*8, %rsp                /* Make room on the stack            */
+       movq %rsi, 13*8(%rsp)
+       movq 14*8(%rsp), %rsi           /* ARG1: the interrupt vector number */
+       movq %rdi, 14*8(%rsp)
+       movq %rdx, 12*8(%rsp)
+       movq %rcx, 11*8(%rsp)
+       movq %rax, 10*8(%rsp)
+       movq %r8,   9*8(%rsp)
+       movq %r9,   8*8(%rsp)
+       movq %r10,  7*8(%rsp) 
+       movq %r11,  6*8(%rsp) 
+       movq %rbx,  5*8(%rsp)
+       movq %rbp,  4*8(%rsp)
+       movq %r12,  3*8(%rsp)
+       movq %r13,  2*8(%rsp)
+       movq %r14,  1*8(%rsp)
+       movq %r15,     (%rsp)
+
+       /*
+        * Load kernel GS if we're coming from user-space
+        */
+       testl $3, CS(%rsp)              /* Sets ZF=1 if coming from kspace   */
+       je 1f                           /* If ZF=1, skip installing the PDA  */
+       swapgs                          /* Install the PDA                   */
+1:     
+       /*
+        * Call C code interrupt handler entry point
+        */
+       movq %rsp, %rdi                 /* ARG0: pointer to 'struct pt_regs' */
+       sti                             /* Enable external interrupts        */
+       call do_interrupt               /* Call common C handler             */
+       cli                             /* Disable external interrupts       */
+
+       /*
+        * If returning to user-space, reschedule and restore user-space GS
+        */
+       testl $3, CS(%rsp)              /* Sets ZF=1 if returning to kspace  */
+       je 2f                           /* If ZF=1, jump forward to 2: below */
+       sti                             /* Enable external interrupts        */
+       call schedule                   /* Reschedule                        */
+       cli                             /* Disable external interrupts       */
+       swapgs                          /* Restore uspace GS register        */
+2:
+       /*
+        * Restore registers and return to interrupted program
+        */
+       movq     (%rsp), %r15
+       movq  1*8(%rsp), %r14
+       movq  2*8(%rsp), %r13
+       movq  3*8(%rsp), %r12
+       movq  4*8(%rsp), %rbp
+       movq  5*8(%rsp), %rbx
+       movq  6*8(%rsp), %r11
+       movq  7*8(%rsp), %r10
+       movq  8*8(%rsp), %r9
+       movq  9*8(%rsp), %r8
+       movq 10*8(%rsp), %rax
+       movq 11*8(%rsp), %rcx
+       movq 12*8(%rsp), %rdx
+       movq 13*8(%rsp), %rsi
+       movq 14*8(%rsp), %rdi
+       addq $16*8, %rsp
+       iretq
+END(asm_interrupt)
+
+
+/**
+ * This table contains an initial entry point function for each IDT vector.
+ * When an interrupt vector fires, the first instruction executed is at
+ * table[vector].
+ *
+ * This table scheme is necessary because some x86_64 interrupts push an
+ * error code onto the stack and others do not. Additionally, there is no way
+ * for an interrupt handler to determine the interrupt vector that triggered
+ * it. Therefore, the functions in this table push a dummy error code onto
+ * the stack when necessary, always push the vector number, and then call a
+ * common handler (asm_interrupt).
+ *
+ * WARNING: Each function/entry in this table must be <= 16 bytes.
+ *          Be very careful when adding instructions.
+ */
+.align 16
+ENTRY(asm_idtvec_table)
+       vector=0
+       .rept NUM_IDT_ENTRIES
+               .if vector<=7||vector==9||vector==15||vector==16||vector>=18
+               pushq $0                /* push dummy error_code */
+               .endif
+               pushq $vector           /* push vector # into RDI slot */
+               jmp asm_interrupt       /* call common handler */
+
+               /* Move onto next entry in table*/
+               .align 16
+               vector=vector+1
+       .endr
+END(asm_idtvec_table)
+
+
+/**
+ * Reload gs selector with exception handling.
+ *     edi:  new selector
+ */
+ENTRY(load_gs_index)
+       CFI_STARTPROC
+       pushf
+       CFI_ADJUST_CFA_OFFSET 8
+       cli
+       swapgs
+gs_change:
+       movl %edi,%gs
+2:     mfence          /* workaround */
+       swapgs
+       popf
+       CFI_ADJUST_CFA_OFFSET -8
+       ret
+       CFI_ENDPROC
+ENDPROC(load_gs_index)
+
+       .section __ex_table,"a"
+       .align 8
+       .quad gs_change,bad_gs
+       .previous
+       .section .fixup,"ax"
+       /* running with kernelgs */
+bad_gs:
+       swapgs                  /* switch back to user gs */
+       xorl %eax,%eax
+       movl %eax,%gs
+       jmp  2b
+       .previous
+
+
diff --git a/kitten/arch/x86_64/kernel/head.S b/kitten/arch/x86_64/kernel/head.S
new file mode 100644 (file)
index 0000000..3bcaadd
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ *  linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
+ *
+ *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ *  Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
+ *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
+ *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
+ *  Copyright (C) 2005 Eric Biederman <ebiederm@xmission.com>
+ */
+
+
+#include <lwk/linkage.h>
+#include <lwk/init.h>
+#include <lwk/cpu.h>
+#include <arch/desc.h>
+#include <arch/segment.h>
+#include <arch/pgtable.h>
+#include <arch/page.h>
+#include <arch/msr.h>
+#include <arch/cache.h>
+
+/* we are not able to switch in one step to the final KERNEL ADRESS SPACE
+ * because we need identity-mapped pages.
+ *
+ */
+
+       .text
+       .section .bootstrap.text
+
+#ifdef CONFIG_CRAY_XT
+       .code32
+       .globl startup_32
+startup_32:
+       cld
+       cli
+       movl    $(__KERNEL_DS), %eax
+       movl    %eax, %ds
+       lgdt    gdt32_descr - __START_KERNEL_map
+
+       /* Enable PAE mode and PGE */
+       xorl    %eax, %eax
+       btsl    $5,   %eax      /* enable PAE */
+       btsl    $7,   %eax      /* enable PGE */
+       movl    %eax, %cr4
+
+       /* Setup early boot page tables */
+       movl    $(init_level4_pgt - __START_KERNEL_map), %eax
+       movl    %eax, %cr3
+
+       /* Enable Long Mode */
+       movl    $MSR_EFER, %ecx
+       rdmsr
+       btsl    $_EFER_LME, %eax
+       wrmsr
+       xorl    %eax, %eax
+       btsl    $31,  %eax      /* enable paging */
+       btsl    $0,   %eax      /* enable protected mode */
+       movl    %eax, %cr0
+
+       /* coldstart uses a hard-coded address for real_mode_data */
+       movl    $0x90000, %esi
+
+       /*
+        * At this point we're in long mode but 32-bit compatibility mode.
+        * This jump transitions us into true 64-bit mode.
+        */
+       ljmp    $__KERNEL_CS, $(startup_64 - __START_KERNEL_map)
+#endif /* CONFIG_CRAY_XT */
+
+       .code64
+       .globl startup_64
+startup_64:
+
+       /*
+        * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
+        * and someone has loaded an identity mapped page table
+        * for us.  These identity mapped page tables map all of the
+        * kernel pages and possibly all of memory.
+        *
+        * %esi holds a physical pointer to real_mode_data.
+        *
+        * We come here either directly from a 64bit bootloader, or from
+        * arch/x86_64/boot/compressed/head.S.
+        *
+        * We only come here initially at boot nothing else comes here.
+        *
+        * Since we may be loaded at an address different from what we were
+        * compiled to run at we first fixup the physical addresses in our page
+        * tables and then reload them.
+        */
+
+       /* Compute the delta between the address I am compiled to run at and the
+        * address I am actually running at.
+        */
+       leaq    _text(%rip), %rbp
+       subq    $_text - __START_KERNEL_map, %rbp
+
+       /* Is the address not 2M aligned? */
+       movq    %rbp, %rax
+       andl    $~LARGE_PAGE_MASK, %eax
+       testl   %eax, %eax
+       jnz     bad_address
+
+       /* Is the address too large? */
+       leaq    _text(%rip), %rdx
+       movq    $PGDIR_SIZE, %rax
+       cmpq    %rax, %rdx
+       jae     bad_address
+
+       /* Fixup the physical addresses in the page table
+        */
+       addq    %rbp, init_level4_pgt + 0(%rip)
+       addq    %rbp, init_level4_pgt + (258*8)(%rip)
+       addq    %rbp, init_level4_pgt + (511*8)(%rip)
+
+       addq    %rbp, level3_ident_pgt + 0(%rip)
+       addq    %rbp, level3_kernel_pgt + (510*8)(%rip)
+
+       /* Add an Identity mapping if I am above 1G */
+       leaq    _text(%rip), %rdi
+       andq    $LARGE_PAGE_MASK, %rdi
+
+       movq    %rdi, %rax
+       shrq    $PUD_SHIFT, %rax
+       andq    $(PTRS_PER_PUD - 1), %rax
+       jz      ident_complete
+
+       leaq    (level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+       leaq    level3_ident_pgt(%rip), %rbx
+       movq    %rdx, 0(%rbx, %rax, 8)
+
+       movq    %rdi, %rax
+       shrq    $PMD_SHIFT, %rax
+       andq    $(PTRS_PER_PMD - 1), %rax
+       leaq    __PAGE_KERNEL_LARGE_EXEC(%rdi), %rdx
+       leaq    level2_spare_pgt(%rip), %rbx
+       movq    %rdx, 0(%rbx, %rax, 8)
+ident_complete:
+
+       /* Fixup the kernel text+data virtual addresses
+        */
+       leaq    level2_kernel_pgt(%rip), %rdi
+       leaq    4096(%rdi), %r8
+       /* See if it is a valid page table entry */
+1:     testq   $1, 0(%rdi)
+       jz      2f
+       addq    %rbp, 0(%rdi)
+       /* Go to the next page */
+2:     addq    $8, %rdi
+       cmp     %r8, %rdi
+       jne     1b
+
+       /* Fixup phys_base */
+       addq    %rbp, phys_base(%rip)
+
+       addq    %rbp, trampoline_level4_pgt + 0(%rip)
+       addq    %rbp, trampoline_level4_pgt + (511*8)(%rip)
+#ifdef CONFIG_ACPI_SLEEP
+       addq    %rbp, wakeup_level4_pgt + 0(%rip)
+       addq    %rbp, wakeup_level4_pgt + (511*8)(%rip)
+#endif
+
+       /* Due to ENTRY(), sometimes the empty space gets filled with
+        * zeros. Better take a jmp than relying on empty space being
+        * filled with 0x90 (nop)
+        */
+       jmp secondary_startup_64
+ENTRY(secondary_startup_64)
+       /*
+        * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
+        * and someone has loaded a mapped page table.
+        *
+        * %esi holds a physical pointer to real_mode_data.
+        *
+        * We come here either from startup_64 (using physical addresses)
+        * or from trampoline.S (using virtual addresses).
+        *
+        * Using virtual addresses from trampoline.S removes the need
+        * to have any identity mapped pages in the kernel page table
+        * after the boot processor executes this code.
+        */
+
+       /* Enable PAE mode and PGE */
+       xorq    %rax, %rax
+       btsq    $5, %rax
+       btsq    $7, %rax
+       movq    %rax, %cr4
+
+       /* Setup early boot stage 4 level pagetables. */
+       movq    $(init_level4_pgt - __START_KERNEL_map), %rax
+       addq    phys_base(%rip), %rax
+       movq    %rax, %cr3
+
+       /* Ensure I am executing from virtual addresses */
+       movq    $1f, %rax
+       jmp     *%rax
+1:
+
+       /* Check if nx is implemented */
+       movl    $0x80000001, %eax
+       cpuid
+       movl    %edx,%edi
+
+       /* Setup EFER (Extended Feature Enable Register) */
+       movl    $MSR_EFER, %ecx
+       rdmsr
+       btsl    $_EFER_SCE, %eax        /* Enable System Call */
+       btl     $20,%edi                /* No Execute supported? */
+       jnc     1f
+       btsl    $_EFER_NX, %eax
+1:     wrmsr                           /* Make changes effective */
+
+       /* Setup cr0 */
+#define CR0_PM                         1               /* protected mode */
+#define CR0_MP                         (1<<1)
+#define CR0_ET                         (1<<4)
+#define CR0_NE                         (1<<5)
+#define CR0_WP                         (1<<16)
+#define CR0_AM                         (1<<18)
+#define CR0_PAGING                     (1<<31)
+       movl $CR0_PM|CR0_MP|CR0_ET|CR0_NE|CR0_WP|CR0_AM|CR0_PAGING,%eax
+       /* Make changes effective */
+       movq    %rax, %cr0
+
+       /* Setup a boot time stack */
+       movq init_rsp(%rip),%rsp
+
+       /* zero EFLAGS after setting rsp */
+       pushq $0
+       popfq
+
+       /*
+        * We must switch to a new descriptor in kernel space for the GDT
+        * because soon the kernel won't have access anymore to the userspace
+        * addresses where we're currently running on. We have to do that here
+        * because in 32bit we couldn't load a 64bit linear address.
+        */
+       lgdt    cpu_gdt_descr(%rip)
+
+       /* set up data segments. actually 0 would do too */
+       movl $__KERNEL_DS,%eax
+       movl %eax,%ds
+       movl %eax,%ss
+       movl %eax,%es
+
+       /*
+        * We don't really need to load %fs or %gs, but load them anyway
+        * to kill any stale realmode selectors.  This allows execution
+        * under VT hardware.
+        */
+       movl %eax,%fs
+       movl %eax,%gs
+
+       /* 
+        * Setup up a dummy PDA. this is just for some early bootup code
+        * that does in_interrupt() 
+        */ 
+       movl    $MSR_GS_BASE,%ecx
+       movq    $empty_zero_page,%rax
+       movq    %rax,%rdx
+       shrq    $32,%rdx
+       wrmsr   
+
+       /* esi is pointer to real mode structure with interesting info.
+          pass it to C */
+       movl    %esi, %edi
+       
+       /* Finally jump to run C code and to be on real kernel address
+        * Since we are running on identity-mapped space we have to jump
+        * to the full 64bit address, this is only possible as indirect
+        * jump.  In addition we need to ensure %cs is set so we make this
+        * a far return.
+        */
+       movq    initial_code(%rip),%rax
+       pushq   $0              # fake return address to stop unwinder
+       pushq   $__KERNEL_CS    # set correct cs
+       pushq   %rax            # target address in negative space
+       lretq
+
+       /* SMP bootup changes these two */
+       .align  8
+       .globl  initial_code
+initial_code:
+       .quad   x86_64_start_kernel
+       .globl init_rsp
+init_rsp:
+       .quad  bootstrap_task_union+TASK_SIZE-8
+
+bad_address:
+       jmp bad_address
+
+ENTRY(early_idt_handler)
+       cmpl $2,early_recursion_flag(%rip)
+       jz  1f
+       incl early_recursion_flag(%rip)
+       xorl %eax,%eax
+       movq 8(%rsp),%rsi       # get rip
+       movq (%rsp),%rdx
+       movq %cr2,%rcx
+       leaq early_idt_msg(%rip),%rdi
+       call printk
+       cmpl $2,early_recursion_flag(%rip)
+       jz  1f
+//     call dump_stack
+1:     hlt
+       jmp 1b
+early_recursion_flag:
+       .long 0
+
+early_idt_msg:
+       .asciz "PANIC: early exception rip %lx error %lx cr2 %lx\n"
+early_idt_ripmsg:
+       .asciz "RIP %s\n"
+
+.balign PAGE_SIZE
+
+#define NEXT_PAGE(name) \
+       .balign PAGE_SIZE; \
+ENTRY(name)
+
+/* Automate the creation of 1 to 1 mapping pmd entries */
+#define PMDS(START, PERM, COUNT)               \
+       i = 0 ;                                 \
+       .rept (COUNT) ;                         \
+       .quad   (START) + (i << 21) + (PERM) ;  \
+       i = i + 1 ;                             \
+       .endr
+
+       /*
+        * This default setting generates an ident mapping at address 0x100000
+        * and a mapping for the kernel that precisely maps virtual address
+        * 0xffffffff80000000 to physical address 0x000000. (always using
+        * 2Mbyte large pages provided by PAE mode)
+        */
+NEXT_PAGE(init_level4_pgt)
+       .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+       .fill   257,8,0
+       .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+       .fill   252,8,0
+       /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+       .quad   level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
+
+NEXT_PAGE(level3_ident_pgt)
+       .quad   level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+       .fill   511,8,0
+
+NEXT_PAGE(level3_kernel_pgt)
+       .fill   510,8,0
+       /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
+       .quad   level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
+#ifndef CONFIG_CRAY_XT
+        .fill   1,8,0
+#else
+        .quad   level2_seastar_pgt - __START_KERNEL_map + _KERNPG_TABLE
+#endif
+
+NEXT_PAGE(level2_ident_pgt)
+       /* Since I easily can, map the first 1G.
+        * Don't set NX because code runs from these pages.
+        */
+       PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
+
+NEXT_PAGE(level2_kernel_pgt)
+       /* 40MB kernel mapping. The kernel code cannot be bigger than that.
+          When you change this change KERNEL_TEXT_SIZE in page.h too. */
+       /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
+       PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL, KERNEL_TEXT_SIZE/PMD_SIZE)
+       /* Module mapping starts here */
+       .fill   (PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0
+
+#ifdef CONFIG_CRAY_XT
+NEXT_PAGE(level2_seastar_pgt)
+        .fill 511,8,0
+        .quad   0x00000000ffe00193
+#endif
+
+NEXT_PAGE(level2_spare_pgt)
+       .fill   512,8,0
+
+#undef PMDS
+#undef NEXT_PAGE
+
+       .data
+       .align 16
+       .globl cpu_gdt_descr
+cpu_gdt_descr:
+       .word   gdt_end-cpu_gdt_table-1
+gdt:
+       .quad   cpu_gdt_table
+       .rept   NR_CPUS-1
+       .word   0
+       .quad   0
+       .endr
+
+#ifdef CONFIG_CRAY_XT
+       .align 16
+       .globl gdt32_descr
+gdt32_descr:
+       .word   gdt_end-cpu_gdt_table-1
+       .long   cpu_gdt_table-__START_KERNEL_map
+#endif
+
+ENTRY(phys_base)
+       /* This must match the first entry in level2_kernel_pgt */
+       .quad   0x0000000000000000
+
+/* We need valid kernel segments for data and code in long mode too
+ * IRET will check the segment types  kkeil 2000/10/28
+ * Also sysret mandates a special GDT layout 
+ */
+                               
+       .section .data.page_aligned, "aw"
+       .align PAGE_SIZE
+
+/* The TLS descriptors are currently at a different place compared to i386.
+   Hopefully nobody expects them at a fixed place (Wine?) */
+       
+ENTRY(cpu_gdt_table)
+       .quad   0x0000000000000000      /* NULL descriptor */
+       .quad   0x00cf9b000000ffff      /* __KERNEL32_CS */
+       .quad   0x00af9b000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf93000000ffff      /* __KERNEL_DS */
+       .quad   0x00cffb000000ffff      /* __USER32_CS */
+       .quad   0x00cff3000000ffff      /* __USER_DS, __USER32_DS  */
+       .quad   0x00affb000000ffff      /* __USER_CS */
+       .quad   0x0                     /* unused */
+       .quad   0,0                     /* TSS */
+       .quad   0,0                     /* LDT */
+       .quad   0,0,0                   /* three TLS descriptors */ 
+       .quad   0x0000f40000000000      /* node/CPU stored in limit */
+gdt_end:       
+       /* asm/segment.h:GDT_ENTRIES must match this */ 
+       /* This should be a multiple of the cache line size */
+       /* GDTs of other CPUs are now dynamically allocated */
+
+       /* zero the remaining page */
+       .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0
+
+       .section .bss, "aw", @nobits
+       .align L1_CACHE_BYTES
+ENTRY(idt_table)
+       .skip 256 * 16
+
+       .section .bss.page_aligned, "aw", @nobits
+       .align PAGE_SIZE
+ENTRY(empty_zero_page)
+       .skip PAGE_SIZE
diff --git a/kitten/arch/x86_64/kernel/head64.c b/kitten/arch/x86_64/kernel/head64.c
new file mode 100644 (file)
index 0000000..38d5588
--- /dev/null
@@ -0,0 +1,136 @@
+#include <lwk/init.h>
+#include <lwk/kernel.h>
+#include <lwk/string.h>
+#include <lwk/screen_info.h>
+#include <lwk/params.h>
+#include <lwk/smp.h>
+#include <lwk/cpuinfo.h>
+#include <arch/bootsetup.h>
+#include <arch/sections.h>
+#include <arch/pda.h>
+#include <arch/processor.h>
+#include <arch/desc.h>
+#include <arch/proto.h>
+#include <arch/page.h>
+#include <arch/pgtable.h>
+#include <arch/tlbflush.h>
+
+/**
+ * Data passed to the kernel by the bootloader.
+ *
+ * NOTE: This is marked as __initdata so it goes away after the
+ *       kernel bootstrap process is complete.
+ */
+char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
+
+/**
+ * Interrupt Descriptor Table (IDT) descriptor.
+ *
+ * This descriptor contains the length of the IDT table and a
+ * pointer to the table.  The lidt instruction (load IDT) requires
+ * this format.
+ */
+struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
+
+/**
+ * Array of pointers to each CPU's per-processor data area.
+ * The array is indexed by CPU ID.
+ */
+struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly;
+
+/**
+ * Array of per-processor data area structures, one per CPU.
+ * The array is indexed by CPU ID.
+ */
+struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned;
+
+/**
+ * This unmaps virtual addresses [0,512GB) by clearing the first entry in the
+ * PGD/PML4T. After this executes, accesses to virtual addresses [0,512GB) will
+ * cause a page fault.
+ */
+static void __init
+zap_identity_mappings(void)
+{
+       pgd_t *pgd = pgd_offset_k(0UL);
+       pgd_clear(pgd);
+       __flush_tlb();
+}
+
+/**
+ * Determines the address of the kernel boot command line.
+ */
+static char * __init
+find_command_line(void)
+{
+       unsigned long new_data;
+
+       new_data = *(u32 *) (x86_boot_params + NEW_CL_POINTER);
+       if (!new_data) {
+               if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
+                       return NULL;
+               }
+               new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
+       }
+       return __va(new_data);
+}
+
+/**
+ * This is the initial C entry point to the kernel.
+ * NOTE: The order of operations is usually important.  Be careful.
+ */
+void __init
+x86_64_start_kernel(char * real_mode_data)
+{
+       int i;
+
+       /*
+        * Zero the "Block Started by Symbol" section...
+        * you know, the one that holds uninitialized data.
+        */
+       memset(__bss_start, 0,
+              (unsigned long) __bss_stop - (unsigned long) __bss_start);
+
+       /*
+        * Make NULL pointer dereferences segfault.
+        */
+       zap_identity_mappings();
+
+       /*
+        * Setup the initial interrupt descriptor table (IDT).
+        * This will be eventually be populated with the real handlers.
+        */
+       for (i = 0; i < 256; i++)
+               set_intr_gate(i, early_idt_handler);
+       asm volatile("lidt %0" :: "m" (idt_descr));
+
+       /*
+        * Early per-processor data area (PDA) initialization.
+        */
+       for (i = 0; i < NR_CPUS; i++)
+               cpu_pda(i) = &boot_cpu_pda[i];
+       pda_init(0, &bootstrap_task_union.task_info);
+
+       /*
+        * Make a copy data passed by the bootloader.
+        * real_mode_data will get clobbered eventually when the memory
+        * subsystem is initialized.
+        */
+       memcpy(x86_boot_params, __va(real_mode_data), sizeof(x86_boot_params));
+       memcpy(lwk_command_line, find_command_line(), sizeof(lwk_command_line));
+       
+       /*
+        * Tell the VGA driver the starting line number... this avoids
+        * overwriting BIOS and bootloader messages. 
+        */
+       param_set_by_name_int("vga.row", SCREEN_INFO.orig_y);
+
+       /* 
+        * Okay... we've done the bare essentials. Call into the 
+        * platform-independent bootstrap function. This will in turn
+        * call back into architecture dependent code to do things like
+        * initialize interrupts and boot CPUs. 
+        */
+       start_kernel();
+}
+
diff --git a/kitten/arch/x86_64/kernel/i387.c b/kitten/arch/x86_64/kernel/i387.c
new file mode 100644 (file)
index 0000000..f4a5678
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  linux/arch/x86_64/kernel/i387.c
+ *
+ *  Copyright (C) 1994 Linus Torvalds
+ *  Copyright (C) 2002 Andi Kleen, SuSE Labs
+ *
+ *  Pentium III FXSR, SSE support
+ *  General FPU state handling cleanups
+ *     Gareth Hughes <gareth@valinux.com>, May 2000
+ * 
+ *  x86-64 rework 2002 Andi Kleen. 
+ *  Does direct fxsave in and out of user space now for signal handlers.
+ *  All the FSAVE<->FXSAVE conversion code has been moved to the 32bit emulation,
+ *  the 64bit user space sees a FXSAVE frame directly. 
+ */
+
+#include <lwk/task.h>
+#include <lwk/init.h>
+#include <arch/processor.h>
+#include <arch/i387.h>
+#include <arch/sigcontext.h>
+#include <arch/user.h>
+#include <arch/ptrace.h>
+#include <arch/uaccess.h>
+
+unsigned int mxcsr_feature_mask __read_mostly = 0xffffffff;
+
+void mxcsr_feature_mask_init(void)
+{
+       unsigned int mask;
+       clts();
+       memset(&current->arch.thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
+       asm volatile("fxsave %0" : : "m" (current->arch.thread.i387.fxsave));
+       mask = current->arch.thread.i387.fxsave.mxcsr_mask;
+       if (mask == 0) mask = 0x0000ffbf;
+       mxcsr_feature_mask &= mask;
+       stts();
+}
+
+/*
+ * Called at bootup to set up the initial FPU state that is later cloned
+ * into all processes.
+ */
+void __cpuinit fpu_init(void)
+{
+       unsigned long oldcr0 = read_cr0();
+       extern void __bad_fxsave_alignment(void);
+               
+       if (offsetof(struct task_struct, arch.thread.i387.fxsave) & 15)
+               __bad_fxsave_alignment();
+       set_in_cr4(X86_CR4_OSFXSR);     /* enable fast FPU state save/restore */
+       set_in_cr4(X86_CR4_OSXMMEXCPT); /* enable unmasked SSE exceptions */
+
+       write_cr0(oldcr0 & ~((1UL<<3)|(1UL<<2))); /* clear TS and EM */
+
+       mxcsr_feature_mask_init();
+       /* clean state in init */
+       current->arch.flags = 0;
+       clear_used_math();
+}
+
diff --git a/kitten/arch/x86_64/kernel/init_task.c b/kitten/arch/x86_64/kernel/init_task.c
new file mode 100644 (file)
index 0000000..03441f5
--- /dev/null
@@ -0,0 +1,39 @@
+#include <lwk/task.h>
+#include <lwk/init_task.h>
+#include <lwk/percpu.h>
+#include <lwk/aspace.h>
+#include <arch/processor.h>
+
+struct aspace bootstrap_aspace = {
+       BOOTSTRAP_ASPACE(bootstrap_aspace)
+       .arch = {
+               .pgd = (xpte_t *) init_level4_pgt
+       }
+};
+
+union task_union bootstrap_task_union
+       __attribute__((__section__(".data.bootstrap_task"))) =
+               {
+                       /* Initialize task_union.task_info */
+                       {
+                               /* arch independent portion */
+                               BOOTSTRAP_TASK(bootstrap_task_union.task_info)
+
+                               /* x86_64 specific portion */
+                               .arch = {
+                                       .addr_limit = PAGE_OFFSET
+                               }
+                       }
+               };
+
+/**
+ * Each CPU gets its own Task State Segment (TSS) structure. Tasks are
+ * completely 'soft' in the LWK, no more per-task TSS's and hardware task
+ * switching... we switch tasks completely in software. The TSS size is kept
+ * cacheline-aligned so they are allowed to end up in the
+ * .data.cacheline_aligned section. Since TSS's are completely CPU-local, we
+ * want them on exact cacheline boundaries, to eliminate cacheline ping-pong.
+ */
+DEFINE_PER_CPU(struct tss_struct, tss)
+____cacheline_internodealigned_in_smp = BOOTSTRAP_TSS;
+
diff --git a/kitten/arch/x86_64/kernel/interrupts.c b/kitten/arch/x86_64/kernel/interrupts.c
new file mode 100644 (file)
index 0000000..ff55da3
--- /dev/null
@@ -0,0 +1,333 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/kallsyms.h>
+#include <lwk/task.h>
+#include <lwk/sched.h>
+#include <lwk/timer.h>
+#include <lwk/palacios.h>
+#include <arch/desc.h>
+#include <arch/idt_vectors.h>
+#include <arch/show.h>
+#include <arch/xcall.h>
+#include <arch/i387.h>
+#include <arch/io.h>
+
+idtvec_handler_t idtvec_table[NUM_IDT_ENTRIES];
+static DEFINE_SPINLOCK(idtvec_table_lock);
+
+extern void asm_idtvec_table(void);
+
+void
+do_unhandled_idt_vector(struct pt_regs *regs, unsigned int vector)
+{
+       if ((vector >= IRQ0_VECTOR) && (vector <= IRQ15_VECTOR)) {
+               printk(KERN_EMERG
+                      "Unhandled Interrupt! (vector=%u, isa_irq=%u)\n",
+                      vector, vector - IRQ0_VECTOR);
+       } else {
+               printk(KERN_EMERG
+                      "Unhandled Interrupt! (vector=%u)\n", vector);
+       }
+}
+
+void
+do_divide_error(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Divide Error Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_nmi(struct pt_regs *regs, unsigned int vector)
+{
+       printk("NMI Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_int3(struct pt_regs *regs, unsigned int vector)
+{
+       printk("INT3 Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_overflow(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Overflow Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_bounds(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Bounds Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_invalid_op(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Invalid Op Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_device_not_available(struct pt_regs *regs, unsigned int vector)
+{
+       BUG_ON(current->arch.flags & TF_USED_FPU);
+       current->arch.flags |= TF_USED_FPU;
+       clts();
+       fpu_restore_state(current);
+}
+
+void
+do_double_fault(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Double Fault Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_coproc_segment_overrun(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Coprocessor Segment Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_invalid_tss(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Invalid TSS Exception)\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_segment_not_present(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Segment Not Present Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_stack_segment(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Stack Segment Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_general_protection(struct pt_regs *regs, unsigned int vector)
+{
+       printk("General Protection Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_page_fault(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Page Fault Exception (regs %p)\n", regs );
+
+       static uint8_t recursive_fault;
+       if( recursive_fault++ )
+               panic( "Recursive page fault!  Halt and catch fire!" );
+
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_spurious_interrupt_bug(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Spurious Interrupt Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_coprocessor_error(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Coprocessor Error Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_alignment_check(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Alignment Check Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_machine_check(struct pt_regs *regs, unsigned int vector)
+{
+       printk("Machine Check Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_simd_coprocessor_error(struct pt_regs *regs, unsigned int vector)
+{
+       printk("SIMD Coprocessor Error Exception\n");
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_apic_timer(struct pt_regs *regs, unsigned int vector)
+{
+       expire_timers();
+}
+
+void
+do_apic_perf_counter(struct pt_regs *regs, unsigned int vector)
+{
+       printk("APIC Perf. Counter Interrupt, vector=%u\n", vector);
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_apic_thermal(struct pt_regs *regs, unsigned int vector)
+{
+       printk("APIC Thermal Interrupt, vector=%u\n", vector);
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_apic_error(struct pt_regs *regs, unsigned int vector)
+{
+       printk("APIC Error Interrupt, vector=%u\n", vector);
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_apic_spurious(struct pt_regs *regs, unsigned int vector)
+{
+       printk("APIC Spurious Interrupt, vector=%u\n", vector);
+       show_registers(regs);
+       while (1) {}
+}
+
+void
+do_keyboard_interrupt(struct pt_regs *regs, unsigned int vector)
+{
+       const uint8_t KB_OUTPUT_FULL = 0x01;
+       const uint8_t KB_STATUS_PORT = 0x64;
+       const uint8_t KB_DATA_PORT = 0x60;
+
+       uint8_t status = inb( KB_STATUS_PORT );
+
+       if( (status & KB_OUTPUT_FULL) == 0 )
+               return;
+
+       uint8_t key = inb( KB_DATA_PORT );
+#ifdef CONFIG_V3VEE
+       send_key_to_vmm( status, key );
+#endif
+}
+
+
+void
+set_idtvec_handler(unsigned int vector, idtvec_handler_t handler)
+{
+       char namebuf[KSYM_NAME_LEN+1];
+       unsigned long symsize, offset;
+       unsigned long irqstate;
+
+       ASSERT(vector < NUM_IDT_ENTRIES);
+
+       if (handler != &do_unhandled_idt_vector) {
+               printk(KERN_DEBUG "IDT Vector %3u -> %s()\n",
+                       vector, kallsyms_lookup( (unsigned long)handler,
+                                                 &symsize, &offset, namebuf )
+               );
+       }
+
+       spin_lock_irqsave(&idtvec_table_lock, irqstate);
+       idtvec_table[vector] = handler;
+       spin_unlock_irqrestore(&idtvec_table_lock, irqstate);
+}
+
+void
+do_interrupt(struct pt_regs *regs, unsigned int vector)
+{
+       idtvec_table[vector](regs, vector);
+       if (vector >= FIRST_EXTERNAL_VECTOR)
+               lapic_ack_interrupt();
+}
+
+void __init
+interrupts_init(void)
+{
+       int vector;
+
+       /*
+        * Initialize the Interrupt Descriptor Table (IDT).
+        */
+       for (vector = 0; vector < NUM_IDT_ENTRIES; vector++) {
+               void *asm_handler = (void *) (
+                 (uintptr_t)(&asm_idtvec_table) + (vector * 16)
+               );
+               set_intr_gate(vector, asm_handler);
+               set_idtvec_handler(vector, &do_unhandled_idt_vector);
+       }
+
+       /*
+        * Register handlers for the standard x86_64 interrupts & exceptions.
+        */
+       set_idtvec_handler( DIVIDE_ERROR_VECTOR,           &do_divide_error           );
+       set_idtvec_handler( NMI_VECTOR,                    &do_nmi                    );
+       set_idtvec_handler( INT3_VECTOR,                   &do_int3                   );
+       set_idtvec_handler( OVERFLOW_VECTOR,               &do_overflow               );
+       set_idtvec_handler( BOUNDS_VECTOR,                 &do_bounds                 );
+       set_idtvec_handler( INVALID_OP_VECTOR,             &do_invalid_op             );
+       set_idtvec_handler( DEVICE_NOT_AVAILABLE_VECTOR,   &do_device_not_available   );
+       set_idtvec_handler( DOUBLE_FAULT_VECTOR,           &do_double_fault           );
+       set_idtvec_handler( COPROC_SEGMENT_OVERRUN_VECTOR, &do_coproc_segment_overrun );
+       set_idtvec_handler( INVALID_TSS_VECTOR,            &do_invalid_tss            );
+       set_idtvec_handler( SEGMENT_NOT_PRESENT_VECTOR,    &do_segment_not_present    );
+       set_idtvec_handler( STACK_SEGMENT_VECTOR,          &do_stack_segment          );
+       set_idtvec_handler( GENERAL_PROTECTION_VECTOR,     &do_general_protection     );
+       set_idtvec_handler( PAGE_FAULT_VECTOR,             &do_page_fault             );
+       set_idtvec_handler( SPURIOUS_INTERRUPT_BUG_VECTOR, &do_spurious_interrupt_bug );
+       set_idtvec_handler( COPROCESSOR_ERROR_VECTOR,      &do_coprocessor_error      );
+       set_idtvec_handler( ALIGNMENT_CHECK_VECTOR,        &do_alignment_check        );
+       set_idtvec_handler( MACHINE_CHECK_VECTOR,          &do_machine_check          );
+       set_idtvec_handler( SIMD_COPROCESSOR_ERROR_VECTOR, &do_simd_coprocessor_error );
+       set_idtvec_handler( IRQ1_VECTOR, &do_keyboard_interrupt );
+
+       /*
+        * Register handlers for all of the local APIC vectors.
+        */
+       set_idtvec_handler( APIC_TIMER_VECTOR,        &do_apic_timer        );
+       set_idtvec_handler( APIC_PERF_COUNTER_VECTOR, &do_apic_perf_counter );
+       set_idtvec_handler( APIC_THERMAL_VECTOR,      &do_apic_thermal      );
+       set_idtvec_handler( APIC_ERROR_VECTOR,        &do_apic_error        );
+       set_idtvec_handler( APIC_SPURIOUS_VECTOR,     &do_apic_spurious     );
+
+       /*
+        * Register handlers for inter-CPU interrupts (cross calls).
+        */
+       set_idtvec_handler( XCALL_FUNCTION_VECTOR,   &arch_xcall_function_interrupt   );
+       set_idtvec_handler( XCALL_RESCHEDULE_VECTOR, &arch_xcall_reschedule_interrupt );
+}
+
+
diff --git a/kitten/arch/x86_64/kernel/ioapic.c b/kitten/arch/x86_64/kernel/ioapic.c
new file mode 100644 (file)
index 0000000..bf38e20
--- /dev/null
@@ -0,0 +1,355 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/resource.h>
+#include <lwk/bootmem.h>
+#include <lwk/spinlock.h>
+#include <lwk/cpuinfo.h>
+#include <arch/io.h>
+#include <arch/pgtable.h>
+#include <arch/fixmap.h>
+#include <arch/apicdef.h>
+#include <arch/io_apic.h>
+#include <arch/idt_vectors.h>
+
+/**
+ * Lock that protects access to the IO APICs in the system.
+ * There is only one lock for all IO APICs.
+ */
+static DEFINE_SPINLOCK(ioapic_lock);
+
+/**
+ * Number of IO APICs in the system.
+ */
+unsigned int ioapic_num;
+
+/**
+ * Array containing the IDs of the IO APICs in the system.
+ * The array is indexed by ioapic_index.
+ */
+unsigned int ioapic_id[MAX_IO_APICS] = { 1 };
+
+/**
+ * Addresses of the IO APICs in the system.
+ * The array is indexed by ioapic_index.
+ */
+uintptr_t ioapic_phys_addr[MAX_IO_APICS] = { 0xFEC00000 };
+
+/**
+ * Resource entries for the IO APIC memory mapping.
+ */
+static struct resource *ioapic_resources;
+
+/**
+ * Structure used to map IO APIC registers.
+ */
+struct ioapic {
+       uint32_t index;
+       uint32_t unused[3];
+       uint32_t data;
+};
+
+/**
+ * Union used to map an IO APIC routing entry register.
+ */
+union ioapic_entry_union {
+       struct { uint32_t low_word, high_word; };
+       struct IO_APIC_route_entry entry;
+};
+
+/**
+ * Returns the base kernel virtual address of the specified IO APIC's
+ * kernel mapping.
+ */
+static struct ioapic *
+ioapic_base_addr(int ioapic_index)
+{
+       return (void *) __fix_to_virt(FIX_IO_APIC_BASE_0 + ioapic_index)
+                + (ioapic_phys_addr[ioapic_index] & ~PAGE_MASK);
+}
+
+/**
+ * Reads a value from an IO APIC register.
+ */
+static uint32_t
+ioapic_read(unsigned int ioapic_index, uint32_t reg)
+{
+       struct ioapic *ioapic = ioapic_base_addr(ioapic_index);
+       writel(reg, &ioapic->index);
+       return readl(&ioapic->data);
+}
+
+/**
+ * Writes a value to an IO APIC register.
+ */
+static void
+ioapic_write(unsigned int ioapic_index, uint32_t reg, uint32_t value)
+{
+       struct ioapic *ioapic = ioapic_base_addr(ioapic_index);
+       writel(reg, &ioapic->index);
+       writel(value, &ioapic->data);
+}
+
+/**
+ * Reads an IO APIC pin routing entry.
+ */
+static struct IO_APIC_route_entry
+ioapic_read_pin(
+       unsigned int ioapic_index,
+       unsigned int pin
+)
+{
+       union ioapic_entry_union eu;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       eu.low_word  = ioapic_read(ioapic_index, 0x10 + 2 * pin);
+       eu.high_word = ioapic_read(ioapic_index, 0x11 + 2 * pin);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+
+       return eu.entry;
+}
+
+/**
+ * Writes an IO APIC pin routing entry.
+ *
+ * When we write a new IO APIC routing entry, we need to write the high word
+ * first. This is because the mask/enable bit is in the low word and we do not
+ * want to enable the entry before it is fully populated.
+ */
+static void
+ioapic_write_pin(
+       unsigned int               ioapic_index,
+       unsigned int               pin,
+       struct IO_APIC_route_entry pin_config
+)
+{
+       union ioapic_entry_union eu;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioapic_lock, flags);
+       eu.entry = pin_config;
+       ioapic_write(ioapic_index, 0x11 + 2 * pin, eu.high_word);
+       ioapic_write(ioapic_index, 0x10 + 2 * pin, eu.low_word);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+/**
+ * Masks (disables) an IO APIC input pin.
+ */
+static void
+ioapic_mask_pin(
+       unsigned int ioapic_index,
+       unsigned int pin
+)
+{
+       struct IO_APIC_route_entry pin_config =
+                                       ioapic_read_pin(ioapic_index, pin);
+       pin_config.mask = 1;
+       ioapic_write_pin(ioapic_index, pin, pin_config);
+}
+
+/**
+ * Unmasks (enables) an IO APIC input pin.
+ */
+static void
+ioapic_unmask_pin(
+       unsigned int ioapic_index,
+       unsigned int pin
+)
+{
+       struct IO_APIC_route_entry pin_config =
+                                       ioapic_read_pin(ioapic_index, pin);
+       pin_config.mask = 0;
+       ioapic_write_pin(ioapic_index, pin, pin_config);
+}
+
+/**
+ * Returns the number of input pins provided by the specified IO APIC.
+ */
+static unsigned int
+ioapic_get_num_pins(unsigned int ioapic_index)
+{
+       union IO_APIC_reg_01 reg_01;
+
+       reg_01.raw = ioapic_read(ioapic_index, 1);
+       return reg_01.bits.entries + 1;
+}
+
+/**
+ * Initializes the primary IO APIC (the one connected to the ISA IRQs).
+ */
+static void __init
+ioapic_init_primary(
+       unsigned int ioapic_index
+)
+{
+       unsigned int pin;
+       unsigned int num_pins = ioapic_get_num_pins(ioapic_index);
+       struct IO_APIC_route_entry cfg;
+
+       if (num_pins != 24)
+               panic("Expected IOAPIC to have 24 pins, has %u.", num_pins);
+
+       /* Mask (disable) all pins */
+       for (pin = 0; pin < num_pins; pin++) {
+               ioapic_mask_pin(ioapic_index, pin);
+       }
+
+       /*
+        * Configure ISA IRQs.
+        * (Assuming pins [1,15] are the standard ISA IRQs)
+        * (Assuming pin 2 is hooked to the timer interrupt)
+        * (Assuming pin 0 is hooked to the old i8259 PIC... don't use it)
+        */
+       for (pin = 1; pin <= 15; pin++) {
+               cfg = ioapic_read_pin(ioapic_index, pin);
+
+               cfg.delivery_mode = ioapic_fixed;
+               cfg.dest_mode     = ioapic_physical_dest;
+               cfg.polarity      = (pin == 8)
+                                       ? ioapic_active_low
+                                       : ioapic_active_high;
+               cfg.trigger       = ioapic_edge_sensitive;
+               cfg.dest          = (uint8_t) cpu_info[0].physical_id;
+               cfg.vector        = IRQ0_VECTOR + pin;
+
+               ioapic_write_pin(ioapic_index, pin, cfg);
+       }
+
+       /*
+        * Configure PCI IRQs.
+        * (Assuming pins [16,19] are PCI INTA, INTB, INTC, and INTD)
+        */
+       for (pin = 16; pin <= 19; pin++) {
+               cfg = ioapic_read_pin(ioapic_index, pin);
+
+               cfg.delivery_mode = ioapic_fixed;
+               cfg.dest_mode     = ioapic_physical_dest;
+               cfg.polarity      = ioapic_active_low;
+               cfg.trigger       = ioapic_level_sensitive;
+               cfg.dest          = (uint8_t) cpu_info[0].physical_id;
+               cfg.vector        = IRQ0_VECTOR + pin;
+
+               ioapic_write_pin(ioapic_index, pin, cfg);
+       } 
+
+       /* Unmask (enable) all of the pins that have been configured */
+       for (pin = 1; pin < 19; pin++) {
+               ioapic_unmask_pin(ioapic_index, pin);
+       }
+}
+
+/**
+ * Creates a kernel mapping for all IO APICs in the system.
+ */
+void __init
+ioapic_map(void)
+{
+       unsigned int i;
+       const int name_size = 16;
+       char *name;
+
+       if (ioapic_num == 0)
+       {
+               printk( "%s: Faking IO APIC\n", __func__ );
+               ioapic_num = 1;
+       }
+
+       /*
+        * Allocate enough memory for one resource structure per detected IO
+        * APIC in the system. Memory for the resource name strings is tacked
+        * onto the end of the allocation (name_size*ioapic_num bytes).
+        */
+       ioapic_resources = alloc_bootmem(ioapic_num *
+                                        (sizeof(struct resource) + name_size));
+       name = ((char *)ioapic_resources) + ioapic_num*sizeof(struct resource);
+
+       for (i = 0; i < ioapic_num; i++) {
+               /* Reserve the physical memory used by the IO APIC */
+               sprintf(name, "IO APIC %u", i);
+               ioapic_resources[i].name  = name;
+               ioapic_resources[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               ioapic_resources[i].start = ioapic_phys_addr[i];
+               ioapic_resources[i].end   = ioapic_phys_addr[i] + 4096 - 1;
+               request_resource(&iomem_resource, &ioapic_resources[i]);
+               name += name_size;
+
+               /* Map the IO APIC into the kernel */
+               set_fixmap_nocache(FIX_IO_APIC_BASE_0 + i, ioapic_phys_addr[i]);
+
+               printk(KERN_DEBUG
+                      "IO APIC mapped to virtual address 0x%016lx\n",
+                      __fix_to_virt(FIX_IO_APIC_BASE_0 + i)
+               );
+       }
+}
+
+/**
+ * Initializes all IO APICs in the system.
+ */
+void __init
+ioapic_init(void)
+{
+       if (ioapic_num == 0)
+               return;
+
+/* TODO: FIX THIS... NEED TO PARSE MPTABLE OR SOMETHING ELSE */
+#ifdef CONFIG_PC
+       /* TODO: For now, only initializes the first one. */
+       ioapic_init_primary(0);
+       ioapic_dump();
+#endif
+}
+
+/**
+ * Dumps the current state of all IO APICs in the system.
+ */
+void __init
+ioapic_dump(void)
+{
+       unsigned int ioapic_index, pin;
+       union IO_APIC_reg_00 reg_00;
+       union IO_APIC_reg_01 reg_01;
+       union IO_APIC_reg_02 reg_02;
+       struct IO_APIC_route_entry entry;
+       unsigned long flags;
+
+       for (ioapic_index = 0; ioapic_index < ioapic_num; ioapic_index++) {
+
+               spin_lock_irqsave(&ioapic_lock, flags);
+               reg_00.raw = ioapic_read(ioapic_index, 0);
+               reg_01.raw = ioapic_read(ioapic_index, 1);
+               if (reg_01.bits.version >= 0x10)
+                   reg_02.raw = ioapic_read(ioapic_index, 2);
+               spin_unlock_irqrestore(&ioapic_lock, flags);
+
+               printk(KERN_DEBUG "Dump of IO APIC %u (physical id %u):\n",
+                                 ioapic_index, ioapic_id[ioapic_index]);
+               printk(KERN_DEBUG "  register #00: %08X\n", reg_00.raw);
+               printk(KERN_DEBUG "    physical APIC id: %02u\n", reg_00.bits.ID);
+               printk(KERN_DEBUG "  register #01: %08X\n", *(int *)&reg_01);
+               printk(KERN_DEBUG "    max redirection entries: %04X\n", reg_01.bits.entries);
+               printk(KERN_DEBUG "    PRQ implemented: %X\n", reg_01.bits.PRQ);
+               printk(KERN_DEBUG "    IO APIC version: %04X\n", reg_01.bits.version);
+               if (reg_01.bits.version >= 0x10) {
+                       printk(KERN_DEBUG "  register #02: %08X\n", reg_02.raw);
+                       printk(KERN_DEBUG "    arbitration: %02X\n", reg_02.bits.arbitration);
+               }
+
+               printk(KERN_DEBUG "  Interrupt Redirection Table:\n");
+               for (pin = 0; pin <= reg_01.bits.entries; pin++) {
+                       entry = ioapic_read_pin(ioapic_index, pin);
+                       printk(KERN_DEBUG
+                              "    %02u: vector=%u dest=%03u mask=%1d "
+                                        "trigger=%1d irr=%1d polarity=%1d\n",
+                                     pin, entry.vector, entry.dest, entry.mask,
+                                     entry.trigger, entry.irr, entry.polarity);
+                       printk(KERN_DEBUG
+                              "        dest_mode=%1d delivery_mode=%1d "
+                                      "delivery_status=%1d\n",
+                                     entry.dest_mode, entry.delivery_mode,
+                                     entry.delivery_status);
+               }
+       }
+}
+
diff --git a/kitten/arch/x86_64/kernel/lapic.c b/kitten/arch/x86_64/kernel/lapic.c
new file mode 100644 (file)
index 0000000..f10c372
--- /dev/null
@@ -0,0 +1,472 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/resource.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/smp.h>
+#include <lwk/delay.h>
+#include <arch/page.h>
+#include <arch/pgtable.h>
+#include <arch/fixmap.h>
+#include <arch/apicdef.h>
+#include <arch/apic.h>
+#include <arch/idt_vectors.h>
+#include <arch/tsc.h>
+
+/**
+ * Physical address of the local APIC memory mapping.
+ * If the system BIOS provided an MP configuration table, this is set in
+ * arch/x86_64/kernel/mpparse.c to the value parsed from the table.
+ * Otherwise, the default address is used.
+ */
+unsigned long lapic_phys_addr = APIC_DEFAULT_PHYS_BASE;
+
+/**
+ * Resource entry for the local APIC memory mapping.
+ */
+static struct resource lapic_resource = {
+       .name  = "Local APIC",
+       .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
+       /* .start and .end filled in later based on detected address */
+};
+
+/**
+ * Creates a kernel mapping for the local APIC.
+ *
+ * The hardware/platform/BIOS maps each CPU's local APIC at the same location
+ * in physical memory. This function uses the 'fixmap' to map the local APIC
+ * into the kernel's virtual memory space at a fixed virtual address that is
+ * known at compile time. Since the local APIC's virtual address is known
+ * at compile time, local APIC registers can be accessed directly, without
+ * any pointer dereferencing.
+ */
+void __init
+lapic_map(void)
+{
+       if (!cpu_has_apic)
+               panic("No local APIC.");
+
+       /* Reserve physical memory used by the local APIC */
+       lapic_resource.start = lapic_phys_addr;
+       lapic_resource.end   = lapic_phys_addr + 4096 - 1;
+       request_resource(&iomem_resource, &lapic_resource);
+
+       /* Map local APIC into the kernel */ 
+       set_fixmap_nocache(FIX_APIC_BASE, lapic_phys_addr);
+
+       printk(KERN_DEBUG "Local APIC mapped to virtual address 0x%016lx\n",
+                         fix_to_virt(FIX_APIC_BASE));
+}
+
+/**
+ * Initializes the calling CPU's local APIC.
+ */
+void __init
+lapic_init(void)
+{
+       uint32_t val;
+
+       /*
+        * Initialize Destination Format Register.
+        * When using logical destination mode, we want to use the flat model.
+        */
+       apic_write(APIC_DFR, APIC_DFR_FLAT);
+
+       /*
+        * Initialize the Logical Destination Register.
+        * The LWK never uses logical destination mode, so just set it to the
+        * APIC's physical ID to avoid possible confusion.
+        */
+       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+       val |= SET_APIC_LOGICAL_ID( GET_APIC_ID(apic_read(APIC_ID)) );
+       apic_write(APIC_LDR, val);
+
+       /*
+        * Initialize the Task Priority Register.
+        * We set this to accept all (0) and never touch it again.
+        */
+       val = apic_read(APIC_TASKPRI) & ~APIC_TPRI_MASK;
+       apic_write(APIC_TASKPRI, val);
+
+       /*
+        * Intialize the Spurious-Interrupt Vector Register.
+        * This also enables the local APIC.
+        */
+       val = apic_read(APIC_SPIV) & ~APIC_VECTOR_MASK;
+       val |= (APIC_SPIV_APIC_ENABLED | APIC_SPURIOUS_VECTOR);
+       apic_write(APIC_SPIV, val);
+
+       /* Setup LVT[0] = APIC Timer Interrupt */
+       apic_write(APIC_LVTT, 0
+                    | APIC_DM_FIXED       /* route to fixed IDT vector */
+                    | APIC_TIMER_VECTOR   /* IDT vector to route to */
+                    | APIC_LVT_MASKED     /* initially disable */
+       );
+
+       /* Setup LVT[1] = Thermal Sensor Interrupt */
+       apic_write(APIC_LVTTHMR, 0
+                    | APIC_DM_FIXED       /* route to fixed IDT vector */     
+                    | APIC_THERMAL_VECTOR /* IDT vector to route to */
+       );
+
+       /* Setup LVT[2] = Performance Counter Interrupt */
+       apic_write(APIC_LVTPC, 0
+                    | APIC_DM_NMI         /* treat as non-maskable interrupt */
+                                          /* NMIs are routed to IDT vector 2 */
+                    | APIC_LVT_MASKED     /* initially disable */
+       );
+
+       /* Setup LVT[3] = Local Interrupt Pin 0 */
+       apic_write(APIC_LVT0, 0
+                    | APIC_DM_EXTINT      /* hooked up to old 8259A PIC   */
+                                          /* IDT vector provided by 8259A */
+                    | APIC_LVT_MASKED     /* disable */
+       );
+
+       /* Setup LVT[4] = Local Interrupt Pin 1 */
+       apic_write(APIC_LVT1, 0
+                    | APIC_DM_NMI         /* treat as non-maskable interrupt */
+                                          /* NMIs are routed to IDT vector 2 */
+                    | ((this_cpu != 0)
+                        ? APIC_LVT_MASKED /* mask on all but bootstrap CPU */
+                        : 0)              /* bootstrap CPU (0) receives NMIs */
+       );
+
+       /* Setup LVT[5] = Internal APIC Error Detector Interrupt */
+       apic_write(APIC_LVTERR, 0
+                    | APIC_DM_FIXED       /* route to fixed IDT vector */
+                    | APIC_ERROR_VECTOR   /* IDT vector to route to */
+       );
+       apic_write(APIC_ESR, 0); /* spec says to clear after enabling LVTERR */
+}
+
+void 
+lapic_set_timer(uint32_t count)
+{
+       uint32_t lvt;
+
+       /* Setup Divide Count Register to use the bus frequency directly. */
+       apic_write(APIC_TDCR, APIC_TDR_DIV_1);
+
+       /* Program the initial count register */
+       apic_write(APIC_TMICT, count);
+
+       /* Enable the local APIC timer */
+       lvt = apic_read(APIC_LVTT);
+       lvt &= ~APIC_LVT_MASKED;
+       lvt |= APIC_LVT_TIMER_PERIODIC;
+       apic_write(APIC_LVTT, lvt);
+}
+
+void
+lapic_stop_timer(void)
+{
+       uint32_t lvt;
+
+       /* Set the initial count to 0 */
+       apic_write(APIC_TMICT, 0);
+
+       /* Enable the local APIC timer */
+       lvt = apic_read(APIC_LVTT);
+       lvt |= APIC_LVT_MASKED;
+       apic_write(APIC_LVTT, lvt);
+}
+
+/**
+ * Detects the local APIC reference bus clock. The only sure-fire way to do
+ * this is to depend on some other absolute timing source. This function uses
+ * the CPU's cycle counter and the previously detected CPU clock frequency.
+ *
+ * NOTE: This assumes that the CPU's clock frequency has already been detected.
+ *       (i.e., cpu_info[cpu_id()].arch.tsc_khz has been initialized.
+ */
+unsigned int __init
+lapic_calibrate_timer(void)
+{
+       const unsigned int tick_count = 100000000;
+       cycles_t tsc_start, tsc_now;
+       uint32_t apic_start, apic_now;
+       unsigned int apic_Hz;
+
+       /* Start the APIC counter running for calibration */
+       lapic_set_timer(4000000000);
+
+       apic_start = apic_read(APIC_TMCCT);
+       tsc_start  = get_cycles_sync();
+
+       /* Spin until enough ticks for a meaningful result have elapsed */
+       do {
+               apic_now = apic_read(APIC_TMCCT);
+               tsc_now  = get_cycles_sync();
+       } while ( ((tsc_now    - tsc_start) < tick_count) &&
+                 ((apic_start - apic_now)  < tick_count) );
+
+       apic_Hz = (apic_start - apic_now) * 1000L *
+                 cpu_info[this_cpu].arch.tsc_khz / (tsc_now - tsc_start);
+
+       lapic_stop_timer();
+
+       return (apic_Hz / 1000);
+}
+
+static uint32_t
+lapic_wait4_icr_idle(void)
+{
+       uint32_t send_status;
+       int timeout;
+
+       /* Wait up to 100 milliseconds */
+       timeout = 0;
+       do {
+               send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+               if (!send_status)
+                       break;
+               udelay(100);
+       } while (timeout++ < 1000);
+
+       return send_status;
+}
+
+/**
+ * Returns the number of entries in the Local Vector Table minus one.
+ * 
+ * This should return 5 or higher on all x86_64 CPUs.
+ * 6 is returned if the APIC Thermal Interrupt is supported, 5 otherwise.
+ */
+static uint32_t
+lapic_get_maxlvt(void)
+{
+       return GET_APIC_MAXLVT(apic_read(APIC_LVR));
+}
+
+/**
+ * Sends an INIT inter-processor interrupt.
+ * This is used during bootstrap to wakeup the AP CPUs.
+ */
+void __init
+lapic_send_init_ipi(unsigned int cpu)
+{
+       uint32_t status;
+       unsigned int apic_id = cpu_info[cpu].arch.apic_id;
+
+       /* Turn on INIT at target CPU */
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
+       apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+                               | APIC_DM_INIT);
+       status = lapic_wait4_icr_idle();
+       if (status)
+               panic("INIT IPI ERROR: failed to assert INIT. (%x)", status);
+       mdelay(10);
+
+       /* Turn off INIT at target CPU */
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
+       apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+       status = lapic_wait4_icr_idle();
+       if (status)
+               panic("INIT IPI ERROR: failed to deassert INIT. (%x)", status);
+}
+
+/**
+ * Send a STARTUP inter-processor interrupt.
+ * This is used during bootstrap to wakeup the AP CPUs.
+ */
+void __init
+lapic_send_startup_ipi(
+       unsigned int    cpu,            /* Logical CPU ID */
+       unsigned long   start_rip       /* Physical addr  */
+)
+{
+       uint32_t status;
+       unsigned int maxlvt  = lapic_get_maxlvt();
+       unsigned int apic_id = cpu_info[cpu].arch.apic_id;
+
+       /* Clear errors */
+       apic_write(APIC_ESR, 0);
+       apic_read(APIC_ESR);
+
+       /* Set target CPU */
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
+
+       /* Send Startup IPI to target CPU */
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
+       apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12));
+       udelay(300);  /* Give AP CPU some time to accept the IPI */
+       status = lapic_wait4_icr_idle();
+       if (status)
+               panic("STARTUP IPI ERROR: failed to send. (%x)", status);
+       udelay(300);  /* Give AP CPU some time to accept the IPI */
+
+       /* Fixup for Pentium erratum 3AP, clear errors */
+       if (maxlvt > 3)
+               apic_write(APIC_ESR, 0);
+
+       /* Verify that IPI was accepted */
+       status = (apic_read(APIC_ESR) & 0xEF);
+       if (status)
+               panic("STARTUP IPI ERROR: failed to accept. (%x)", status);
+}
+
+/**
+ * Sends an inter-processor interrupt (IPI) to the specified CPU.
+ * Note that the IPI has not necessarily been delivered when this function
+ * returns.
+ */
+void
+lapic_send_ipi(
+       unsigned int    cpu,            /* Logical CPU ID */
+       unsigned int    vector          /* Interrupt vector to send */
+)
+{
+       uint32_t status;
+       unsigned int apic_id;
+
+       /* Wait for idle */
+       status = lapic_wait4_icr_idle();
+       if (status)
+               panic("lapic_wait4_icr_idle() timed out. (%x)", status);
+
+       /* Set target CPU */
+       apic_id = cpu_info[cpu].arch.apic_id;
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
+
+       /* Send the IPI */
+       if (unlikely(vector == NMI_VECTOR))
+               apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_NMI);
+       else
+               apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_FIXED|vector);
+}
+
+/**
+ * Converts an entry in a local APIC's Local Vector Table to a
+ * human-readable string.
+ */
+static char *
+lvt_stringify(uint32_t entry, char *buf)
+{
+       uint32_t delivery_mode = GET_APIC_DELIVERY_MODE(entry);
+
+       if (delivery_mode == APIC_MODE_FIXED) {
+               sprintf(buf, "FIXED -> IDT_VECTOR %d",
+                       entry & APIC_VECTOR_MASK
+               );
+       } else if (delivery_mode == APIC_MODE_NMI) {
+               sprintf(buf, "NMI   -> IDT VECTOR 2"); 
+       } else if (delivery_mode == APIC_MODE_EXTINT) {
+               sprintf(buf, "ExtINT, hooked to old 8259A PIC");
+       } else {
+               sprintf(buf, "UNKNOWN");
+       }
+
+       if (entry & APIC_LVT_MASKED)
+               strcat(buf, ", MASKED");
+
+       return buf;
+}
+
+/**
+ * Prints various local APIC registers of interest to the console.
+ */
+void
+lapic_dump(void)
+{
+       char buf[128];
+
+       printk(KERN_DEBUG "LOCAL APIC DUMP (LOGICAL CPU #%d):\n", this_cpu);
+
+       /*
+        * Lead off with the important stuff...
+        */
+       printk(KERN_DEBUG
+               "  ID:  0x%08x (id=%d)\n",
+               apic_read(APIC_ID),
+               GET_APIC_ID(apic_read(APIC_ID))
+       );
+       printk(KERN_DEBUG
+               "  VER: 0x%08x (version=0x%x, max_lvt=%d)\n",
+               apic_read(APIC_LVR),
+               GET_APIC_VERSION(apic_read(APIC_LVR)),
+               GET_APIC_MAXLVT(apic_read(APIC_LVR))
+       );
+       printk(KERN_DEBUG
+               "  ESR: 0x%08x (Error Status Reg, non-zero is bad)\n",
+               apic_read(APIC_ESR)
+       );
+       printk(KERN_DEBUG
+               "  SVR: 0x%08x (Spurious vector=%d, %s)\n",
+               apic_read(APIC_SPIV),
+               apic_read(APIC_SPIV) & APIC_VECTOR_MASK,
+               (apic_read(APIC_SPIV) & APIC_SPIV_APIC_ENABLED)
+                       ? "APIC IS ENABLED"
+                       : "APIC IS DISABLED"
+       );
+
+       /*
+        * Local Vector Table
+        */
+       printk(KERN_DEBUG "  Local Vector Table Entries:\n");
+       printk(KERN_DEBUG "      LVT[0] Timer:     0x%08x (%s)\n",
+               apic_read(APIC_LVTT),
+               lvt_stringify(apic_read(APIC_LVTT), buf)
+       );
+       printk(KERN_DEBUG "      LVT[1] Thermal:   0x%08x (%s)\n",
+               apic_read(APIC_LVTTHMR),
+               lvt_stringify(apic_read(APIC_LVTTHMR), buf)
+       );
+       printk(KERN_DEBUG "      LVT[2] Perf Cnt:  0x%08x (%s)\n",
+               apic_read(APIC_LVTPC),
+               lvt_stringify(apic_read(APIC_LVTPC), buf)
+       );
+       printk(KERN_DEBUG "      LVT[3] LINT0 Pin: 0x%08x (%s)\n",
+               apic_read(APIC_LVT0),
+               lvt_stringify(apic_read(APIC_LVT0), buf)
+       );
+       printk(KERN_DEBUG "      LVT[4] LINT1 Pin: 0x%08x (%s)\n",
+               apic_read(APIC_LVT1),
+               lvt_stringify(apic_read(APIC_LVT1), buf)
+       );
+       printk(KERN_DEBUG "      LVT[5] Error:     0x%08x (%s)\n",
+               apic_read(APIC_LVTERR),
+               lvt_stringify(apic_read(APIC_LVTERR), buf)
+       );
+
+       /*
+        * APIC timer configuration registers
+        */
+       printk(KERN_DEBUG "  Local APIC Timer:\n");
+       printk(KERN_DEBUG "      DCR (Divide Config Reg): 0x%08x\n",
+               apic_read(APIC_TDCR)
+       );
+       printk(KERN_DEBUG "      ICT (Initial Count Reg): 0x%08x\n",
+               apic_read(APIC_TMICT)
+       );
+       printk(KERN_DEBUG "      CCT (Current Count Reg): 0x%08x\n",
+               apic_read(APIC_TMCCT)
+       );
+
+       /*
+        * Logical APIC addressing mode registers
+        */
+       printk(KERN_DEBUG "  Logical Addressing Mode Information:\n");
+       printk(KERN_DEBUG "      LDR (Logical Dest Reg):  0x%08x (id=%d)\n",
+               apic_read(APIC_LDR),
+               GET_APIC_LOGICAL_ID(apic_read(APIC_LDR))
+       );
+       printk(KERN_DEBUG "      DFR (Dest Format Reg):   0x%08x (%s)\n",
+               apic_read(APIC_DFR),
+               (apic_read(APIC_DFR) == APIC_DFR_FLAT) ? "FLAT" : "CLUSTER"
+       );
+
+       /*
+        * Task/processor/arbitration priority registers
+        */
+       printk(KERN_DEBUG "  Task/Processor/Arbitration Priorities:\n");
+       printk(KERN_DEBUG "      TPR (Task Priority Reg):        0x%08x\n",
+               apic_read(APIC_TASKPRI)
+       );
+       printk(KERN_DEBUG "      PPR (Processor Priority Reg):   0x%08x\n",
+               apic_read(APIC_PROCPRI)
+       );
+       printk(KERN_DEBUG "      APR (Arbitration Priority Reg): 0x%08x\n",
+               apic_read(APIC_ARBPRI)
+       );
+}
+
diff --git a/kitten/arch/x86_64/kernel/mpboot.c b/kitten/arch/x86_64/kernel/mpboot.c
new file mode 100644 (file)
index 0000000..16aaee6
--- /dev/null
@@ -0,0 +1,87 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/smp.h>
+#include <lwk/delay.h>
+#include <lwk/bootmem.h>
+#include <lwk/task.h>
+#include <lwk/sched.h>
+#include <arch/atomic.h>
+#include <arch/apicdef.h>
+#include <arch/apic.h>
+#include <arch/desc.h>
+
+/**
+ * MP boot trampoline 80x86 program as an array.
+ */
+extern unsigned char trampoline_data[];
+extern unsigned char trampoline_end[];
+
+/**
+ * These specify the initial stack pointer and instruction pointer for a
+ * newly booted CPU.
+ */
+extern volatile unsigned long init_rsp;
+extern void (*initial_code)(void);
+
+void __init
+start_secondary(void)
+{
+       cpu_init();
+       cpu_set(this_cpu, cpu_online_map);
+       schedule(); /* runs idle_task, since that's the only task
+                    * on the CPU's run queue at this point */
+}
+
+void __init
+arch_boot_cpu(unsigned int cpu)
+{
+       union task_union *new_task_union;
+       struct task_struct *new_task;
+
+       /*
+        * Setup the 'trampoline' cpu boot code. The trampoline contains the
+        * first code executed by the CPU being booted. x86 CPUs boot in
+        * pre-historic 16-bit 'real mode'... the trampoline does the messy
+        * work to get us to 64-bit long mode and then calls the *initial_code
+        * kernel entry function.
+        */
+       memcpy(__va(SMP_TRAMPOLINE_BASE), trampoline_data,
+                                         trampoline_end - trampoline_data
+       );
+
+       /*
+        * Allocate memory for the new CPU's GDT.
+        */
+       cpu_gdt_descr[cpu].address = (unsigned long) kmem_get_pages(0);
+
+       /*
+        * Allocate memory for the new CPU's bootstrap task.
+        */
+       new_task_union = kmem_get_pages(TASK_ORDER);
+       new_task = &new_task_union->task_info;
+
+       /*
+        * Initialize the bare minimum info needed to bootstrap the new CPU.
+        */
+       new_task->id      = 0;
+       new_task->aspace  = &bootstrap_aspace;
+       new_task->cpu_id  = cpu;
+       strcpy(new_task->name, "bootstrap");
+       list_head_init(&new_task->sched_link);
+
+       /*
+        * Set the initial kernel entry point and stack pointer for the new CPU.
+        */
+       initial_code = start_secondary;
+       init_rsp     = (unsigned long)new_task_union
+                                         + sizeof(union task_union) - 1;
+
+       /*
+        * Boot it!
+        */
+       lapic_send_init_ipi(cpu);
+       lapic_send_startup_ipi(cpu, SMP_TRAMPOLINE_BASE);
+       lapic_send_startup_ipi(cpu, SMP_TRAMPOLINE_BASE);
+}
+
diff --git a/kitten/arch/x86_64/kernel/mpparse.c b/kitten/arch/x86_64/kernel/mpparse.c
new file mode 100644 (file)
index 0000000..10495c6
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ *     Intel Multiprocessor Specification 1.1 and 1.4
+ *     compliant MP-table parsing routines.
+ *
+ *     (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *     (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ *     Fixes
+ *             Erich Boleyn    :       MP v1.4 and additional changes.
+ *             Alan Cox        :       Added EBDA scanning
+ *             Ingo Molnar     :       various cleanups and rewrites
+ *             Maciej W. Rozycki:      Bits for default MP configurations
+ *             Paul Diefenbaugh:       Added full ACPI support
+ */
+
+#include <lwk/smp.h>
+#include <lwk/init.h>
+#include <lwk/bootmem.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/params.h>
+#include <arch/io.h>
+#include <arch/mpspec.h>
+#include <arch/proto.h>
+#include <arch/io_apic.h>
+
+/**
+ * Points to the MP table, once and if it is found.
+ * This gets initialized by find_mp_table().
+ */
+static struct intel_mp_floating *mpf_found;
+
+/**
+ * Physical CPU ID of the bootstrap CPU (the BP).
+ */
+unsigned int __initdata boot_phys_cpu_id = -1U;
+
+/**
+ * The number of CPUs in the system.
+ */
+unsigned int __initdata num_cpus = 0;
+
+/**
+ * Map of all CPUs present.
+ * Bits set represent physical CPU IDs present.
+ */
+physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE;
+
+/**
+ * Version information for every Local APIC in the system.
+ * The array is indexed by APIC ID.
+ */
+unsigned char apic_version[MAX_APICS];
+
+/**
+ * MP Bus information
+ */
+static int    mp_current_pci_id = 0;
+unsigned char mp_bus_id_to_type    [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
+int           mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
+
+/**
+ * MP IO APIC information
+ */
+int nr_ioapics = 0;
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+
+/**
+ * MP IRQ information
+ */
+int mp_irq_entries = 0;
+struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+
+/* TODO: move these */
+int pic_mode;
+
+/**
+ * Computes the checksum of an MP configuration block.
+ */
+static int __init
+mpf_checksum(unsigned char *mp, int len)
+{
+       int sum = 0;
+       while (len--)
+               sum += *mp++;
+       return sum & 0xFF;
+}
+
+/**
+ * Parses an MP table CPU entry.
+ */
+static void __init
+MP_processor_info(struct mpc_config_processor *m)
+{
+       int cpu;
+       int is_bp;
+       unsigned char ver;
+       cpumask_t tmp_map;
+
+       if (!(m->mpc_cpuflag & CPU_ENABLED))
+               panic("A disabled CPU was encountered\n");
+
+       /* Count the new CPU */
+       if (++num_cpus > NR_CPUS)
+               panic("NR_CPUS limit of %i reached.\n", NR_CPUS);
+
+       /*
+        * Determine if this is the bootstrap processor...
+        * the one responsible for booting the other CPUs.
+        */
+       is_bp = (m->mpc_cpuflag & CPU_BOOTPROCESSOR);
+
+       /*
+        * Assign a logical CPU ID.
+        * The bootstrap CPU is always assigned logical ID 0.
+        * All other CPUs are assigned the lowest ID available.
+        */
+       if (is_bp) {
+               cpu = 0;
+       } else {
+               cpus_complement(tmp_map, cpu_present_map);
+               cpu = first_cpu(tmp_map);
+       }
+
+       /* Validate APIC version, fixing up if necessary. */
+       ver = m->mpc_apicver;
+       if (ver == 0x0) {
+               printk(KERN_ERR "BIOS bug, APIC version is 0 for PhysCPU#%d! "
+                               "fixing up to 0x10. (tell your hw vendor)\n",
+                               m->mpc_apicid);
+               ver = 0x10;
+       }
+
+       /* Remember the APIC's version */
+       apic_version[m->mpc_apicid] = ver;
+
+       /* Add the CPU to the map of physical CPU IDs present. */
+       physid_set(m->mpc_apicid, phys_cpu_present_map);
+
+       /* Remember the physical CPU ID of the bootstrap CPU. */
+       if (is_bp)
+               boot_phys_cpu_id = m->mpc_apicid;
+
+       /* Add the CPU to the map of logical CPU IDs present. */
+       cpu_set(cpu, cpu_present_map);
+
+       /* Store ID information. */
+       cpu_info[cpu].logical_id   = cpu;
+       cpu_info[cpu].physical_id  = m->mpc_apicid;
+       cpu_info[cpu].arch.apic_id = m->mpc_apicid;
+
+       printk(KERN_DEBUG
+         "Physical CPU #%d -> Logical CPU #%d, %d:%d APIC version %d%s\n",
+               m->mpc_apicid,
+               cpu,
+              (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
+              (m->mpc_cpufeature & CPU_MODEL_MASK)  >> 4,
+               ver,
+               is_bp ? " (Bootstrap CPU)" : "");
+}
+
+/**
+ * Parses an MP table BUS entry.
+ */
+static void __init
+MP_bus_info(struct mpc_config_bus *m)
+{
+       char str[7];
+
+       memcpy(str, m->mpc_bustype, 6);
+       str[6] = 0;
+       printk(KERN_DEBUG "Bus #%d is %s\n", m->mpc_busid, str);
+
+       if (strncmp(str, "ISA", 3) == 0) {
+               mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
+       } else if (strncmp(str, "EISA", 4) == 0) {
+               mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
+       } else if (strncmp(str, "PCI", 3) == 0) {
+               mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
+               mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
+               mp_current_pci_id++;
+       } else if (strncmp(str, "MCA", 3) == 0) {
+               mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
+       } else {
+               printk(KERN_ERR "Unknown bustype %s\n", str);
+       }
+}
+
+/**
+ * Parses an MP table BUS entry.
+ */
+static void __init
+MP_ioapic_info(struct mpc_config_ioapic *m)
+{
+       if (!(m->mpc_flags & MPC_APIC_USABLE)) {
+               printk(KERN_DEBUG "Encountered unusable APIC, ignoring it.\n");
+               return;
+       }
+
+       printk(KERN_DEBUG "I/O APIC #%d Version %d at 0x%X\n",
+               m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
+       if (nr_ioapics >= MAX_IO_APICS) {
+               printk(KERN_ERR "Max # of I/O APICs (%d) exceeded (found %d).\n",
+                       MAX_IO_APICS, nr_ioapics);
+               panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
+       }
+       if (!m->mpc_apicaddr) {
+               printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
+                       " found in MP table, skipping!\n");
+               return;
+       }
+       mp_ioapics[nr_ioapics] = *m;
+       nr_ioapics++;
+
+       ioapic_id[ioapic_num]        = m->mpc_apicid;
+       ioapic_phys_addr[ioapic_num] = m->mpc_apicaddr;
+       ioapic_num++;
+}
+
+/**
+ * Parses an MP table IRQ source entry.
+ */
+static void __init
+MP_intsrc_info(struct mpc_config_intsrc *m)
+{
+       mp_irqs [mp_irq_entries] = *m;
+       printk(KERN_DEBUG
+               "Int: type %d, pol %d, trig %d, bus %d,"
+               " IRQ %02x, APIC ID %x, APIC INT %02x\n",
+                       m->mpc_irqtype, m->mpc_irqflag & 3,
+                       (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
+                       m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
+       if (++mp_irq_entries >= MAX_IRQ_SOURCES)
+               panic("Max # of irq sources exceeded!!\n");
+}
+
+/**
+ * Parses an MP table LINT entry.
+ */
+static void __init
+MP_lintsrc_info (struct mpc_config_lintsrc *m)
+{
+       printk(KERN_DEBUG
+               "Lint: type %d, pol %d, trig %d, bus %d,"
+               " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
+                       m->mpc_irqtype, m->mpc_irqflag & 3,
+                       (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
+                       m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
+       /*
+        * Well it seems all SMP boards in existence
+        * use ExtINT/LVT1 == LINT0 and
+        * NMI/LVT2 == LINT1 - the following check
+        * will show us if this assumptions is false.
+        * Until then we do not have to add baggage.
+        */
+       if ((m->mpc_irqtype == mp_ExtINT) &&
+               (m->mpc_destapiclint != 0))
+                       BUG();
+       if ((m->mpc_irqtype == mp_NMI) &&
+               (m->mpc_destapiclint != 1))
+                       BUG();
+}
+
+/**
+ * Parses the input MP table, storing various bits of information in global
+ * variables as it goes.
+ */
+static int __init
+read_mpc(struct mp_config_table *mpc)
+{
+       char str[16];
+       int count=sizeof(*mpc);
+       unsigned char *mpt=((unsigned char *)mpc)+count;
+
+       if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) {
+               printk(KERN_ERR "SMP mptable: bad signature [%c%c%c%c]!\n",
+                       mpc->mpc_signature[0],
+                       mpc->mpc_signature[1],
+                       mpc->mpc_signature[2],
+                       mpc->mpc_signature[3]);
+               return -1;
+       }
+       if (mpf_checksum((unsigned char *)mpc, mpc->mpc_length)) {
+               printk(KERN_ERR "SMP mptable: checksum error!\n");
+               return -1;
+       }
+       if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
+               printk(KERN_ERR "SMP mptable: bad table version (%d)!\n",
+                       mpc->mpc_spec);
+               return -1;
+       }
+       if (!mpc->mpc_lapic) {
+               printk(KERN_ERR "SMP mptable: null local APIC address!\n");
+               return -1;
+       }
+       memcpy(str, mpc->mpc_oem, 8);
+       str[8]=0;
+       printk(KERN_DEBUG "    OEM ID: %s\n", str);
+
+       memcpy(str, mpc->mpc_productid, 12);
+       str[12]=0;
+       printk(KERN_DEBUG "    Product ID: %s\n", str);
+
+       printk(KERN_DEBUG "    APIC at: 0x%X\n", mpc->mpc_lapic);
+
+       /* Save the local APIC address, it might be non-default. */
+       lapic_phys_addr = mpc->mpc_lapic;
+
+       /* Now process all of the configuration blocks in the table. */
+       while (count < mpc->mpc_length) {
+               switch(*mpt) {
+                       case MP_PROCESSOR:
+                       {
+                               struct mpc_config_processor *m=
+                                       (struct mpc_config_processor *)mpt;
+                               MP_processor_info(m);
+                               mpt += sizeof(*m);
+                               count += sizeof(*m);
+                               break;
+                       }
+                       case MP_BUS:
+                       {
+                               struct mpc_config_bus *m=
+                                       (struct mpc_config_bus *)mpt;
+                               MP_bus_info(m);
+                               mpt += sizeof(*m);
+                               count += sizeof(*m);
+                               break;
+                       }
+                       case MP_IOAPIC:
+                       {
+                               struct mpc_config_ioapic *m=
+                                       (struct mpc_config_ioapic *)mpt;
+                               MP_ioapic_info(m);
+                               mpt+=sizeof(*m);
+                               count+=sizeof(*m);
+                               break;
+                       }
+                       case MP_INTSRC:
+                       {
+                               struct mpc_config_intsrc *m=
+                                       (struct mpc_config_intsrc *)mpt;
+
+                               MP_intsrc_info(m);
+                               mpt+=sizeof(*m);
+                               count+=sizeof(*m);
+                               break;
+                       }
+                       case MP_LINTSRC:
+                       {
+                               struct mpc_config_lintsrc *m=
+                                       (struct mpc_config_lintsrc *)mpt;
+                               MP_lintsrc_info(m);
+                               mpt+=sizeof(*m);
+                               count+=sizeof(*m);
+                               break;
+                       }
+               }
+       }
+       //clustered_apic_check();
+       if (!num_cpus)
+               printk(KERN_ERR "SMP mptable: no CPUs registered!\n");
+       return 0;
+}
+
+/**
+ * Determines the multiprocessor configuration.
+ * The configuration information is stored in global variables so nothing is
+ * returned.  find_mp_config() must be called before this function.
+ */
+void __init
+get_mp_config(void)
+{
+       struct intel_mp_floating *mpf = mpf_found;
+       if (!mpf) {
+               printk(KERN_WARNING "Assuming 1 CPU.\n");
+               num_cpus = 1;
+               /* Assign the only CPU logical=physical ID 0 */
+               cpu_set(0, cpu_present_map);
+               physid_set(0, phys_cpu_present_map);
+               cpu_info[0].logical_id   = 0;
+               cpu_info[0].physical_id  = 0;
+               cpu_info[0].arch.apic_id = 0;
+               return;
+       }
+
+       printk(KERN_DEBUG "Intel MultiProcessor Specification v1.%d\n",
+              mpf->mpf_specification);
+       if (mpf->mpf_feature2 & (1<<7)) {
+               printk(KERN_DEBUG "    IMCR and PIC compatibility mode.\n");
+               pic_mode = 1;
+       } else {
+               printk(KERN_DEBUG "    Virtual Wire compatibility mode.\n");
+               pic_mode = 0;
+       }
+
+       /*
+        * We don't support the default MP configuration.
+        * All supported multi-CPU systems must provide a full MP table.
+        */
+       if (mpf->mpf_feature1 != 0)
+               BUG();
+       if (!mpf->mpf_physptr)
+               BUG();
+
+       /*
+        * Set this early so we don't allocate CPU0 if the
+        * MADT list doesn't list the bootstrap processor first.
+        * The bootstrap processor has to be logical ID 0... which
+        * we are reserving here.
+        */
+       cpu_set(0, cpu_present_map);
+
+       /*
+        * Parse the MP configuration
+        */
+       if (read_mpc(phys_to_virt(mpf->mpf_physptr)))
+               panic("BIOS bug, MP table errors detected! (tell your hw vendor)\n");
+}
+
+/**
+ * Scans a region of memory for the MP table.
+ */
+static int __init
+scan(unsigned long base, unsigned long length)
+{
+       unsigned int *bp = phys_to_virt(base);
+       struct intel_mp_floating *mpf;
+
+       printk(KERN_DEBUG "Scan for MP table from 0x%p for %ld bytes\n",
+                         bp, length);
+
+       while (length > 0) {
+               mpf = (struct intel_mp_floating *)bp;
+               if ((*bp == SMP_MAGIC_IDENT) &&
+                       (mpf->mpf_length == 1) &&
+                       !mpf_checksum((unsigned char *)bp, 16) &&
+                       ((mpf->mpf_specification == 1)
+                               || (mpf->mpf_specification == 4)) ) {
+
+                       reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
+                       if (mpf->mpf_physptr)
+                               reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE);
+                       mpf_found = mpf;
+                       printk(KERN_DEBUG "Found MP table at:     0x%p\n", mpf);
+                       return 1;
+               }
+               bp += 4;
+               length -= 16;
+       }
+       return 0;
+}
+
+/**
+ * Locates the MP table, if there is one.
+ * This does not parse the MP table... get_mp_config() does that.
+ */
+void __init
+find_mp_config(void)
+{
+       /* 
+        * 1) Scan the bottom 1K for a signature
+        * 2) Scan the top 1K of base RAM
+        * 3) Scan the 64K of bios
+        */
+       if (scan(0x0,0x400) ||
+               scan(639*0x400,0x400) ||
+                       scan(0xF0000,0x10000))
+               return;
+
+       /*
+        * If it is an MP machine we should know now.
+        *
+        * If not, make a final effort and scan the
+        * Extended BIOS Data Area. 
+        *
+        * NOTE! There are Linux loaders that will corrupt the EBDA
+        * area, and as such this kind of MP config may be less
+        * trustworthy, simply because the MP table may have been
+        * stomped on during early boot. These loaders are buggy and
+        * should be fixed.
+        */
+       if (scan(ebda_addr, 0x1000)) {
+               printk(KERN_WARNING "MP table found in EBDA\n");
+               return;
+       }
+
+       /* If we have come this far, we did not find an MP table */
+       printk(KERN_DEBUG "No MP table found.\n");
+}
+
diff --git a/kitten/arch/x86_64/kernel/percpu.c b/kitten/arch/x86_64/kernel/percpu.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/kitten/arch/x86_64/kernel/rca/Makefile b/kitten/arch/x86_64/kernel/rca/Makefile
new file mode 100644 (file)
index 0000000..21f9fe2
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_CRAY_XT) += l0rca.o
diff --git a/kitten/arch/x86_64/kernel/rca/l0rca.c b/kitten/arch/x86_64/kernel/rca/l0rca.c
new file mode 100644 (file)
index 0000000..7bf61b1
--- /dev/null
@@ -0,0 +1,1258 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ */
+/*
+ *   RCA: Interface between CRAY RCA and linux kernel
+ *
+ * Copyright (c) 2003 Cray 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.
+ *
+ *
+ */
+/*
+ * This code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+
+#include <lwk/kernel.h>
+#include <lwk/string.h>
+#include <lwk/errno.h>
+#include <lwk/delay.h>
+#include <lwk/version.h>
+#include <rca/rca_l0_linux.h>
+#include <rca/rca_l0.h>
+extern void    set_debug_traps(void) ;         /* GDB routine */
+
+#if defined(CONFIG_CRAY_RS_DEBUG)
+#define assert(expr) \
+if(!(expr)) {                                   \
+       printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+              #expr,__FILE__,__FUNCTION__,__LINE__);          \
+}
+#else
+#define assert(expr)
+#endif /* CONFIG_CRAY_RS_DEBUG */
+
+/* States for up channel. Used for calling the tx_done callback only if reqd */
+#define        CHAN_TX_STATE_AVAIL     (0)
+#define        CHAN_TX_STATE_FULL      (1)
+#define GET_CHAN_STATE(x)      ((x)->state)
+#define SET_CHAN_STATE(x, s)   ((x)->state = (s))
+
+typedef struct l0rca_mapped_ch {
+       uint32_t num_obj;        /* number of objects    */
+       uint32_t intr_bit;
+       volatile uint32_t *ch_ridx;             /* Pointer to ridx */
+       volatile uint32_t *ch_widx;             /* Pointer to widx */
+       rs_event_t              *ch_buf_ptr;    /* Pointer to channel buffer */
+       l0rca_down_handle_t     down_handler;
+       l0rca_up_handle_t       up_handler;
+       uint32_t                reg_count;
+       int                     poll;           /* timeout */
+       int                     tshhld;         /* timeout */
+       int                     state;          /* outgoing chan full or not */
+} l0rca_mapped_ch_t;
+
+#define L0RCA_INITVAL   (0xAA55F00D)
+
+typedef struct l0rca_mapped_config {
+       uint32_t        version;        /* config version */
+       rs_node_t       proc_id;        /* node id */
+       int32_t         proc_num;       /* cpu number (0-3) */
+       l0rca_mapped_ch_t       ch_data[NUM_L0RCA_CHANNELS];
+       volatile uint32_t       *l0rca_l0_intr_ptr;     /* interrupt to L0 */
+        uint32_t        initialized;
+} l0rca_mapped_config_t;
+
+/* Our copy with virt addrs; so we can directly access the config area */
+l0rca_mapped_config_t l0rca_early_cfg = {0};
+
+/* Pointer to the actual config struct in Seastar RAM shared memory */
+l0rca_config_t *l0rca_cfg = NULL;
+
+/* Store the size of the event header without the msg body */
+uint32_t rs_ev_hdr_sz;
+
+
+void send_intr_to_l0(l0rca_mapped_ch_t *ch)
+{
+       volatile uint32_t *addr = &(((l0rca_intr_t *)(l0rca_early_cfg.l0rca_l0_intr_ptr))->l0r_intr_set);
+       SSPUT32(addr, (ch)->intr_bit);
+}
+
+/* 
+ * Function:   l0rca_event_data
+ * 
+ * Description: Return a pointer to the data portion and length of the
+ *             data portion of the event.
+ *             NB: Reflect any changes to l0rca_event_data in gdb_l0rca_event_data
+ * 
+ * Arguments: rs_event_t *evp IN: Event whose data is of interest
+ *           void **data OUT: Upon return will point to data portion of event
+ *           int32_t *len OUT: Upon return will have the length of the data
+ *                             portion of the event
+ *
+ * Returns: No Return Value.
+ * Note: The main purpose of this routine is to read in the data portion of the
+ * event from Seastar memory. 
+ */
+void l0rca_event_data(rs_event_t *evp, void **data, int32_t *len)
+{
+        /* Get length and data portion from the event */
+        *len = evp->ev_len;
+        *data = &evp->ev_data;
+} /* l0rca_event_data */
+
+/* 
+ * Function:   l0rca_get_proc_id
+ * 
+ * Description: Return the node/processor id.
+ * 
+ * Arguments: None
+ *
+ * Returns: The proc id.
+ */
+rs_node_t l0rca_get_proc_id(void)
+{
+       return l0rca_cfg->proc_id;
+}
+
+/* 
+ * Function:   l0rca_get_proc_num
+ * 
+ * Description: Returns this processor's CPU number, 0-3.
+ * 
+ * Arguments: None.
+ * 
+ * Returns: The CPU number of this node.
+ */
+int l0rca_get_proc_num(void)
+{
+    int tmp;
+    SSGET32(&(l0rca_cfg->proc_num),tmp);
+    return(tmp);
+}
+
+/*
+ * Function:   set_chan_tx_state
+ *
+ * Description:        Looks at the read and write indices to determine if the
+ *             channel is full or not. Sets state accordingly.
+ *             NB: Reflect any changes to set_chan_tx_state in gdb_set_chan_tx_state.
+ *
+ * Arguments: l0rca_mapped_ch_t *ch_ptr IN: Pointer to channel being set.
+ *
+ * Returns: None
+ */
+static inline void set_chan_tx_state(l0rca_mapped_ch_t *ch_ptr)
+{
+       volatile uint32_t wx, rx;
+       int not_full;
+       SSGET32(ch_ptr->ch_widx, wx);
+       SSGET32(ch_ptr->ch_ridx, rx);
+       not_full = (wx - rx) < ch_ptr->num_obj;
+       SET_CHAN_STATE(ch_ptr, not_full  ? CHAN_TX_STATE_AVAIL : CHAN_TX_STATE_FULL);
+}
+
+
+/*
+ * Function:   l0rca_init_config
+ *
+ * Description: Read L0 - RCA communication config structure and populate 
+ *              our personal copy. If there is any error, the OS panics
+ *              since not being able to communicate with L0 is a total disaster.
+ *              If already initialized then returns silently.
+ *
+ * Arguments: None.
+ *
+ * Returns: None
+ */
+
+void l0rca_init_config(void)
+{
+       rs_event_t *ev_buf;
+       int i;
+       volatile uint64_t tmp64;
+       volatile uint32_t tmp32;
+
+       /* 
+        * Check if already initialized; No locking is needed as this 
+        * is called during the boot process from within the kernel (as 
+        * opposed from a driver)
+        */
+       if (L0RCA_INITVAL == l0rca_early_cfg.initialized)
+               return;
+
+       l0rca_cfg = (l0rca_config_t *)rca_l0_comm_va(L0_SIC_RAM);
+
+       /* TODO - first order of business is to check the Version Number */
+       /* Also, should we panic if version mismatch? */
+#ifdef CONFIG_CRAY_RS_DEBUG
+       printk ("l0 config at virtual %p\n", l0rca_cfg);
+       printk ("Phys event bufs 0x%llx intr reg 0x%llx\n",
+               l0rca_cfg->l0rca_buf_addr,
+               l0rca_cfg->l0rca_l0_intr_addr);
+#endif /* CONFIG_CRAY_RS_DEBUG */
+
+       /* convert event buffer address from physical to virtual */
+       SSGET64(&(l0rca_cfg->l0rca_buf_addr),tmp64);
+       ev_buf = (rs_event_t *)rca_l0_comm_va(tmp64);
+
+       /* convert intr reg address from physical to virtual */
+       SSGET64(&(l0rca_cfg->l0rca_l0_intr_addr), tmp64);
+       l0rca_early_cfg.l0rca_l0_intr_ptr = (uint32_t *)rca_l0_comm_va(tmp64);
+
+#ifdef CONFIG_CRAY_RS_DEBUG
+        printk ("event bufs %p intr reg %p\n", ev_buf,
+                l0rca_early_cfg.l0rca_l0_intr_ptr);
+#endif /* CONFIG_CRAY_RS_DEBUG */
+
+       /* Now setup the channel buffers */
+       for (i = 0; i < NUM_L0RCA_CHANNELS; i++)
+       {
+               int num_obj; 
+               SSGET32(&(l0rca_cfg->chnl_data[i].num_obj), tmp32);
+               num_obj = tmp32;
+
+               /* Skip if channel is unused */
+               if (!num_obj)
+                       continue;
+
+               /* Ensure num_obj is a power of 2 */
+               if (num_obj & (num_obj - 1))
+               {
+#if 0
+                       panic ("l0rca_init_config: num_obj[%u] for channel %d is not power of 2\n",
+                              num_obj, i);
+#endif
+               }
+               l0rca_early_cfg.ch_data[i].num_obj = num_obj;
+               SSGET32(&(l0rca_cfg->chnl_data[i].l0_intr_bit), tmp32);
+               l0rca_early_cfg.ch_data[i].intr_bit = tmp32;
+
+               /* Point to the read/writew index */
+               l0rca_early_cfg.ch_data[i].ch_ridx = &l0rca_cfg->chnl_data[i].ridx;
+               l0rca_early_cfg.ch_data[i].ch_widx = &l0rca_cfg->chnl_data[i].widx;
+               l0rca_early_cfg.ch_data[i].ch_buf_ptr = ev_buf;
+
+               ev_buf += num_obj;
+
+#ifdef CONFIG_CRAY_RS_DEBUG
+               printk ("Buffer %p for channel %d rd %u wr %u\n", 
+                       l0rca_early_cfg.ch_data[i].ch_buf_ptr, i,
+                       l0rca_cfg->chnl_data[i].ridx,
+                       l0rca_cfg->chnl_data[i].widx);
+#endif /* CONFIG_CRAY_RS_DEBUG */
+       }       /* End of for */
+
+       /* Set the remaining fields */
+       SSGET32(&(l0rca_cfg->version), l0rca_early_cfg.version);
+       SSGET32(&(l0rca_cfg->proc_id), l0rca_early_cfg.proc_id);
+       SSGET32(&(l0rca_cfg->proc_num), l0rca_early_cfg.proc_num);
+
+       /* Assumes ev_data is the last element TODO: this should be
+         * defined via a macro in the rs_event_t structure definition */
+       rs_ev_hdr_sz = offsetof(rs_event_t, ev_data);
+
+       /* Indicate we have a initialized the mapped copy */
+       l0rca_early_cfg.initialized = L0RCA_INITVAL;
+
+        return;
+}
+
+/* 
+ * Function:   register_ch_up
+ * 
+ * Description: Register function for the upload channel. It is expected that
+ * there be at most one registered user for an upload channel. This user 
+ * provides a callback to be invoked when the buffer drains below tshhld
+ * (only if the buffer became full last time the tshhld was crossed)
+ * 
+ * Arguments: int ch_num IN: channel number to register on
+ *           l0rca_up_handle_t handler IN: callback routine
+ *            int tshhld IN: buffer to drain before invoking callback; ignored
+ *                          if poll is negative.
+ *           int poll IN: if > zero - duration in ms to check for buffer drain
+ *                        if = zero - tx done interrupt invokes callback (TODO)
+ *                        if < zero - do nothing. It is assumed that the user (TODO)
+ *                        has her own means to check for buffer drain
+ *
+ * Returns: -EBUSY - If another user is already registered.
+ *          -EINVAL - if ch_num is not in range.
+ *          zero (SUCCESS) otherwise.
+ *
+ * Note: It is expected that the buffer is empty upon call to this routine. 
+ *      This should be true on system startup and after an unregister call.
+ *
+ * Note: As of 12/1/04, the polling is forced, and is hard coded in 
+ *   l0rca_linux.c.  Thus, the tshhld and poll params have no meaning.
+ */
+int
+register_ch_up(int ch_num, l0rca_up_handle_t handler, int tshhld, int poll)
+{
+        volatile uint32_t wx, rx;
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+
+       if (NUM_L0RCA_CHANNELS <= ch_num)
+               return -EINVAL;
+
+       /* Allow only one user per channel */
+       if (ch_ptr->reg_count)
+               return -EBUSY;
+
+        SSGET32(ch_ptr->ch_widx, wx);
+        SSGET32(ch_ptr->ch_ridx, rx);
+       assert(wx == rx);
+
+       SET_CHAN_STATE(ch_ptr, CHAN_TX_STATE_AVAIL);
+       ch_ptr->down_handler = NULL;    /* Clear the down handler */
+       ch_ptr->reg_count++;
+       ch_ptr->poll = poll;
+       ch_ptr->up_handler = handler;
+       ch_ptr->tshhld = tshhld;
+
+       return 0;
+}
+
+/* 
+ * Function:   register_ch_down
+ * 
+ * Description: Register function for the download channel. It is expected that
+ * there be at most one registered user for a download channel. This user 
+ * provides a callback to be invoked when data from L0 arrives on the channel.
+ * 
+ * Arguments: int ch_num IN: channel number to register on
+ *           l0rca_down_handle_t handler IN: callback routine
+ *           int poll IN: if > zero - duration in ms to check for event
+ *                        if = zero - event arrival is interrupt driven.
+ *                        if < zero - do nothing. It is assumed that the user
+ *                        has her own means to check for event arrival.
+ *
+ * Returns: EBUSY - If another user is already registered.
+ *          zero (SUCCESS) otherwise.
+ * 
+ * Note: As of 12/1/04, the polling is forced, and is hard coded in 
+ *   l0rca_linux.c.  Thus, the poll parameter has no meaning.
+ */
+int register_ch_down(int ch_num, l0rca_down_handle_t handler, int poll)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+
+       if (NUM_L0RCA_CHANNELS <= ch_num)
+               return -EINVAL;
+
+       /* Allow only one user per channel */
+       if (ch_ptr->reg_count)
+               return -EBUSY;
+
+       ch_ptr->reg_count++;
+       ch_ptr->down_handler = handler;
+       ch_ptr->poll = poll;
+
+#if 0
+       /* Do any OS specific initialization e.g. set irq, timers etc. */
+       if (l0rca_os_init())
+       {
+               panic ("Unable to initialize OS service for L0RCA interface\n");
+       }
+#endif
+
+       return 0;
+}
+
+#ifdef CONFIG_CRAY_RS_DEBUG
+uint32_t l0rca_buf_full;
+#endif /* CONFIG_CRAY_RS_DEBUG */
+/* 
+ * Function:   ch_send_data
+ * 
+ * Description: Sends data towards the L0. 
+ * The data that buf points to is sent as the payload in an rs_event structure.
+ * The header is a separate parameter and the send routine directly copies
+ * the header and the data into the circular buffer, thus avoiding a copy.
+ *
+ * NB: Reflect any changes to ch_send_data in gdb_ch_send_data
+ * 
+ * Arguments: int ch_num IN: channel number on which to send data
+ *           rs_event_t *ev_hdr  IN: Header without len & timestamp
+ *           void* buf  IN: Buffer with data
+ *           int len    IN: length of data to transfer
+ *
+ * Returns: -EINVAL - if no user registered on the channel (Debug only)
+ *          -EFAULT - if buf or ev_hdr is NULL (Debug only)
+ *          -E2BIG -  if len exceeds max event payload (RS_MSG_LEN) (Debug only)
+ *          zero -    SUCCESS, all bytes sent.
+ *          > 0 -     Bytes not sent. Sender should retry.
+ *
+ * Notes: data in buf will be copied to the channel buffer, therfore, upon
+ *       return, user can free the buf. buf may not be NULL and the len must
+ *       not be zero. Use ch_send_event to send events with zero length data
+ *       portion.
+ */
+
+int ch_send_data(int ch_num, const rs_event_t *ev_hdr, 
+                void* buf, unsigned int len)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+       uint32_t ev_len = 0;
+       volatile uint32_t tmpwx, tmprx;
+
+#ifdef CONFIG_CRAY_RS_DEBUG
+       uint32_t wr, rd, no_events;
+       if ((NULL == ev_hdr) || (NULL == buf))
+       {
+               return -EFAULT;
+       }
+
+       if ((NUM_L0RCA_CHANNELS <= ch_num) || (0 == len) ||
+           (L0RCA_INITVAL != l0rca_early_cfg.initialized) ||
+           (0 == ch_ptr->reg_count))
+       {
+               return -EINVAL;
+       }
+
+       /* Normalize the write & read indexes */
+        SSGET32(ch_ptr->ch_widx, tmpwx);
+       wr = tmpwx & (ch_ptr->num_obj - 1);
+        SSGET32(ch_ptr->ch_ridx, tmprx);
+       rd = tmprx & (ch_ptr->num_obj - 1);
+
+
+       /* Calculate the number of events we will be sending */
+       no_events = (len + RS_MSG_LEN -1)/RS_MSG_LEN;
+       if ((wr + (no_events) - rd) < ch_ptr->num_obj)
+       {
+            l0rca_buf_full++;
+       }
+
+#endif /* CONFIG_CRAY_RS_DEBUG */
+
+       /* Optimize for buf not full and only one event needed to send */
+
+       /* 
+        * Masking of indexes is not needed for the check in while() below.
+        * Both widx & ridx are unsigned and increase monotonically such that
+        * ridx cannot lag behind widx by more than the circular buf size i.e.
+        * num_obj. widx will overflow before ridx.
+        * 'widx - ridx' will always yield the difference between the two 
+        * even if widx has overflowed and ridx has not yet overflowed.
+        */
+       SSGET32(ch_ptr->ch_widx, tmpwx);
+       SSGET32(ch_ptr->ch_ridx, tmprx);
+       while ((tmpwx - tmprx) < ch_ptr->num_obj)
+       {
+               rs_event_t *wr_ev_ptr = 
+                 &ch_ptr->ch_buf_ptr[tmpwx & (ch_ptr->num_obj - 1)];
+
+               /* Copy same header for each event */
+               SSMEMPUT(wr_ev_ptr, (uint32_t*) ev_hdr, rs_ev_hdr_sz);
+
+               /* Copy the data portion over */
+               ev_len = (RS_MSG_LEN > len) ? len : RS_MSG_LEN;
+               SSPUT32(&(wr_ev_ptr->ev_len), ev_len);
+               SSMEMPUT((char*)wr_ev_ptr + rs_ev_hdr_sz, buf, RS_MSG_LEN);
+
+               /* TODO: Set the timestamp in each event */
+#if 0
+               SSPUT32(wr_ev_ptr->_ev_stp, 0x0);
+#endif  /* 0 */
+               len -= ev_len;
+               /* 
+                * After updating the widx, DO NOT access any field in that 
+                * event. Though not desirable, the reader is free to alter 
+                * fields in the event.
+                */
+               SSGET32(ch_ptr->ch_widx, tmpwx);
+               SSPUT32(ch_ptr->ch_widx, tmpwx + 1);
+               set_chan_tx_state(ch_ptr);
+
+               /* Let L0 know an ev is available */
+                send_intr_to_l0(ch_ptr);
+
+               if (0 == len)
+                       break;
+
+               buf = (void *)(((char *)buf) + RS_MSG_LEN);
+
+               SSGET32(ch_ptr->ch_widx, tmpwx);
+               SSGET32(ch_ptr->ch_ridx, tmprx);
+       }       /* End of while */
+       return len;     /* bytes remaining, if any */
+}
+
+/* 
+ * Function:   ch_send_event
+ * 
+ * Description: Sends an event to L0. An event with zero length data portion
+ *             is supported.
+ * 
+ * Arguments: int ch_num IN: channel number on which to send the event
+ *           const rs_event_t *evp  IN: EVent to send
+ *
+ * Returns: -EINVAL - if no user registered on the channel (Debug only)
+ *          -EFAULT - if evp is NULL (Debug only)
+ *          zero -    SUCCESS, event sent.
+ *          +EBUSY -  Event not sent. Sender should retry.
+ *
+ * Notes: The event will be copied to the channel buffer, therfore, upon
+ *       return, user may free the space associated with the event
+ */
+int ch_send_event(int ch_num, const rs_event_t *evp)
+{
+       int ret = 0;
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+        volatile uint32_t tmpwx, tmprx;
+
+#ifdef CONFIG_CRAY_RS_DEBUG
+       if (NULL == evp)
+       {
+               return -EFAULT;
+       }
+
+       if ((NUM_L0RCA_CHANNELS <= ch_num) ||
+           (L0RCA_INITVAL != l0rca_early_cfg.initialized) ||
+           (0 == ch_ptr->reg_count))
+       {
+               return -EINVAL;
+       }
+#endif /* CONFIG_CRAY_RS_DEBUG */
+
+       /* Optimize for circular buffer not full */
+
+       /* 
+        * Masking of indexes is not needed for the check in while() below.
+        * Both widx & ridx are unsigned and increase monotonically such that
+        * ridx cannot lag behind widx by more than the circular buf size i.e.
+        * num_obj. widx will overflow before ridx.
+        * 'widx - ridx' will always yield the difference between the two 
+        * even if widx has overflowed and ridx has not yet overflowed.
+        */
+       SSGET32(ch_ptr->ch_widx,tmpwx);
+       SSGET32(ch_ptr->ch_ridx,tmprx);
+       if((tmpwx - tmprx) < ch_ptr->num_obj)
+       {
+               rs_event_t *wr_ev_ptr = 
+                 &ch_ptr->ch_buf_ptr[tmpwx & (ch_ptr->num_obj - 1)];
+
+               /* Copy header & data length for the event */
+               SSMEMPUT(wr_ev_ptr, (uint32_t*)evp, rs_ev_hdr_sz + evp->ev_len);
+
+               SSGET32(ch_ptr->ch_widx, tmpwx);
+               SSPUT32(ch_ptr->ch_widx, tmpwx + 1);
+               set_chan_tx_state(ch_ptr);
+
+               /* Let L0 know an ev is available */
+                send_intr_to_l0(ch_ptr);
+       } else
+       {
+               ret = EBUSY;
+       }
+
+       return ret;
+}
+
+/* 
+ * Function:   l0rca_ch_get_event
+ * 
+ * Description: Read an event from L0 (if any). If an event is availabe then 
+ *             the read pointer is advanced.
+ *             NB: Reflect any changes to l0rca_ch_get_event in gdb_l0rca_ch_get_event
+ * 
+ * Arguments: int ch_num IN: channel number from which to read the event
+ *           rs_event_t *evp  IN: Buffer to place the event
+ *
+ * Returns: -EINVAL - if no user registered on the channel (Debug only)
+ *          -EFAULT - if evp is NULL (Debug only)
+ *          zero -    no event to receive at this time
+ *          > 0 -     Event received
+ *
+ */
+int l0rca_ch_get_event(int ch_num, rs_event_t *evp)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+       int ret = 0;
+       uint32_t nbytes;
+       volatile uint32_t tmpwx, tmprx;
+
+#ifdef CONFIG_CRAY_RS_DEBUG
+       if (NULL == evp)
+               return -EFAULT;
+
+       if ((NUM_L0RCA_CHANNELS <= ch_num) ||
+           (L0RCA_INITVAL != l0rca_early_cfg.initialized) ||
+           (0 == ch_ptr->reg_count))
+               return -EINVAL;
+#endif /* CONFIG_CRAY_RS_DEBUG */
+
+       SSGET32(ch_ptr->ch_widx,tmpwx);
+       SSGET32(ch_ptr->ch_ridx,tmprx);
+       if(tmpwx != tmprx)
+       {
+               rs_event_t *wr_ev_ptr = 
+                 &ch_ptr->ch_buf_ptr[tmprx & (ch_ptr->num_obj - 1)];
+
+               /* Copy over the event */
+               SSGET32(&(wr_ev_ptr->ev_len), nbytes);
+               SSMEMGET(evp, (uint32_t*)wr_ev_ptr, nbytes + rs_ev_hdr_sz);
+
+               /* Update the rd index */
+               SSGET32(ch_ptr->ch_ridx, tmprx);
+               SSPUT32(ch_ptr->ch_ridx, tmprx + 1);
+
+               /* Let L0 know that the  event has been drained */
+               send_intr_to_l0(ch_ptr);
+
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/* 
+ * Function:   unregister_ch_down
+ * 
+ * Description: Unregister function for the upload channel. Use to indicate
+ * that the channel is no longer to be used. The read & write pointers are 
+ * equalized to make the circ buffer empty.
+ * 
+ * Arguments: int ch_num IN: channel number to unregister
+ *
+ * Returns: -EINVAL - if ch_num is not correct or no user registered
+ *          zero (SUCCESS)
+ */
+int unregister_ch_down(int ch_num)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+       volatile uint32_t tmpwx;
+
+       if (NUM_L0RCA_CHANNELS <= ch_num)
+               return -EINVAL;
+
+       /* Check if user is using this channel */
+       if (!ch_ptr->reg_count)
+               return -EINVAL;
+
+       ch_ptr->down_handler = NULL;
+       ch_ptr->reg_count--;
+
+       /* Equalize the read & write pointers i.e. drain the circ buffer */
+       /* NOTE: We cannot really stop the L0 from sending data */
+       SSGET32(ch_ptr->ch_widx, tmpwx);
+       SSPUT32(ch_ptr->ch_ridx, tmpwx);
+
+       return 0;
+}
+
+/* 
+ * Function:   unregister_ch_up
+ * 
+ * Description: Unregister function for the download channel. Use to indicate
+ * that the channel is no longer to be used.
+ * 
+ * Arguments: int ch_num IN: channel number to unregister
+ *
+ * Returns: -EINVAL - if ch_num is not correct or no user registered
+ *          zero (SUCCESS)
+ */
+int unregister_ch_up(int ch_num)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+       volatile uint32_t tmpwx, tmprx;
+
+       if (NUM_L0RCA_CHANNELS <= ch_num)
+               return -EINVAL;
+
+       /* Check if user is using this channel */
+       if (!ch_ptr->reg_count)
+               return -EINVAL;
+
+       /* Wait for events to be drained by the L0 */
+       SSGET32(ch_ptr->ch_widx,tmpwx);
+       SSGET32(ch_ptr->ch_ridx,tmprx);
+       while(tmpwx != tmprx)
+       {
+               udelay(1000);
+               SSGET32(ch_ptr->ch_widx,tmpwx);
+               SSGET32(ch_ptr->ch_ridx,tmprx);
+       }
+
+       ch_ptr->up_handler = NULL;
+       ch_ptr->reg_count--;
+
+       return 0;
+}
+
+/* TODO: If we decide to use the PKT_MODE register to indicate the channels
+ * that need attention then use PKT_MODE instead of looking at each channel.
+ * TODO: Currently the rx_done callback is invoked for each event in the 
+ * incoming channel. Change this to be called with all the pending events.
+ * Note that since the channel is a circular buffer and the pending events
+ * wrap around, then the callback needs to be invoked twice - once with events
+ * upto the "end" of the circular buffer and then with events starting from the
+ * "start" of the circular buffer.
+ * TODO: To prevent thrashing of the tx_done callback in case the circular
+ * buffer is being operated under almost full condition, obey the threshold
+ * specified at the registration. The tx_done callback is only called once the
+ * circular buffer occupancy is below the specified threshold.
+ */
+/* 
+ * Function:   l0rca_poll_callback
+ * 
+ * Description: Scan the incoming channels and call the receive callback
+ *             (if any) in case an event is pending to be processed.
+ *             Update the read pointer. Next scan the outgoing channels
+ *             and if the channel was full, call the transmit done callback
+ *             so that events may be sent.
+ * 
+ * Arguments: None
+ *
+ * Returns: 0 if no events were processed, else 1.
+ *
+ * Note: It is possible that this routine is called from interrupt
+ *      context. The callbacks invoked *must* not block.
+ */
+
+int l0rca_poll_callback(void)
+{
+       int i;
+       int rval = 0;
+       rs_event_t ev, *wr_ev_ptr;
+       volatile uint32_t tmpwx, tmprx;
+
+       /* Loop through all channels with incoming events */
+       for (i = 1; i < NUM_L0RCA_CHANNELS; i+=2)
+       {
+               l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[i];
+
+               /* GDB handled separately.
+                */
+               if (i == L0RCA_CH_KGDB_DOWN) 
+                   continue;
+
+               if ((0 == ch_ptr->reg_count) || (NULL == ch_ptr->down_handler))
+                       continue;
+               
+               if ((ch_ptr->ch_ridx == 0) || (ch_ptr->ch_widx == 0)) {
+                   continue;
+               }
+
+               if (!ch_ptr->num_obj) {
+                   SSGET32(ch_ptr->ch_widx, tmpwx);
+                   SSGET32(ch_ptr->ch_ridx, tmprx);
+                   continue;
+               }
+
+               SSGET32(ch_ptr->ch_widx, tmpwx);
+               SSGET32(ch_ptr->ch_ridx, tmprx);
+               if (tmpwx != tmprx)
+               {
+                       wr_ev_ptr = (rs_event_t*)&ch_ptr->ch_buf_ptr[tmprx & (ch_ptr->num_obj - 1)];
+                       /* read the entire event */
+                       SSMEMGET((uint32_t*)&ev, (uint32_t*)wr_ev_ptr, rs_sizeof_event(RS_MSG_LEN));
+
+                       /* Call callback routine with one event */
+                       (ch_ptr->down_handler)(i, &ev, 1);
+
+                       /* We are done with this event */
+                       rval++;
+                       SSGET32(ch_ptr->ch_ridx, tmprx);
+                       SSPUT32(ch_ptr->ch_ridx, tmprx + 1);
+
+                       /* Let L0 know that the  event has been drained */
+                       send_intr_to_l0(ch_ptr);
+               } /* End of if */
+       } /* End of for incoming channels */
+
+       /* Loop through all channels with outgoing events */
+       for (i = 0; i < NUM_L0RCA_CHANNELS; i+=2)
+       {
+               l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[i];
+
+               /* GDB handled separately.
+                */
+               if (i == L0RCA_CH_KGDB_UP)
+                       continue;
+
+               if(NULL != ch_ptr->up_handler)
+               {
+                       /* Lock needed for mutex with tx routine */
+                       LOCK_CHANNEL(i);
+                       if (CHAN_TX_STATE_FULL == GET_CHAN_STATE(ch_ptr))
+                       {
+                               /* Call the callback if chan no longer full */
+                               assert(0 != ch_ptr->reg_count);
+                               SSGET32(ch_ptr->ch_widx, tmpwx);
+                               SSGET32(ch_ptr->ch_ridx, tmprx);
+                               if((tmpwx - tmprx) < ch_ptr->num_obj)
+                               {
+                                       rval++;
+                                       SET_CHAN_STATE(ch_ptr,CHAN_TX_STATE_AVAIL);
+                                       UNLOCK_CHANNEL(i);
+                                       (ch_ptr->up_handler)(i);
+                                       LOCK_CHANNEL(i);
+                               }
+                       } /* End of if */
+                       UNLOCK_CHANNEL(i);
+               }
+       } /* End of for */
+
+       return rval;
+}
+
+#if defined(CONFIG_CRAY_XT_KGDB) || defined(CONFIG_CRAY_KGDB)
+/* Kernel mode GDB via L0 interface routines.
+ *
+ * Note that this code was derived from gdbl0.c,
+ * which was derived from Linux gdbserial.c,
+ * which contains no copyright notice.  Parts
+ * of this may need to be rewritten if a GPL
+ * copyright notice was removed from gdbserial.c
+ *
+ */
+
+#define LRPRINTF  printk
+
+#undef PRNT                            /* define for debug printing */
+
+#define        GDB_BUF_SIZE    512             /* power of 2, please */
+
+static char    gdb_buf[GDB_BUF_SIZE] ;
+static int     gdb_buf_in_inx ;
+static int     gdb_buf_in_cnt ;
+static int     gdb_buf_out_inx ;
+
+static int initialized = -1;
+
+int gdb_store_overflow;
+int gdb_read_error;
+
+/* Preset this with constant fields in the event header */
+static rs_event_t l0rca_gdb_ev_template = {0};
+
+/*
+ * Function:    rcal0_gdb_template
+ *
+ * Description: Hand craft a event header to be sent with each outgoing event
+ *
+ * Arguments: None.
+ *
+ * Returns: None
+ *
+ * Note: The len & timestamp are not filled in.
+ */
+static void rcal0_gdb_template(void)
+{
+       l0rca_gdb_ev_template.ev_id = ec_kgdb_output;
+       l0rca_gdb_ev_template.ev_gen = RCA_MKSVC(RCA_INST_ANY,
+           RCA_SVCTYPE_TEST0, l0rca_get_proc_id());
+       l0rca_gdb_ev_template.ev_src = l0rca_gdb_ev_template.ev_gen;
+       l0rca_gdb_ev_template.ev_priority = RCA_LOG_DEBUG;
+       l0rca_gdb_ev_template.ev_flag = 0;      /* For Debugging */
+
+       /* Timestamp, len & data is filled at the time of sending event */
+}
+
+/*
+ * Function:    l0_gdb_init
+ *
+ * Description: Take steps to set things up for early_printk output
+ *
+ * Arguments: struct console *console IN: pointer to console struct
+ *            char *input IN: Not used
+ *
+ * Returns: zero (SUCCESS)
+ */
+int l0_gdb_init(void)
+{
+
+       int ret;
+
+       /* RCA already initialized on Q
+        */
+       /* Read the configuration information provided by L0 */
+       l0rca_init_config();
+
+       /* Setup the Event template to use for outgoing events */
+       rcal0_gdb_template();
+
+       /* Set up channel internal state by calling
+        * registration routines.
+        */
+
+       /* Register with the KGDB out channel to send gdb data */
+       ret = register_ch_up (L0RCA_CH_KGDB_UP, NULL, 0, 0);
+
+       if (!ret)
+       {
+               /* Register with the KGDB in channel to receive gdb commands */
+               ret = register_ch_down(L0RCA_CH_KGDB_DOWN, NULL, 0);
+       }
+       
+       return ret;
+}
+
+extern void breakpoint(void);
+
+
+int gdb_hook(void)
+{
+       int retval;
+
+       /*
+        * Call GDB routine to setup the exception vectors for the debugger.
+        */
+       
+       /* Setup both kgdb channels */
+       retval = l0_gdb_init();
+
+       /* TODO: on Linux the call to printk in this
+        * routine no longer generate output.
+        *
+        * Did something change in the setup of the
+        * console channel?
+        */
+       if (retval == 0)
+       {
+               initialized = 1;
+       } else
+       {
+               initialized = 0;
+               LRPRINTF("gdb_hook: l0_gdb_init() failed: %d\n", retval);
+               return (-1);
+       }
+       return 0;
+
+} /* gdb_hook */
+
+/*
+ * Function:   l0rca_kgdb_down_getc()
+ * 
+ * Description:        Checks for an event on the KGDB DOWN L0 channel
+ *             and returns the first character, other characters
+ *              are thrown away.  Used to detect control C for
+ *              breakpointing the kernel.  Returns 0 when no
+ *             input is available or on error where gdb_read_error
+ *             is incremented.
+ */
+int l0rca_kgdb_down_getc(void)
+{
+       char    *chp;
+       int ret, len;
+       rs_event_t ev = {0};
+
+       if ((ret = l0rca_ch_get_event(L0RCA_CH_KGDB_DOWN, &ev)) <= 0) {
+               if (ret < 0)
+                    gdb_read_error++;
+               return 0;
+       }
+       l0rca_event_data(&ev, (void *)&chp, &len);
+       if (len > 0)
+               return *chp;
+       return 0;
+} /* l0rca_kgdb_down_getc */
+
+/* Only routines used by the Kernel trap mode KGDB interface
+ * should follow this point.
+ *
+ * These functions should only call other `gdb_.*' functions.
+ *
+ * This is best done by examining the assembly file and
+ * ensuring that all assembly call statements only call
+ * routines that match `gdb_.*', in all of the routines
+ * that follow.
+ *
+ * NB: SETTING BREAKPOINTS IN THE FOLLOWING ROUTINES MAY
+ * BREAK THE KERNEL DEBUGGER.
+ */
+
+/* 
+ * Function:   gdb_l0rca_event_data
+ * 
+ * Description:        Clone of l0rca_event_data to only be called by kernel GDB.
+ *             data portion of the event.
+ * 
+ * Arguments: rs_event_t *evp IN: Event whose data is of interest
+ *           void **data OUT: Upon return will point to data portion of event
+ *           int32_t *len OUT: Upon return will have the length of the data
+ *                             portion of the event
+ *
+ * Returns: No Return Value.
+ */
+void gdb_l0rca_event_data(rs_event_t *evp, void **data, int32_t *len)
+{
+        /* Get length and data portion from the event */
+        *len = evp->ev_len;
+        *data = &evp->ev_data;
+} /* gdb_l0rca_event_data */
+
+/*
+ * Function:   gdb_set_chan_tx_state
+ *
+ * Description:        Clone of set_chan_tx_state to only be called by kernel GDB.
+ */
+static inline void gdb_set_chan_tx_state(l0rca_mapped_ch_t *ch_ptr)
+{
+
+       int not_full = (*ch_ptr->ch_widx - *ch_ptr->ch_ridx) < ch_ptr->num_obj;
+
+       SET_CHAN_STATE(ch_ptr, not_full  ? CHAN_TX_STATE_AVAIL : CHAN_TX_STATE_FULL);
+}
+
+static void gdb_memcpy(void *dest, const void *src, int cnt)
+{
+    int i;
+    char *pd = dest;
+    const char *ps = src;
+
+    for (i = 0; i < cnt; i++)
+       pd[i] = ps[i];
+}
+
+/* 
+ * Function:   gdb_ch_send_data
+ *
+ * Description:        Clone of ch_send_data to be only called by kernel GDB.
+ * 
+ */
+int gdb_ch_send_data(int ch_num, const rs_event_t *ev_hdr, 
+                void* buf, unsigned int len)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+
+       /* No registration checks needed.
+        */
+
+       /* Optimize for buf not full and only one event needed to send */
+
+       /* 
+        * Masking of indexes is not needed for the check in while() below.
+        * Both widx & ridx are unsigned and increase monotonically such that
+        * ridx cannot lag behind widx by more than the circular buf size i.e.
+        * num_obj. widx will overflow before ridx.
+        * 'widx - ridx' will always yield the difference between the two 
+        * even if widx has overflowed and ridx has not yet overflowed.
+        */
+       while((*ch_ptr->ch_widx - *ch_ptr->ch_ridx) < ch_ptr->num_obj)
+       {
+               rs_event_t *wr_ev_ptr = 
+                 &ch_ptr->ch_buf_ptr[*ch_ptr->ch_widx & (ch_ptr->num_obj - 1)];
+
+               /* Copy same header for each event */
+               gdb_memcpy(wr_ev_ptr, (void *) ev_hdr, rs_ev_hdr_sz);
+
+               /* Copy the data portion over */
+               wr_ev_ptr->ev_len = (RS_MSG_LEN > len) ? len : RS_MSG_LEN;
+               gdb_memcpy((char *)wr_ev_ptr + rs_ev_hdr_sz, buf,
+                      wr_ev_ptr->ev_len);
+
+               /* TODO: Set the timestamp in each event */
+#if 0
+               wr_ev_ptr->_ev_stp = 0x0;
+#endif /* 0 */
+               
+               len -= wr_ev_ptr->ev_len;
+               /* 
+                * After updating the widx, DO NOT access any field in that 
+                * event. Though not desirable, the reader is free to alter 
+                * fields in the event.
+                */
+               (*ch_ptr->ch_widx)++;
+               gdb_set_chan_tx_state(ch_ptr);
+
+               /* Let L0 know an ev is available */
+                send_intr_to_l0(ch_ptr);
+
+               if (0 == len)
+                       break;
+
+               buf += RS_MSG_LEN;
+       }       /* End of while */
+
+       return len;     /* bytes remaining, if any */
+}
+
+/* 
+ * Function:   gdb_l0rca_ch_get_event
+ * 
+ * Description:        Clone of l0rca_ch_get_event to only be called by kernel GDB.
+ *             the read pointer is advanced.
+ * 
+ */
+int gdb_l0rca_ch_get_event(int ch_num, rs_event_t *evp)
+{
+       l0rca_mapped_ch_t *ch_ptr = &l0rca_early_cfg.ch_data[ch_num];
+       int ret = 0;
+
+       /* No registration checks needed
+        */
+
+       if(*ch_ptr->ch_widx != *ch_ptr->ch_ridx)
+       {
+               rs_event_t *wr_ev_ptr = 
+                 &ch_ptr->ch_buf_ptr[*ch_ptr->ch_ridx & (ch_ptr->num_obj - 1)];
+
+               /* Copy over the event */
+               gdb_memcpy(evp, (void *)wr_ev_ptr, wr_ev_ptr->ev_len+rs_ev_hdr_sz);
+
+               /* Update the rd index */
+               (*ch_ptr->ch_ridx)++;
+
+               /* Let L0 know that the  event has been drained */
+               send_intr_to_l0(ch_ptr);
+
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/*
+ * Function:    gdb_store_char_in_buf
+ *
+ * Description: Check for overflow and place the incoming character into 
+ *             the local buffer for later retreival.
+ *
+ * Arguments: int ch IN: Incoming character
+ *
+ * Returns: zero  - (SUCCESS)
+ *         -1    - Buffer Overflow
+ */
+static int gdb_store_char_in_buf(char ch)
+{
+       if (gdb_buf_in_cnt >= GDB_BUF_SIZE)
+       {       /* buffer overflow, clear it */
+               gdb_buf_in_inx = 0 ;
+               gdb_buf_in_cnt = 0 ;
+               gdb_buf_out_inx = 0 ;
+               return -1;
+       }
+
+       gdb_buf[gdb_buf_in_inx++] = ch;
+       gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
+       gdb_buf_in_cnt++;
+
+       return 0;
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void gdb_write_char(char chr)
+{
+       int ret;
+
+       while ((ret = gdb_ch_send_data(L0RCA_CH_KGDB_UP, &l0rca_gdb_ev_template,
+              (void *)&chr, sizeof(char))) > 0)
+       {
+               /* Buffer full; keep trying.... */
+               ;
+       }       /* End of while */
+
+       return;
+} /* gdb_write_char */
+
+/*
+ * gdb_getc
+ *
+ * This is a GDB stub routine.  It waits for a character from the
+ * L0 interface and then returns it.
+ */
+int gdb_getc(int wait)
+{
+       char    *chp, *end_buf;
+       int ret, len;
+       rs_event_t ev = {0};
+
+#ifdef PRNT
+       LRPRINTF("gdb_getc:") ;
+#endif
+       /* First check if the receive callback has any chars pending */
+       if (gdb_buf_in_cnt == 0)
+       {
+               /* No chars from rx_callback; Loop until a char is available */
+               while ((ret = gdb_l0rca_ch_get_event(L0RCA_CH_KGDB_DOWN, &ev)) 
+                       <= 0)
+               {
+                       if (ret < 0)
+                       {
+                               /* Error!! This is death */
+                               gdb_read_error++;
+                               return -1;
+                       }
+                       if (! wait)
+                               return 0;
+               } /* End of while */
+
+               /* Get the data in the event */
+               gdb_l0rca_event_data(&ev, (void *)&chp, &len);
+
+               /* We have an event; fill the local buffer */
+               for (end_buf = chp+len; chp < end_buf; chp++)
+               {
+                       if (gdb_store_char_in_buf(*chp) < 0)
+                       {
+                               gdb_store_overflow++;
+                       }
+               } /* End of for */
+       } /* End of if */
+
+       /* There should be something for us in the local buffer now */
+       chp = &gdb_buf[gdb_buf_out_inx++] ;
+       gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
+       gdb_buf_in_cnt--;
+
+#ifdef PRNT
+       LRPRINTF("%c\n", *chp > ' ' && *chp < 0x7F ? *chp : ' ') ;
+#endif
+       return(*chp) ;
+
+} /* gdb_getc */
+
+/*
+ * gdb_putc
+ *
+ * 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.
+ */
+int gdb_putc(char chr)
+{
+#ifdef PRNT
+       LRPRINTF("gdb_putc: chr=%02x '%c'\n", chr,
+                chr > ' ' && chr < 0x7F ? chr : ' ') ;
+#endif
+
+       gdb_write_char(chr);    /* this routine will wait */
+
+       return 1;
+
+} /* gdb_putc */
+
+int    putDebugPacket(char *buf, int n)
+{
+       int ret = -1;
+
+       /* Loop sending the data */
+       while (n)
+       {
+               if ((ret = gdb_ch_send_data(L0RCA_CH_KGDB_UP, &l0rca_gdb_ev_template,
+                    (void *)buf, n)) <= 0) {
+                        /* Either error or we are done */
+                        break;
+                }
+
+                if (n > ret) {
+                        /* Some bytes were sent, point to the remaining data */
+                        buf += (n - ret);
+                        n = ret;
+                }
+       }       
+
+       return ret;
+}
+#endif /* CONFIG_CRAY_KGDB */
diff --git a/kitten/arch/x86_64/kernel/resource.c b/kitten/arch/x86_64/kernel/resource.c
new file mode 100644 (file)
index 0000000..a85416f
--- /dev/null
@@ -0,0 +1,200 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/resource.h>
+#include <arch/page.h>
+#include <arch/io.h>
+#include <arch/sections.h>
+#include <arch/e820.h>
+
+/**
+ * Standard PC resources.
+ */
+struct resource standard_io_resources[] = {
+       { .name = "dma1", .start = 0x00, .end = 0x1f,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "pic1", .start = 0x20, .end = 0x21,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "timer0", .start = 0x40, .end = 0x43,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "timer1", .start = 0x50, .end = 0x53,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "keyboard", .start = 0x60, .end = 0x6f,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "dma page reg", .start = 0x80, .end = 0x8f,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "pic2", .start = 0xa0, .end = 0xa1,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "dma2", .start = 0xc0, .end = 0xdf,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "fpu", .start = 0xf0, .end = 0xff,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO }
+};
+
+#define STANDARD_IO_RESOURCES \
+       (sizeof standard_io_resources / sizeof standard_io_resources[0])
+
+#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
+
+struct resource data_resource = {
+       .name = "Kernel data",
+       .start = 0,
+       .end = 0,
+       .flags = IORESOURCE_RAM,
+};
+struct resource code_resource = {
+       .name = "Kernel code",
+       .start = 0,
+       .end = 0,
+       .flags = IORESOURCE_RAM,
+};
+
+#define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM)
+
+static struct resource system_rom_resource = {
+       .name = "System ROM",
+       .start = 0xf0000,
+       .end = 0xfffff,
+       .flags = IORESOURCE_ROM,
+};
+
+static struct resource extension_rom_resource = {
+       .name = "Extension ROM",
+       .start = 0xe0000,
+       .end = 0xeffff,
+       .flags = IORESOURCE_ROM,
+};
+
+static struct resource adapter_rom_resources[] = {
+       { .name = "Adapter ROM", .start = 0xc8000, .end = 0,
+               .flags = IORESOURCE_ROM },
+       { .name = "Adapter ROM", .start = 0, .end = 0,
+               .flags = IORESOURCE_ROM },
+       { .name = "Adapter ROM", .start = 0, .end = 0,
+               .flags = IORESOURCE_ROM },
+       { .name = "Adapter ROM", .start = 0, .end = 0,
+               .flags = IORESOURCE_ROM },
+       { .name = "Adapter ROM", .start = 0, .end = 0,
+               .flags = IORESOURCE_ROM },
+       { .name = "Adapter ROM", .start = 0, .end = 0,
+               .flags = IORESOURCE_ROM }
+};
+
+#define ADAPTER_ROM_RESOURCES \
+       (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
+
+static struct resource video_rom_resource = {
+       .name = "Video ROM",
+       .start = 0xc0000,
+       .end = 0xc7fff,
+       .flags = IORESOURCE_ROM,
+};
+
+static struct resource video_ram_resource = {
+       .name = "Video RAM area",
+       .start = 0xa0000,
+       .end = 0xbffff,
+       .flags = IORESOURCE_RAM,
+};
+
+#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+static int __init
+romchecksum(unsigned char *rom, unsigned long length)
+{
+       unsigned char *p, sum = 0;
+
+       for (p = rom; p < rom + length; p++)
+               sum += *p;
+       return sum == 0;
+}
+
+static void __init
+probe_roms(void)
+{
+       unsigned long start, length, upper;
+       unsigned char *rom;
+       int           i;
+
+       /* video rom */
+       upper = adapter_rom_resources[0].start;
+       for (start = video_rom_resource.start; start < upper; start += 2048) {
+               rom = isa_bus_to_virt(start);
+               if (!romsignature(rom))
+                       continue;
+
+               video_rom_resource.start = start;
+
+               /* 0 < length <= 0x7f * 512, historically */
+               length = rom[2] * 512;
+
+               /* if checksum okay, trust length byte */
+               if (length && romchecksum(rom, length))
+                       video_rom_resource.end = start + length - 1;
+
+               request_resource(&iomem_resource, &video_rom_resource);
+               break;
+       }
+
+       start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
+       if (start < upper)
+               start = upper;
+
+       /* system rom */
+       request_resource(&iomem_resource, &system_rom_resource);
+       upper = system_rom_resource.start;
+
+       /* check for extension rom (ignore length byte!) */
+       rom = isa_bus_to_virt(extension_rom_resource.start);
+       if (romsignature(rom)) {
+               length = extension_rom_resource.end - extension_rom_resource.start + 1;
+               if (romchecksum(rom, length)) {
+                       request_resource(&iomem_resource, &extension_rom_resource);
+                       upper = extension_rom_resource.start;
+               }
+       }
+
+       /* check for adapter roms on 2k boundaries */
+       for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
+               rom = isa_bus_to_virt(start);
+               if (!romsignature(rom))
+                       continue;
+
+               /* 0 < length <= 0x7f * 512, historically */
+               length = rom[2] * 512;
+
+               /* but accept any length that fits if checksum okay */
+               if (!length || start + length > upper || !romchecksum(rom, length))
+                       continue;
+
+               adapter_rom_resources[i].start = start;
+               adapter_rom_resources[i].end = start + length - 1;
+               request_resource(&iomem_resource, &adapter_rom_resources[i]);
+
+               start = adapter_rom_resources[i++].end & ~2047UL;
+       }
+}
+
+void __init
+init_resources(void)
+{
+       unsigned int i;
+
+       code_resource.start = virt_to_phys(&_text);
+       code_resource.end   = virt_to_phys(&_etext)-1;
+       data_resource.start = virt_to_phys(&_etext);
+       data_resource.end   = virt_to_phys(&_edata)-1;
+
+       /*
+        * Request address space for all standard RAM and ROM resources
+        * and also for regions reported as reserved by the e820.
+        */
+       probe_roms();
+       e820_reserve_resources(); 
+
+       request_resource(&iomem_resource, &video_ram_resource);
+
+       /* request I/O space for devices used on all i[345]86 PCs */
+       for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+               request_resource(&ioport_resource, &standard_io_resources[i]);
+}
+
diff --git a/kitten/arch/x86_64/kernel/sched.c b/kitten/arch/x86_64/kernel/sched.c
new file mode 100644 (file)
index 0000000..522d668
--- /dev/null
@@ -0,0 +1,81 @@
+#include <lwk/kernel.h>
+#include <lwk/smp.h>
+#include <lwk/task.h>
+#include <arch/i387.h>
+
+struct task_struct *
+__arch_context_switch(struct task_struct *prev_p, struct task_struct *next_p)
+{
+       struct thread_struct *prev = &prev_p->arch.thread;
+       struct thread_struct *next = &next_p->arch.thread;
+       id_t cpu = this_cpu;
+       struct tss_struct *tss = &per_cpu(tss, cpu);
+
+       /* Update TSS */
+       tss->rsp0 = next->rsp0;
+
+       /* Switch DS and ES segment registers */
+       asm volatile("mov %%es,%0" : "=m" (prev->es));
+       if (unlikely(next->es | prev->es))
+               loadsegment(es, next->es);
+       asm volatile("mov %%ds,%0" : "=m" (prev->ds));
+       if (unlikely(next->ds | prev->ds))
+               loadsegment(ds, next->ds);
+
+       /* Load FS and GS segment registers (used for thread local storage) */
+       {
+               unsigned int fsindex;
+               asm volatile("movl %%fs,%0" : "=r" (fsindex));
+               if (unlikely(fsindex | next->fsindex | prev->fs)) {
+                       loadsegment(fs, next->fsindex);
+                       if (fsindex)
+                               prev->fs = 0;
+               }
+               if (next->fs)
+                       wrmsrl(MSR_FS_BASE, next->fs);
+               prev->fsindex = fsindex;
+       }
+       {
+               unsigned int gsindex;
+               asm volatile("movl %%gs,%0" : "=r" (gsindex));
+               if (unlikely(gsindex | next->gsindex | prev->gs)) {
+                       load_gs_index(next->gsindex);
+                       if (gsindex)
+                               prev->gs = 0;
+               }
+               if (next->gs)
+                       wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
+               prev->gsindex = gsindex;
+       }
+
+       /* Update the CPU's PDA (per-CPU data area) */
+       write_pda(pcurrent, next_p);
+
+       /* If necessary, save and restore floating-point state */
+       if (prev_p->arch.flags & TF_USED_FPU)
+               fpu_save_state(prev_p);
+       if (next_p->arch.flags & TF_USED_FPU) {
+               clts();
+               fpu_restore_state(next_p);
+       } else {
+               /*
+                * Set the TS flag of CR0 so that FPU/MMX/SSE instructions
+                * will cause a "Device not available" exception. The exception
+                * handler will then initialize the FPU state and set the
+                * task's TF_USED_FPU flag.  From that point on, the task
+                * should never experience another "Device not available"
+                * exception.
+                */
+               stts();
+       }
+
+       return prev_p;
+}
+
+void
+arch_idle_task_loop_body(void)
+{
+       /* Issue HALT instruction,
+        * which should put CPU in a lower power mode */
+       halt();
+}
diff --git a/kitten/arch/x86_64/kernel/setup.c b/kitten/arch/x86_64/kernel/setup.c
new file mode 100644 (file)
index 0000000..a940b4d
--- /dev/null
@@ -0,0 +1,305 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/bootmem.h>
+#include <lwk/smp.h>
+#include <arch/bootsetup.h>
+#include <arch/e820.h>
+#include <arch/page.h>
+#include <arch/sections.h>
+#include <arch/proto.h>
+#include <arch/mpspec.h>
+#include <arch/pda.h>
+#include <arch/io_apic.h>
+
+/**
+ * Bitmap of of PTE/PMD entry flags that are supported.
+ * This is AND'ed with a PTE/PMD entry before it is installed.
+ */
+unsigned long __supported_pte_mask __read_mostly = ~0UL;
+
+/**
+ * Bitmap of features enabled in the CR4 register.
+ */
+unsigned long mmu_cr4_features;
+
+/**
+ * Start and end addresses of the initrd image.
+ */
+paddr_t __initdata initrd_start;
+paddr_t __initdata initrd_end;
+
+/**
+ * The init_task ELF image.
+ */
+paddr_t __initdata init_elf_image;
+
+/**
+ * Base address and size of the Extended BIOS Data Area.
+ */
+paddr_t __initdata ebda_addr;
+size_t  __initdata ebda_size;
+#define EBDA_ADDR_POINTER 0x40E
+
+/**
+ * Finds the address and length of the Extended BIOS Data Area.
+ */
+static void __init
+discover_ebda(void)
+{
+       /*
+        * There is a real-mode segmented pointer pointing to the 
+        * 4K EBDA area at 0x40E
+        */
+       ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
+       ebda_addr <<= 4;
+
+       ebda_size = *(unsigned short *)__va(ebda_addr);
+
+       /* Round EBDA up to pages */
+       if (ebda_size == 0)
+               ebda_size = 1;
+       ebda_size <<= 10;
+       ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
+       if (ebda_size > 64*1024)
+               ebda_size = 64*1024;
+}
+
+/**
+ * This sets up the bootstrap memory allocator.  It is a simple
+ * bitmap based allocator that tracks memory at a page grandularity.
+ * Once the bootstrap process is complete, each unallocated page
+ * is added to the real memory allocator's free pool.  Memory allocated
+ * during bootstrap remains allocated forever, unless explicitly
+ * freed before turning things over to the real memory allocator.
+ */
+static void __init
+setup_bootmem_allocator(
+       unsigned long   start_pfn,
+       unsigned long   end_pfn
+)
+{
+       unsigned long bootmap_size, bootmap;
+
+       bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
+       bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
+       if (bootmap == -1L)
+               panic("Cannot find bootmem map of size %ld\n",bootmap_size);
+       bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
+       e820_bootmem_free(0, end_pfn << PAGE_SHIFT);
+       reserve_bootmem(bootmap, bootmap_size);
+}
+
+/**
+ * Mark in-use memory regions as reserved.
+ * This prevents the bootmem allocator from allocating them.
+ */
+static void __init
+reserve_memory(void)
+{
+       /* Reserve the kernel page table memory */
+       reserve_bootmem(table_start << PAGE_SHIFT,
+                       (table_end - table_start) << PAGE_SHIFT);
+
+       /* Reserve kernel memory */
+       reserve_bootmem(__pa_symbol(&_text),
+                       __pa_symbol(&_end) - __pa_symbol(&_text));
+
+       /* Reserve physical page 0... it's a often a special BIOS page */
+       reserve_bootmem(0, PAGE_SIZE);
+
+       /* Reserve the Extended BIOS Data Area memory */
+       if (ebda_addr)
+               reserve_bootmem(ebda_addr, ebda_size);
+
+       /* Reserve SMP trampoline */
+       reserve_bootmem(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
+
+       /* Find and reserve boot-time SMP configuration */
+       find_mp_config();
+
+       /* Reserve memory used by the initrd image */
+       if (LOADER_TYPE && INITRD_START) {
+               if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
+                       printk(KERN_DEBUG
+                              "reserving memory used by initrd image\n");
+                       printk(KERN_DEBUG
+                              "  INITRD_START=0x%lx, INITRD_SIZE=%ld bytes\n",
+                              (unsigned long) INITRD_START,
+                              (unsigned long) INITRD_SIZE);
+                       reserve_bootmem(INITRD_START, INITRD_SIZE);
+                       initrd_start = INITRD_START;
+                       initrd_end = initrd_start+INITRD_SIZE;
+                       init_elf_image = initrd_start;
+               } else {
+                       printk(KERN_ERR
+                              "initrd extends beyond end of memory "
+                              "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                              (unsigned long)(INITRD_START + INITRD_SIZE),
+                              (unsigned long)(end_pfn << PAGE_SHIFT));
+                       initrd_start = 0;
+               }
+       }
+}
+
+/**
+ * This initializes a per-CPU area for each CPU.
+ *
+ * TODO: The PDA and per-CPU areas are pretty tightly wound.  It should be
+ *       possible to make the per-CPU area *be* the PDA, or put another way,
+ *       point %GS at the per-CPU area rather than the PDA.  All of the PDA's
+ *       current contents would become normal per-CPU variables.
+ */
+static void __init
+setup_per_cpu_areas(void)
+{ 
+       int i;
+       size_t size;
+
+       /*
+        * There is an ELF section containing all per-CPU variables
+        * surrounded by __per_cpu_start and __per_cpu_end symbols.
+        * We create a copy of this ELF section for each CPU.
+        */
+       size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
+
+       for_each_cpu_mask (i, cpu_present_map) {
+               char *ptr;
+
+               ptr = alloc_bootmem_aligned(size, PAGE_SIZE);
+               if (!ptr)
+                       panic("Cannot allocate cpu data for CPU %d\n", i);
+
+               /*
+                * Pre-bias data_offset by subtracting its offset from
+                * __per_cpu_start.  Later, per_cpu() will calculate a
+                * per_cpu variable's address with:
+                * 
+                * addr = offset_in_percpu_ELF_section + data_offset
+                *      = (__per_cpu_start + offset)   + (ptr - __per_cpu_start)
+                *      =                    offset    +  ptr
+                */
+               cpu_pda(i)->data_offset = ptr - __per_cpu_start;
+
+               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+       }
+} 
+
+static inline int get_family(int cpuid)
+{       
+        int base = (cpuid>>8) & 0xf;
+        int extended = (cpuid>>20) &0xff;
+                        
+        return (0xf == base) ? base + extended : base;
+}
+
+/**
+ * Architecture specific initialization.
+ * This is called from start_kernel() in init/main.c.
+ *
+ * NOTE: Ordering is usually important.  Do not move things
+ *       around unless you know what you are doing.
+ */
+void __init
+setup_arch(void)
+{
+       /*
+        * Figure out which memory regions are usable and which are reserved.
+        * This builds the "e820" map of memory from info provided by the
+        * BIOS.
+        */
+       setup_memory_region();
+
+       /*
+        * Get the bare minimum info about the bootstrap CPU... the
+        * one we're executing on right now.  Latter on, the full
+        * boot_cpu_data and cpu_info[boot_cpu_id] structures will be
+        * filled in completely.
+        */
+       boot_cpu_data.logical_id = 0;
+       early_identify_cpu(&boot_cpu_data);
+
+       /*
+        * Find the Extended BIOS Data Area.
+        * (Not sure why exactly we need this, probably don't.)
+        */ 
+       discover_ebda();
+
+       /*
+        * Initialize the kernel page tables.
+        * The kernel page tables map an "identity" map of all physical memory
+        * starting at virtual address PAGE_OFFSET.  When the kernel executes,
+        * it runs inside of the identity map... memory below PAGE_OFFSET is
+        * from whatever task was running when the kernel got invoked.
+        */
+       init_kernel_pgtables(0, (end_pfn_map << PAGE_SHIFT));
+
+       /*
+        * Initialize the bootstrap dynamic memory allocator.
+        * alloc_bootmem() will work after this.
+        */
+       setup_bootmem_allocator(0, end_pfn);
+       reserve_memory();
+
+       /*
+        * Get the multiprocessor configuration...
+        * number of CPUs, PCI bus info, APIC info, etc.
+        */
+       get_mp_config();
+
+       /*
+        * Initialize resources.  Resources reserve sections of normal memory
+        * (iomem) and I/O ports (ioport) for devices and other system
+        * resources.  For each resource type, there is a tree which tracks
+        * which regions are in use.  This eliminates the possiblity of
+        * conflicts... e.g., two devices trying to use the same iomem region.
+        */
+       init_resources();
+
+       /*
+        * Initialize per-CPU areas, one per CPU.
+        * Variables defined with DEFINE_PER_CPU() end up in the per-CPU area.
+        * This provides a mechanism for different CPUs to refer to their
+        * private copy of the variable using the same name
+        * (e.g., get_cpu_var(foo)).
+        */
+       setup_per_cpu_areas();
+
+       /*
+        * Initialize the IDT table and interrupt handlers.
+        */
+       interrupts_init();
+
+       /*
+        * Map the APICs into the kernel page tables.
+        *
+        * Each CPU has its own Local APIC. All Local APICs are memory mapped
+        * to the same virtual address region. A CPU accesses its Local APIC by
+        * accessing the region. A CPU cannot access another CPU's Local APIC.
+        *
+        * Each Local APIC is connected to all IO APICs in the system. Each IO
+        * APIC is mapped to a different virtual address region. A CPU accesses
+        * a given IO APIC by accessing the appropriate region. All CPUs can
+        * access all IO APICs.
+        */
+       lapic_map();
+       ioapic_map();
+
+       /*
+        * Initialize the virtual system call code/data page.
+        * The vsyscall page is mapped into every task's address space at a
+        * well-known address.  User code can call functions in this page
+        * directly, providing a light-weight mechanism for read-only system
+        * calls such as gettimeofday().
+        */
+       vsyscall_map();
+
+       cpu_init();
+
+       current->cpumask = cpu_present_map;
+
+       ioapic_init();
+
+       lapic_set_timer(1000000000);
+}
+
diff --git a/kitten/arch/x86_64/kernel/show.c b/kitten/arch/x86_64/kernel/show.c
new file mode 100644 (file)
index 0000000..c74f62e
--- /dev/null
@@ -0,0 +1,119 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+#include <lwk/ptrace.h>
+#include <lwk/version.h>
+#include <lwk/kallsyms.h>
+#include <arch/msr.h>
+
+/**
+ * Prints a nicely formatted address to the console.
+ * This attempts to look up the symbolic name of the address.
+ */
+void
+printk_address(unsigned long address)
+{
+       unsigned long offset = 0, symsize;
+       const char *symname;
+       char namebuf[128];
+
+       symname = kallsyms_lookup(address, &symsize, &offset, namebuf);
+       if (!symname) {
+               printk(" [<%016lx>]\n", address);
+               return;
+       }
+       printk(" [<%016lx>] %s+0x%lx/0x%lx\n",
+               address, symname, offset, symsize);
+}
+
+
+/**
+ * Print a stack trace of the context.
+ */
+void
+kstack_trace(
+       void *                  rbp_v
+)
+{
+#ifndef CONFIG_FRAME_POINTER
+       printk( "Unable to generate stack trace "
+               "(recompile with CONFIG_FRAME_POINTER)\n" );
+       return;
+#endif
+
+       uint64_t * rbp = rbp_v;
+       if( rbp == 0 )
+               asm( "mov %%rbp, %0" : "=r"(rbp) );
+
+       int max_depth = 16;
+       printk( "Stack trace from RBP %p\n", rbp );
+
+       while( rbp && max_depth-- )
+       {
+               printk_address( rbp[1] );
+               rbp = (uint64_t*) *rbp;
+       }
+}
+
+
+/**
+ * Prints x86_64 general purpose registers and friends to the console.
+ * NOTE: This prints the CPU register values contained in the passed in
+ *       'struct pt_regs *'.  It DOES NOT print the current values in
+ *       the CPU's registers.
+ */
+void
+show_registers(struct pt_regs * regs)
+{
+       unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
+       unsigned int fsindex, gsindex;
+       unsigned int ds, cs, es;
+       bool user_fault = (regs->rip < PAGE_OFFSET);
+       char namebuf[128];
+
+/*
+       printk("Task ID: %d   Task Name: %s   UTS_RELEASE: %s\n",
+               current ? current->id : -1,
+               current ? current->name : "BAD CURRENT",
+               UTS_RELEASE
+       );
+*/
+       printk("RIP: %04lx:%016lx (%s)\n", regs->cs & 0xffff, regs->rip,
+              (user_fault) ? "user-context"
+                           : kallsyms_lookup(regs->rip, NULL, NULL, namebuf));
+       printk("RSP: %04lx:%016lx EFLAGS: %08lx ERR: %08lx\n",
+               regs->ss, regs->rsp, regs->eflags, regs->orig_rax);
+       printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
+              regs->rax, regs->rbx, regs->rcx);
+       printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
+              regs->rdx, regs->rsi, regs->rdi);
+       printk("RBP: %016lx R08: %016lx R09: %016lx\n",
+              regs->rbp, regs->r8, regs->r9);
+       printk("R10: %016lx R11: %016lx R12: %016lx\n",
+              regs->r10, regs->r11, regs->r12);
+       printk("R13: %016lx R14: %016lx R15: %016lx\n",
+              regs->r13, regs->r14, regs->r15);
+
+       asm("movl %%ds,%0" : "=r" (ds));
+       asm("movl %%cs,%0" : "=r" (cs));
+       asm("movl %%es,%0" : "=r" (es));
+       asm("movl %%fs,%0" : "=r" (fsindex));
+       asm("movl %%gs,%0" : "=r" (gsindex));
+
+       rdmsrl(MSR_FS_BASE, fs);
+       rdmsrl(MSR_GS_BASE, gs);
+       rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
+
+       asm("movq %%cr0, %0": "=r" (cr0));
+       asm("movq %%cr2, %0": "=r" (cr2));
+       asm("movq %%cr3, %0": "=r" (cr3));
+       asm("movq %%cr4, %0": "=r" (cr4));
+
+       printk("FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
+              fs, fsindex, gs, gsindex, shadowgs);
+       printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0);
+       printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+
+       if (!user_fault)
+               kstack_trace( (void *) regs->rbp );
+}
+
diff --git a/kitten/arch/x86_64/kernel/sys_arch_prctl.c b/kitten/arch/x86_64/kernel/sys_arch_prctl.c
new file mode 100644 (file)
index 0000000..5243162
--- /dev/null
@@ -0,0 +1,84 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+#include <arch/prctl.h>
+#include <arch/uaccess.h>
+
+
+long
+do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
+{
+       int ret = 0; 
+       int doit = task == current;
+
+       switch (code) { 
+       case ARCH_SET_GS:
+               if (addr >= task->arch.addr_limit)
+                       return -EPERM; 
+
+               task->arch.thread.gsindex = 0;
+               task->arch.thread.gs = addr;
+               if (doit) {
+                       /* The kernel's %gs is currently loaded, so this
+                          call is needed to set the user version. */
+                       load_gs_index(0);
+                       ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
+               } 
+
+               break;
+       case ARCH_SET_FS:
+               /* Not strictly needed for fs, but do it for symmetry
+                  with gs */
+               if (addr >= task->arch.addr_limit)
+                       return -EPERM; 
+
+               task->arch.thread.fsindex = 0;
+               task->arch.thread.fs = addr;
+               if (doit) {
+                       /* The kernel doesn't use %fs so we can set it
+                          directly.  set the selector to 0 to not confuse
+                          __switch_to */
+                       asm volatile("movl %0,%%fs" :: "r" (0));
+                       ret = checking_wrmsrl(MSR_FS_BASE, addr);
+               }
+
+               break;
+       case ARCH_GET_FS: { 
+               unsigned long base; 
+               if (doit)
+                       rdmsrl(MSR_FS_BASE, base);
+               else
+                       base = task->arch.thread.fs;
+               ret = put_user(base, (unsigned long __user *)addr); 
+               break; 
+       }
+       case ARCH_GET_GS: { 
+               unsigned long base;
+               unsigned gsindex;
+               if (doit) {
+                       asm("movl %%gs,%0" : "=r" (gsindex));
+                       if (gsindex)
+                               rdmsrl(MSR_KERNEL_GS_BASE, base);
+                       else
+                               base = task->arch.thread.gs;
+               }
+               else
+                       base = task->arch.thread.gs;
+               ret = put_user(base, (unsigned long __user *)addr); 
+               break;
+       }
+
+       default:
+               ret = -EINVAL;
+               break;
+       } 
+
+       return ret;     
+}
+
+
+long
+sys_arch_prctl(int code, unsigned long addr)
+{
+       return do_arch_prctl(current, code, addr);
+}
+
diff --git a/kitten/arch/x86_64/kernel/syscall.c b/kitten/arch/x86_64/kernel/syscall.c
new file mode 100644 (file)
index 0000000..c1322f0
--- /dev/null
@@ -0,0 +1,52 @@
+#include <lwk/kernel.h>
+#include <lwk/linkage.h>
+#include <lwk/cache.h>
+#include <lwk/errno.h>
+#include <arch/asm-offsets.h>
+
+/**
+ * This generate prototypes for all system call handlers.
+ */
+#define __SYSCALL(nr, sym) extern long sym(void);
+#undef _ARCH_X86_64_UNISTD_H
+#include <arch/unistd.h>
+
+/**
+ * Setup for the include of <arch/unistd.h> in the sys_call_table[]
+ * definition below.
+ */
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) [ nr ] = sym, 
+#undef _ARCH_X86_64_UNISTD_H
+
+/**
+ * Prototype for system call handler functions.
+ */
+typedef long (*syscall_ptr_t)(void); 
+
+/**
+ * Dummy handler for unimplemented system calls.
+ */
+long syscall_not_implemented(void)
+{
+       unsigned long syscall_number;
+
+       /* On entry to function, syscall # is in %rax register */
+       asm volatile("mov %%rax, %0" : "=r"(syscall_number)::"%rax");
+
+       printk(KERN_DEBUG "System call not implemented! "
+                         "(syscall_number=%lu)\n", syscall_number);
+//     return -ENOSYS;
+       return 0;
+}
+
+/**
+ * This is the system call table.  The system_call() function in entry.S
+ * uses this table to determine the handler function to call for each
+ * system call.  The table is indexed by system call number.
+ */
+const syscall_ptr_t sys_call_table[__NR_syscall_max+1] = {
+       [0 ... __NR_syscall_max] = syscall_not_implemented,
+       #include <arch/unistd.h>
+};
+
diff --git a/kitten/arch/x86_64/kernel/task.c b/kitten/arch/x86_64/kernel/task.c
new file mode 100644 (file)
index 0000000..5254b9c
--- /dev/null
@@ -0,0 +1,47 @@
+#include <lwk/kernel.h>
+#include <lwk/aspace.h>
+#include <lwk/task.h>
+#include <arch/ptrace.h>
+
+int
+arch_task_create(struct task_struct *task,
+                 const start_state_t *start_state)
+{
+       struct pt_regs *regs;
+       kaddr_t kstack_top;
+       kaddr_t initial_ksp;
+
+       regs        = ((struct pt_regs *)((kaddr_t)task + TASK_SIZE)) - 1;
+       kstack_top  = (kaddr_t)(regs + 1);
+       initial_ksp = (kaddr_t)regs;
+
+       task->arch.thread.rsp0    = kstack_top;
+       task->arch.thread.rsp     = initial_ksp;
+       task->arch.thread.userrsp = start_state->stack_ptr;
+
+       /* Mark this as a new-task... arch_context_switch() checks this flag */
+       task->arch.flags = TF_NEW_TASK;
+
+       /* Task's address space is from [0, task->addr_limit) */
+       task->arch.addr_limit = PAGE_OFFSET;
+
+       /* Initialize FPU state */
+       task->arch.thread.i387.fxsave.cwd = 0x37f;
+       task->arch.thread.i387.fxsave.mxcsr = 0x1f80;
+
+       /* CPU control unit uses these fields to start the user task running */
+       if (start_state->aspace_id == KERNEL_ASPACE_ID) {
+               regs->ss     = __KERNEL_DS;
+               regs->rsp    = (vaddr_t)task + TASK_SIZE;
+               regs->eflags = (1 << 9);  /* enable interrupts */
+               regs->cs     = __KERNEL_CS;
+       } else {
+               regs->ss     = __USER_DS;
+               regs->rsp    = start_state->stack_ptr;
+               regs->eflags = (1 << 9);  /* enable interrupts */
+               regs->cs     = __USER_CS;
+       }
+       regs->rip = start_state->entry_point;
+
+       return 0;
+}
diff --git a/kitten/arch/x86_64/kernel/time.c b/kitten/arch/x86_64/kernel/time.c
new file mode 100644 (file)
index 0000000..cc2b0bf
--- /dev/null
@@ -0,0 +1,187 @@
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/spinlock.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/smp.h>
+#include <lwk/time.h>
+#include <arch/io.h>
+#include <arch/apic.h>
+
+#ifdef CONFIG_PC
+/**
+ * Lock that synchronizes access to the Programmable Interval Timer.
+ */
+static DEFINE_SPINLOCK(pit_lock);
+
+/**
+ * This stops the Programmable Interval Timer's periodic system timer
+ * (channel 0). Some systems, BOCHS included, are booted with the PIT system
+ * timer enabled. The LWK doesn't use the PIT, so this function is used during
+ * bootstrap to disable it.
+ */
+static void __init
+pit_stop_timer0(void)
+{
+       unsigned long flags;
+       unsigned PIT_MODE = 0x43;
+       unsigned PIT_CH0  = 0x40;
+
+       spin_lock_irqsave(&pit_lock, flags);
+       outb_p(0x30, PIT_MODE);         /* mode 0 */
+       outb_p(0, PIT_CH0);             /* LSB system timer interval */
+       outb_p(0, PIT_CH0);             /* MSB system timer interval */
+       spin_unlock_irqrestore(&pit_lock, flags);
+}
+
+/**
+ * This uses the Programmable Interval Timer that is standard on all
+ * PC-compatible systems to determine the time stamp counter frequency.
+ *
+ * This uses the speaker output (channel 2) of the PIT. This is better than
+ * using the timer interrupt output because we can read the value of the
+ * speaker with just one inb(), where we need three i/o operations for the
+ * interrupt channel. We count how many ticks the TSC does in 50 ms.
+ *
+ * Returns the detected time stamp counter frequency in KHz.
+ */
+static unsigned int __init
+pit_calibrate_tsc(void)
+{
+       cycles_t start, end;
+       unsigned long flags;
+       unsigned long pit_tick_rate = 1193182UL;  /* 1.193182 MHz */
+
+       spin_lock_irqsave(&pit_lock, flags);
+
+       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+       outb(0xb0, 0x43);
+       outb((pit_tick_rate / (1000 / 50)) & 0xff, 0x42);
+       outb((pit_tick_rate / (1000 / 50)) >> 8, 0x42);
+       start = get_cycles_sync();
+       while ((inb(0x61) & 0x20) == 0);
+       end = get_cycles_sync();
+
+       spin_unlock_irqrestore(&pit_lock, flags);
+       
+       return (end - start) / 50;
+}
+#endif
+
+#ifdef CONFIG_CRAY_XT
+/**
+ * The Cray XT platform does not have any real time clocks. Therefore,
+ * we have to inspect various MSRs to determine the CPU frequency and
+ * trust that it is accurate.
+ *
+ * Returns the detected CPU frequency in KHz.
+ *
+ * NOTE: This function should only be used on Cray XT3/XT4/XT? platforms.
+ *       While it will work on (some) AMD Opteron K8 and K10 systems, using a
+ *       timer based mechanism to detect the actual CPU frequency is preferred.
+ */
+static unsigned int __init
+crayxt_detect_cpu_freq(void)
+{
+       unsigned int MHz = 200;
+       unsigned int lower, upper;
+       int amd_family = cpu_info[this_cpu].arch.x86_family;
+       int amd_model  = cpu_info[this_cpu].arch.x86_model;
+
+       if (amd_family == 16) {
+               unsigned int fid; /* current frequency id */
+               unsigned int did; /* current divide id */
+
+               rdmsr(MSR_K10_COFVID_STATUS, lower, upper);
+               fid = lower & 0x3f;
+               did = (lower >> 6) & 0x3f;
+               MHz = 100 * (fid + 0x10) / (1 << did);
+
+       } else if (amd_family == 15) {
+               unsigned int fid; /* current frequency id */
+
+               if (amd_model < 16) {
+                       /* Revision C and earlier */
+                       rdmsr(MSR_K8_HWCR, lower, upper);
+                       fid = (lower >> 24) & 0x3f;
+               } else {
+                       /* Revision D and later */
+                       rdmsr(MSR_K8_FIDVID_STATUS, lower, upper);
+                       fid = lower & 0x3f;
+               }
+
+               switch (fid) {
+                       case 0:   MHz *= 4; break;
+                       case 2:   MHz *= 5; break;
+                       case 4:   MHz *= 6; break;
+                       case 6:   MHz *= 7; break;
+                       case 8:   MHz *= 8; break;
+                       case 10:  MHz *= 9; break;
+                       case 12:  MHz *= 10; break;
+                       case 14:  MHz *= 11; break;
+                       case 16:  MHz *= 12; break;
+                       case 18:  MHz *= 13; break;
+                       case 20:  MHz *= 14; break;
+                       case 22:  MHz *= 15; break;
+                       case 24:  MHz *= 16; break;
+                       case 26:  MHz *= 17; break;
+                       case 28:  MHz *= 18; break;
+                       case 30:  MHz *= 19; break;
+                       case 32:  MHz *= 20; break;
+                       case 34:  MHz *= 21; break;
+                       case 36:  MHz *= 22; break;
+                       case 38:  MHz *= 23; break;
+                       case 40:  MHz *= 24; break;
+                       case 42:  MHz *= 25; break;
+               }
+       } else {
+               panic("Unknown AMD CPU family (%d).", amd_family);
+       }
+
+       return (MHz * 1000); /* return CPU freq. in KHz */
+}
+#endif
+
+void __init
+time_init(void)
+{
+       unsigned int cpu_khz;
+       unsigned int lapic_khz;
+
+       /*
+        * Detect the CPU frequency
+        */
+#if defined CONFIG_PC
+       cpu_khz = pit_calibrate_tsc();
+       pit_stop_timer0();
+#elif defined CONFIG_CRAY_XT
+       cpu_khz = crayxt_detect_cpu_freq();
+#else
+       #error "In time_init(), unknown system architecture."
+#endif
+
+       cpu_info[this_cpu].arch.cur_cpu_khz = cpu_khz;
+       cpu_info[this_cpu].arch.max_cpu_khz = cpu_khz;
+       cpu_info[this_cpu].arch.min_cpu_khz = cpu_khz;
+       cpu_info[this_cpu].arch.tsc_khz     = cpu_khz;
+
+       init_cycles2ns(cpu_khz);
+
+       /*
+        * Detect the Local APIC timer's base clock frequency
+        */
+       if (this_cpu == 0) {
+               lapic_khz = lapic_calibrate_timer();
+       } else {
+               lapic_khz = cpu_info[0].arch.lapic_khz;
+       }
+
+       cpu_info[this_cpu].arch.lapic_khz   = lapic_khz;
+
+       printk(KERN_DEBUG "CPU %u: %u.%03u MHz, LAPIC bus %u.%03u MHz\n",
+               this_cpu,
+               cpu_khz / 1000, cpu_khz % 1000,
+               lapic_khz / 1000, lapic_khz % 1000
+       );
+}
+
diff --git a/kitten/arch/x86_64/kernel/trampoline.S b/kitten/arch/x86_64/kernel/trampoline.S
new file mode 100644 (file)
index 0000000..1635ca2
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *
+ *     Trampoline.S    Derived from Setup.S by Linus Torvalds
+ *
+ *     4 Jan 1997 Michael Chastain: changed to gnu as.
+ *     15 Sept 2005 Eric Biederman: 64bit PIC support
+ *
+ *     Entry: CS:IP point to the start of our code, we are 
+ *     in real mode with no stack, but the rest of the 
+ *     trampoline page to make our stack and everything else
+ *     is a mystery.
+ *
+ *     In fact we don't actually need a stack so we don't
+ *     set one up.
+ *
+ *     On entry to trampoline_data, the processor is in real mode
+ *     with 16-bit addressing and 16-bit data.  CS has some value
+ *     and IP is zero.  Thus, data addresses need to be absolute
+ *     (no relocation) and are taken with regard to r_base.
+ *
+ *     With the addition of trampoline_level4_pgt this code can
+ *     now enter a 64bit kernel that lives at arbitrary 64bit
+ *     physical addresses.
+ *
+ *     If you work on this file, check the object module with objdump
+ *     --full-contents --reloc to make sure there are no relocation
+ *     entries.
+ */
+
+#include <lwk/linkage.h>
+#include <arch/pgtable.h>
+#include <arch/page.h>
+#include <arch/msr.h>
+#include <arch/segment.h>
+
+.data
+
+.code16
+
+ENTRY(trampoline_data)
+r_base = .
+       cli                     # We should be safe anyway
+       wbinvd  
+       mov     %cs, %ax        # Code and data in the same place
+       mov     %ax, %ds
+       mov     %ax, %es
+       mov     %ax, %ss
+
+
+       movl    $0xA5A5A5A5, trampoline_data - r_base
+                               # write marker for master knows we're running
+
+                                       # Setup stack
+       movw    $(trampoline_stack_end - r_base), %sp
+
+       call    verify_cpu              # Verify the cpu supports long mode
+       testl   %eax, %eax              # Check for return code
+       jnz     no_longmode
+
+       mov     %cs, %ax
+       movzx   %ax, %esi               # Find the 32bit trampoline location
+       shll    $4, %esi
+
+                                       # Fixup the vectors
+       addl    %esi, startup_32_vector - r_base
+       addl    %esi, startup_64_vector - r_base
+       addl    %esi, tgdt + 2 - r_base # Fixup the gdt pointer
+
+       /*
+        * GDT tables in non default location kernel can be beyond 16MB and
+        * lgdt will not be able to load the address as in real mode default
+        * operand size is 16bit. Use lgdtl instead to force operand size
+        * to 32 bit.
+        */
+
+       lidtl   tidt - r_base   # load idt with 0, 0
+       lgdtl   tgdt - r_base   # load gdt with whatever is appropriate
+
+       xor     %ax, %ax
+       inc     %ax             # protected mode (PE) bit
+       lmsw    %ax             # into protected mode
+
+       # flush prefetch and jump to startup_32
+       ljmpl   *(startup_32_vector - r_base)
+
+       .code32
+       .balign 4
+startup_32:
+       movl    $__KERNEL_DS, %eax      # Initialize the %ds segment register
+       movl    %eax, %ds
+
+       xorl    %eax, %eax
+       btsl    $5, %eax                # Enable PAE mode
+       movl    %eax, %cr4
+
+                                       # Setup trampoline 4 level pagetables
+       leal    (trampoline_level4_pgt - r_base)(%esi), %eax
+       movl    %eax, %cr3
+
+       movl    $MSR_EFER, %ecx
+       movl    $(1 << _EFER_LME), %eax # Enable Long Mode
+       xorl    %edx, %edx
+       wrmsr
+
+       xorl    %eax, %eax
+       btsl    $31, %eax               # Enable paging and in turn activate Long Mode
+       btsl    $0, %eax                # Enable protected mode
+       movl    %eax, %cr0
+
+       /*
+        * At this point we're in long mode but in 32bit compatibility mode
+        * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
+        * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
+        * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+        */
+       ljmp    *(startup_64_vector - r_base)(%esi)
+
+       .code64
+       .balign 4
+startup_64:
+       # Now jump into the kernel using virtual addresses
+       movq    $secondary_startup_64, %rax
+       jmp     *%rax
+
+       .code16
+no_longmode:
+       hlt
+       jmp no_longmode
+#include "verify_cpu.S"
+
+       # Careful these need to be in the same 64K segment as the above;
+tidt:
+       .word   0                       # idt limit = 0
+       .word   0, 0                    # idt base = 0L
+
+       # Duplicate the global descriptor table
+       # so the kernel can live anywhere
+       .balign 4
+tgdt:
+       .short  tgdt_end - tgdt         # gdt limit
+       .long   tgdt - r_base
+       .short 0
+       .quad   0x00cf9b000000ffff      # __KERNEL32_CS
+       .quad   0x00af9b000000ffff      # __KERNEL_CS
+       .quad   0x00cf93000000ffff      # __KERNEL_DS
+tgdt_end:
+
+       .balign 4
+startup_32_vector:
+       .long   startup_32 - r_base
+       .word   __KERNEL32_CS, 0
+
+       .balign 4
+startup_64_vector:
+       .long   startup_64 - r_base
+       .word   __KERNEL_CS, 0
+
+trampoline_stack:
+       .org 0x1000
+trampoline_stack_end:
+ENTRY(trampoline_level4_pgt)
+       .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+       .fill   510,8,0
+       .quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
+
+ENTRY(trampoline_end)
diff --git a/kitten/arch/x86_64/kernel/verify_cpu.S b/kitten/arch/x86_64/kernel/verify_cpu.S
new file mode 100644 (file)
index 0000000..717b6e5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *
+ *     verify_cpu.S - Code for cpu long mode and SSE verification. This
+ *     code has been borrowed from boot/setup.S and was introduced by
+ *     Andi Kleen.
+ *
+ *     Copyright (c) 2007  Andi Kleen (ak@suse.de)
+ *     Copyright (c) 2007  Eric Biederman (ebiederm@xmission.com)
+ *     Copyright (c) 2007  Vivek Goyal (vgoyal@in.ibm.com)
+ *
+ *     This source code is licensed under the GNU General Public License,
+ *     Version 2.  See the file COPYING for more details.
+ *
+ *     This is a common code for verification whether CPU supports
+ *     long mode and SSE or not. It is not called directly instead this
+ *     file is included at various places and compiled in that context.
+ *     Following are the current usage.
+ *
+ *     This file is included by both 16bit and 32bit code.
+ *
+ *     arch/x86_64/boot/setup.S : Boot cpu verification (16bit)
+ *     arch/x86_64/boot/compressed/head.S: Boot cpu verification (32bit)
+ *     arch/x86_64/kernel/trampoline.S: secondary processor verfication (16bit)
+ *     arch/x86_64/kernel/acpi/wakeup.S:Verfication at resume (16bit)
+ *
+ *     verify_cpu, returns the status of cpu check in register %eax.
+ *             0: Success    1: Failure
+ *
+ *     The caller needs to check for the error code and take the action
+ *     appropriately. Either display a message or halt.
+ */
+
+#include <arch/cpufeature.h>
+
+verify_cpu:
+       pushfl                          # Save caller passed flags
+       pushl   $0                      # Kill any dangerous flags
+       popfl
+
+       /* minimum CPUID flags for x86-64 as defined by AMD */
+#define M(x) (1<<(x))
+#define M2(a,b) M(a)|M(b)
+#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d)
+
+#define SSE_MASK \
+       (M2(X86_FEATURE_XMM,X86_FEATURE_XMM2))
+#define REQUIRED_MASK1 \
+       (M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\
+        M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\
+        M(X86_FEATURE_FXSR))
+#define REQUIRED_MASK2 \
+       (M(X86_FEATURE_LM - 32))
+
+       pushfl                          # standard way to check for cpuid
+       popl    %eax
+       movl    %eax,%ebx
+       xorl    $0x200000,%eax
+       pushl   %eax
+       popfl
+       pushfl
+       popl    %eax
+       cmpl    %eax,%ebx
+       jz      verify_cpu_no_longmode  # cpu has no cpuid
+
+       movl    $0x0,%eax               # See if cpuid 1 is implemented
+       cpuid
+       cmpl    $0x1,%eax
+       jb      verify_cpu_no_longmode  # no cpuid 1
+
+       xor     %di,%di
+       cmpl    $0x68747541,%ebx        # AuthenticAMD
+       jnz     verify_cpu_noamd
+       cmpl    $0x69746e65,%edx
+       jnz     verify_cpu_noamd
+       cmpl    $0x444d4163,%ecx
+       jnz     verify_cpu_noamd
+       mov     $1,%di                  # cpu is from AMD
+
+verify_cpu_noamd:
+       movl    $0x1,%eax               # Does the cpu have what it takes
+       cpuid
+       andl    $REQUIRED_MASK1,%edx
+       xorl    $REQUIRED_MASK1,%edx
+       jnz     verify_cpu_no_longmode
+
+       movl    $0x80000000,%eax        # See if extended cpuid is implemented
+       cpuid
+       cmpl    $0x80000001,%eax
+       jb      verify_cpu_no_longmode  # no extended cpuid
+
+       movl    $0x80000001,%eax        # Does the cpu have what it takes
+       cpuid
+       andl    $REQUIRED_MASK2,%edx
+       xorl    $REQUIRED_MASK2,%edx
+       jnz     verify_cpu_no_longmode
+
+verify_cpu_sse_test:
+       movl    $1,%eax
+       cpuid
+       andl    $SSE_MASK,%edx
+       cmpl    $SSE_MASK,%edx
+       je      verify_cpu_sse_ok
+       test    %di,%di
+       jz      verify_cpu_no_longmode  # only try to force SSE on AMD
+       movl    $0xc0010015,%ecx        # HWCR
+       rdmsr
+       btr     $15,%eax                # enable SSE
+       wrmsr
+       xor     %di,%di                 # don't loop
+       jmp     verify_cpu_sse_test     # try again
+
+verify_cpu_no_longmode:
+       popfl                           # Restore caller passed flags
+       movl $1,%eax
+       ret
+verify_cpu_sse_ok:
+       popfl                           # Restore caller passed flags
+       xorl %eax, %eax
+       ret
diff --git a/kitten/arch/x86_64/kernel/vmlwk.lds.S b/kitten/arch/x86_64/kernel/vmlwk.lds.S
new file mode 100644 (file)
index 0000000..aae7584
--- /dev/null
@@ -0,0 +1,213 @@
+/* ld script to make x86-64 LWK kernel
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
+ */
+
+#define LOAD_OFFSET __START_KERNEL_map
+
+#include <arch-generic/vmlwk.lds.h>
+#include <arch/page.h>
+
+#undef i386    /* in case the preprocessor is a 32bit one */
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(phys_startup_64)
+_proxy_pda = 1;
+PHDRS {
+       text PT_LOAD FLAGS(5);  /* R_E */
+       data PT_LOAD FLAGS(7);  /* RWE */
+       user PT_LOAD FLAGS(7);  /* RWE */
+       data.init PT_LOAD FLAGS(7);     /* RWE */
+       note PT_NOTE FLAGS(4);  /* R__ */
+}
+SECTIONS
+{
+  . = __START_KERNEL;
+  phys_startup_64 = startup_64 - LOAD_OFFSET;
+  _text = .;                   /* Text and read-only data */
+  .text :  AT(ADDR(.text) - LOAD_OFFSET) {
+       /* First the code that has to be first for bootstrapping */
+       *(.bootstrap.text)
+       _stext = .;
+       /* Then the rest */
+       TEXT_TEXT
+       SCHED_TEXT
+       LOCK_TEXT
+       KPROBES_TEXT
+       *(.fixup)
+       *(.gnu.warning)
+       } :text = 0x9090
+                               /* out-of-line lock text */
+  .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
+
+  _etext = .;                  /* End of text section */
+
+  . = ALIGN(16);               /* Exception table */
+  __start___ex_table = .;
+  __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
+  __stop___ex_table = .;
+
+  BUG_TABLE
+
+  RODATA
+
+  . = ALIGN(PAGE_SIZE);        /* Align data segment to page size boundary */
+                               /* Data */
+  .data : AT(ADDR(.data) - LOAD_OFFSET) {
+       DATA_DATA
+       CONSTRUCTORS
+       } :data
+
+  _edata = .;                  /* End of data section */
+
+  . = ALIGN(PAGE_SIZE);
+  . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+       *(.data.cacheline_aligned)
+  }
+  . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES);
+  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
+       *(.data.read_mostly)
+  }
+
+#define VSYSCALL_ADDR (-10*1024*1024)
+#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+
+#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR)
+#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
+
+#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR)
+#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+
+  . = VSYSCALL_ADDR;
+  .vsyscall_0 :         AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user
+  __vsyscall_0 = VSYSCALL_VIRT_ADDR;
+
+  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
+               { *(.vsyscall_1) }
+
+  .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
+               { *(.vsyscall_2) }
+
+  .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3))
+               { *(.vsyscall_3) }
+
+  . = VSYSCALL_VIRT_ADDR + PAGE_SIZE;
+
+#undef VSYSCALL_ADDR
+#undef VSYSCALL_PHYS_ADDR
+#undef VSYSCALL_VIRT_ADDR
+#undef VLOAD_OFFSET
+#undef VLOAD
+#undef VVIRT_OFFSET
+#undef VVIRT
+
+  . = ALIGN(8192);             /* bootstrap_task */
+  .data.bootstrap_task : AT(ADDR(.data.bootstrap_task) - LOAD_OFFSET) {
+       *(.data.bootstrap_task)
+  }:data.init
+
+  . = ALIGN(4096);
+  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+       *(.data.page_aligned)
+  }
+
+  /* might get freed after init */
+  . = ALIGN(4096);
+  __smp_alt_begin = .;
+  __smp_alt_instructions = .;
+  .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
+       *(.smp_altinstructions)
+  }
+  __smp_alt_instructions_end = .;
+  . = ALIGN(8);
+  __smp_locks = .;
+  .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
+       *(.smp_locks)
+  }
+  __smp_locks_end = .;
+  .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
+       *(.smp_altinstr_replacement)
+  }
+  . = ALIGN(4096);
+  __smp_alt_end = .;
+
+  . = ALIGN(4096);             /* Init code and data */
+  __init_begin = .;
+  .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
+       _sinittext = .;
+       *(.init.text)
+       _einittext = .;
+  }
+  __initdata_begin = .;
+  .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
+  __initdata_end = .;
+  . = ALIGN(16);
+  __setup_start = .;
+  .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
+       INITCALLS
+  }
+  __initcall_end = .;
+  __con_initcall_start = .;
+  .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+       *(.con_initcall.init)
+  }
+  __con_initcall_end = .;
+  SECURITY_INIT
+  . = ALIGN(8);
+  __alt_instructions = .;
+  .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+       *(.altinstructions)
+  }
+  __alt_instructions_end = .; 
+  .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+       *(.altinstr_replacement)
+  }
+  /* .exit.text is discard at runtime, not link time, to deal with references
+     from .altinstructions and .eh_frame */
+  .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
+  .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
+  __initramfs_end = .;
+#endif
+
+  . = ALIGN(4096);
+  __per_cpu_start = .;
+  .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
+  __per_cpu_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
+  __bss_start = .;             /* BSS */
+  .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+       *(.bss.page_aligned)
+       *(.bss)
+       }
+  __bss_stop = .;
+
+  _end = . ;
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+       *(.exitcall.exit)
+       *(.eh_frame)
+       }
+
+  STABS_DEBUG
+
+  DWARF_DEBUG
+}
diff --git a/kitten/arch/x86_64/kernel/vsyscall.c b/kitten/arch/x86_64/kernel/vsyscall.c
new file mode 100644 (file)
index 0000000..c022ece
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Derived from Linux 2.6.25 linux-2.6.25/arch/x86/kernel/vsyscall.c
+ * Original header:
+ *  Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
+ *  Copyright 2003 Andi Kleen, SuSE Labs.
+ *
+ *  Thanks to hpa@transmeta.com for some useful hint.
+ *  Special thanks to Ingo Molnar for his early experience with
+ *  a different vsyscall implementation for Linux/IA32 and for the name.
+ *
+ *  vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
+ *  at virtual address -10Mbyte+1024bytes etc... There are at max 4
+ *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
+ *  jumping out of line if necessary. We cannot add more with this
+ *  mechanism because older kernels won't return -ENOSYS.
+ *  If we want more than four we need a vDSO.
+ *
+ *  Note: the concept clashes with user mode linux. If you use UML and
+ *  want per guest time just set the kernel.vsyscall64 sysctl to 0.
+ */
+
+#include <lwk/kernel.h>
+#include <lwk/init.h>
+#include <lwk/time.h>
+#include <lwk/unistd.h>
+#include <arch/vsyscall.h>
+#include <arch/pgtable.h>
+#include <arch/fixmap.h>
+
+#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
+#define __syscall_clobber "r11","cx","memory"
+
+int __vsyscall(0)
+vgettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       int ret;
+       asm volatile("syscall"
+               : "=a" (ret)
+               : "0" (__NR_gettimeofday),"D" (tv),"S" (tz)
+               : __syscall_clobber );
+       return ret;
+}
+
+time_t __vsyscall(1)
+vtime(time_t *t)
+{
+       int ret;
+       asm volatile("syscall"
+               : "=a" (ret)
+               : "0" (__NR_time),"D" (t)
+               : __syscall_clobber );
+       return ret;
+}
+
+void __init
+vsyscall_map(void)
+{
+       extern char __vsyscall_0;
+       unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
+
+       /* Setup the virtual syscall fixmap entry */
+       __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
+
+       BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
+
+       BUG_ON((unsigned long) &vgettimeofday !=
+                       VSYSCALL_ADDR(__NR_vgettimeofday));
+       BUG_ON((unsigned long) &vtime !=
+                       VSYSCALL_ADDR(__NR_vtime));
+}
+
diff --git a/kitten/arch/x86_64/kernel/xcall.c b/kitten/arch/x86_64/kernel/xcall.c
new file mode 100644 (file)
index 0000000..9afe497
--- /dev/null
@@ -0,0 +1,137 @@
+#include <lwk/kernel.h>
+#include <lwk/spinlock.h>
+#include <lwk/xcall.h>
+#include <arch/apic.h>
+#include <arch/idt_vectors.h>
+#include <arch/processor.h>
+
+/**
+ * Used to pass data to and synchronize the CPUs targeted by a cross-call.
+ */
+struct xcall_data_struct {
+       void            (*func)(void *info);
+       void *          info;
+       atomic_t        started;
+       atomic_t        finished;
+       bool            wait;
+};
+
+/**
+ * Global cross-call data pointer, protected by xcall_data_lock.
+ */
+static struct xcall_data_struct *xcall_data;
+static DEFINE_SPINLOCK(xcall_data_lock);
+
+/**
+ * x86_64 specific code for carrying out inter-CPU function calls. 
+ * This function should not be called directly. Call xcall_function() instead.
+ *
+ * Arguments:
+ *       [IN] cpu_mask: The target CPUs of the cross-call.
+ *       [IN] func:     The function to execute on each target CPU.
+ *       [IN] info:     Argument to pass to func().
+ *       [IN] wait:     true = wait for cross-call to fully complete.
+ *
+ * Returns:
+ *       Success: 0
+ *       Failure: Error code
+ */
+int
+arch_xcall_function(
+       cpumask_t       cpu_mask,
+       void            (*func)(void *info),
+       void *          info,
+       bool            wait
+)
+{
+       struct xcall_data_struct data;
+       unsigned int num_cpus;
+       unsigned int cpu;
+
+       BUG_ON(irqs_disabled());
+
+       /* Count how many CPUs are being targeted */
+       num_cpus = cpus_weight(cpu_mask);
+       if (!num_cpus)
+               return 0;
+
+       /* Fill in the xcall data structure on our stack */
+       data.func = func;
+       data.info = info;
+       atomic_set(&data.started, 0);
+       if (wait)
+               atomic_set(&data.finished, 0);
+       data.wait = wait;
+
+       /* Spin with IRQs enabled */
+       while (!spin_trylock_irq(&xcall_data_lock))
+               ;
+       /* IRQs are now disabled */
+
+       /* Set the global xcall data pointer */
+       xcall_data = &data;
+       wmb();
+
+       /* Send inter-processor interrupts to the target CPUs */
+       for_each_cpu_mask(cpu, cpu_mask)
+               lapic_send_ipi(cpu, XCALL_FUNCTION_VECTOR);
+
+       /* Wait for initiation responses */
+       while (atomic_read(&data.started) != num_cpus)
+               cpu_relax();
+
+       /* If requested, wait for completion responses */
+       if (wait) {
+               while (atomic_read(&data.finished) != num_cpus)
+                       cpu_relax();
+       }
+       spin_unlock_irq(&xcall_data_lock);
+
+       return 0;
+}
+
+/**
+ * The interrupt handler for inter-CPU function calls.
+ */
+void
+arch_xcall_function_interrupt(struct pt_regs *regs, unsigned int vector)
+{
+       void (*func)(void *info) = xcall_data->func;
+       void *info               = xcall_data->info;
+       int wait                 = xcall_data->wait;
+
+       /* Notify initiating CPU that we've started */
+       mb();
+       atomic_inc(&xcall_data->started);
+
+       /* Execute the cross-call function */
+       (*func)(info);
+
+       /* Notify initiating CPU that the cross-call function has completed */
+       if (wait) {
+               mb();
+               atomic_inc(&xcall_data->finished);
+       }
+}
+
+/**
+ * Sends a reschedule inter-processor interrupt to the target CPU.
+ * This causes the target CPU to call schedule().
+ */
+void
+arch_xcall_reschedule(id_t cpu)
+{
+       lapic_send_ipi(cpu, XCALL_RESCHEDULE_VECTOR);
+}
+
+/**
+ * The interrupt handler for inter-CPU reschedule calls.
+ */
+void
+arch_xcall_reschedule_interrupt(struct pt_regs *regs, unsigned int vector)
+{
+       /*
+        * Nothing to do, schedule() will be automatically
+        * called before returning to user-space
+        */
+}
diff --git a/kitten/arch/x86_64/lib/Makefile b/kitten/arch/x86_64/lib/Makefile
new file mode 100644 (file)
index 0000000..a7c7114
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Makefile for x86_64-specific library files.
+#
+lib-y += memmove.o memset.o memcpy.o thunk.o delay.o bitops.o extable.o copy_user.o usercopy.o getuser.o putuser.o
diff --git a/kitten/arch/x86_64/lib/bitops.c b/kitten/arch/x86_64/lib/bitops.c
new file mode 100644 (file)
index 0000000..ae58ed7
--- /dev/null
@@ -0,0 +1,175 @@
+#include <lwk/bitops.h>
+
+#undef find_first_zero_bit
+#undef find_next_zero_bit
+#undef find_first_bit
+#undef find_next_bit
+
+static inline long
+__find_first_zero_bit(const unsigned long * addr, unsigned long size)
+{
+       long d0, d1, d2;
+       long res;
+
+       /*
+        * We must test the size in words, not in bits, because
+        * otherwise incoming sizes in the range -63..-1 will not run
+        * any scasq instructions, and then the flags used by the je
+        * instruction will have whatever random value was in place
+        * before.  Nobody should call us like that, but
+        * find_next_zero_bit() does when offset and size are at the
+        * same word and it fails to find a zero itself.
+        */
+       size += 63;
+       size >>= 6;
+       if (!size)
+               return 0;
+       asm volatile(
+               "  repe; scasq\n"
+               "  je 1f\n"
+               "  xorq -8(%%rdi),%%rax\n"
+               "  subq $8,%%rdi\n"
+               "  bsfq %%rax,%%rdx\n"
+               "1:  subq %[addr],%%rdi\n"
+               "  shlq $3,%%rdi\n"
+               "  addq %%rdi,%%rdx"
+               :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+               :"0" (0ULL), "1" (size), "2" (addr), "3" (-1ULL),
+                [addr] "S" (addr) : "memory");
+       /*
+        * Any register would do for [addr] above, but GCC tends to
+        * prefer rbx over rsi, even though rsi is readily available
+        * and doesn't have to be saved.
+        */
+       return res;
+}
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+long find_first_zero_bit(const unsigned long * addr, unsigned long size)
+{
+       return __find_first_zero_bit (addr, size);
+}
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+long find_next_zero_bit (const unsigned long * addr, long size, long offset)
+{
+       const unsigned long * p = addr + (offset >> 6);
+       unsigned long set = 0;
+       unsigned long res, bit = offset&63;
+
+       if (bit) {
+               /*
+                * Look for zero in first word
+                */
+               asm("bsfq %1,%0\n\t"
+                   "cmoveq %2,%0"
+                   : "=r" (set)
+                   : "r" (~(*p >> bit)), "r"(64L));
+               if (set < (64 - bit))
+                       return set + offset;
+               set = 64 - bit;
+               p++;
+       }
+       /*
+        * No zero yet, search remaining full words for a zero
+        */
+       res = __find_first_zero_bit (p, size - 64 * (p - addr));
+
+       return (offset + set + res);
+}
+
+static inline long
+__find_first_bit(const unsigned long * addr, unsigned long size)
+{
+       long d0, d1;
+       long res;
+
+       /*
+        * We must test the size in words, not in bits, because
+        * otherwise incoming sizes in the range -63..-1 will not run
+        * any scasq instructions, and then the flags used by the jz
+        * instruction will have whatever random value was in place
+        * before.  Nobody should call us like that, but
+        * find_next_bit() does when offset and size are at the same
+        * word and it fails to find a one itself.
+        */
+       size += 63;
+       size >>= 6;
+       if (!size)
+               return 0;
+       asm volatile(
+               "   repe; scasq\n"
+               "   jz 1f\n"
+               "   subq $8,%%rdi\n"
+               "   bsfq (%%rdi),%%rax\n"
+               "1: subq %[addr],%%rdi\n"
+               "   shlq $3,%%rdi\n"
+               "   addq %%rdi,%%rax"
+               :"=a" (res), "=&c" (d0), "=&D" (d1)
+               :"0" (0ULL), "1" (size), "2" (addr),
+                [addr] "r" (addr) : "memory");
+       return res;
+}
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+long find_first_bit(const unsigned long * addr, unsigned long size)
+{
+       return __find_first_bit(addr,size);
+}
+
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+long find_next_bit(const unsigned long * addr, long size, long offset)
+{
+       const unsigned long * p = addr + (offset >> 6);
+       unsigned long set = 0, bit = offset & 63, res;
+
+       if (bit) {
+               /*
+                * Look for nonzero in the first 64 bits:
+                */
+               asm("bsfq %1,%0\n\t"
+                   "cmoveq %2,%0\n\t"
+                   : "=r" (set)
+                   : "r" (*p >> bit), "r" (64L));
+               if (set < (64 - bit))
+                       return set + offset;
+               set = 64 - bit;
+               p++;
+       }
+       /*
+        * No set bit yet, search remaining full words for a bit
+        */
+       res = __find_first_bit (p, size - 64 * (p - addr));
+       return (offset + set + res);
+}
+
+#include <lwk/linux_compat.h>
+
+EXPORT_SYMBOL(find_next_bit);
+EXPORT_SYMBOL(find_first_bit);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/kitten/arch/x86_64/lib/copy_user.S b/kitten/arch/x86_64/lib/copy_user.S
new file mode 100644 (file)
index 0000000..fa5379c
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright 2002 Andi Kleen, SuSE Labs.
+ * Subject to the GNU Public License v2.
+ * 
+ * Functions to copy from and to user space.           
+ */             
+
+#include <lwk/linkage.h>
+#include <arch/dwarf2.h>
+
+#include <arch/current.h>
+#include <arch/asm-offsets.h>
+
+/* Standard copy_to_user with segment limit checking */                
+ENTRY(copy_to_user)
+       CFI_STARTPROC
+       GET_CURRENT(%rax)
+       movq %rdi,%rcx
+       addq %rdx,%rcx
+       jc  bad_to_user
+       cmpq tsk_arch_addr_limit(%rax),%rcx
+       jae bad_to_user
+       xorl %eax,%eax  /* clear zero flag */
+       jmp copy_user_generic_string
+       CFI_ENDPROC
+
+ENTRY(copy_user_generic)
+       CFI_STARTPROC
+       movl $1,%ecx    /* set zero flag */
+       jmp copy_user_generic_string
+       CFI_ENDPROC
+
+ENTRY(__copy_from_user_inatomic)
+       CFI_STARTPROC
+       xorl %ecx,%ecx  /* clear zero flag */
+       jmp copy_user_generic_string
+       CFI_ENDPROC
+
+/* Standard copy_from_user with segment limit checking */      
+ENTRY(copy_from_user)
+       CFI_STARTPROC
+       GET_CURRENT(%rax)
+       movq %rsi,%rcx
+       addq %rdx,%rcx
+       jc  bad_from_user
+       cmpq tsk_arch_addr_limit(%rax),%rcx
+       jae  bad_from_user
+       movl $1,%ecx    /* set zero flag */
+       jmp copy_user_generic_string
+       CFI_ENDPROC
+ENDPROC(copy_from_user)
+       
+       .section .fixup,"ax"
+       /* must zero dest */
+bad_from_user:
+       CFI_STARTPROC
+       movl %edx,%ecx
+       xorl %eax,%eax
+       rep
+       stosb
+bad_to_user:
+       movl    %edx,%eax
+       ret
+       CFI_ENDPROC
+END(bad_from_user)
+       .previous
+       
+               
+ /* rdi        destination
+  * rsi source
+  * rdx count
+  * ecx zero flag
+  *
+  * Output:
+  * eax uncopied bytes or 0 if successfull.
+  *
+  * Only 4GB of copy is supported. This shouldn't be a problem
+  * because the kernel normally only writes from/to page sized chunks
+  * even if user space passed a longer buffer.
+  * And more would be dangerous because both Intel and AMD have
+  * errata with rep movsq > 4GB. If someone feels the need to fix
+  * this please consider this.
+  */
+ENTRY(copy_user_generic_string)
+       CFI_STARTPROC
+       movl %ecx,%r8d          /* save zero flag */
+       movl %edx,%ecx
+       shrl $3,%ecx
+       andl $7,%edx    
+       jz   10f
+1:     rep 
+       movsq 
+       movl %edx,%ecx
+2:     rep
+       movsb
+9:     movl %ecx,%eax
+       ret
+
+       /* multiple of 8 byte */
+10:    rep
+       movsq
+       xor %eax,%eax
+       ret
+
+       /* exception handling */
+3:      lea (%rdx,%rcx,8),%rax /* exception on quad loop */
+       jmp 6f
+5:     movl %ecx,%eax          /* exception on byte loop */
+       /* eax: left over bytes */
+6:     testl %r8d,%r8d         /* zero flag set? */
+       jz 7f
+       movl %eax,%ecx          /* initialize x86 loop counter */
+       push %rax
+       xorl %eax,%eax
+8:     rep
+       stosb                   /* zero the rest */
+11:    pop %rax
+7:     ret
+       CFI_ENDPROC
+END(copy_user_generic_c)
+
+       .section __ex_table,"a"
+       .quad 1b,3b
+       .quad 2b,5b
+       .quad 8b,11b
+       .quad 10b,3b
+       .previous
diff --git a/kitten/arch/x86_64/lib/delay.c b/kitten/arch/x86_64/lib/delay.c
new file mode 100644 (file)
index 0000000..d74e060
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *     Precise Delay Loops for x86-64
+ *
+ *     Copyright (C) 1993 Linus Torvalds
+ *     Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ *     The __delay function must _NOT_ be inlined as its execution time
+ *     depends wildly on alignment on many x86 processors. 
+ */
+
+#include <lwk/smp.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/delay.h>
+#include <arch/msr.h>
+#include <arch/processor.h>
+#include <arch/smp.h>
+
+void __delay(unsigned long cycles)
+{
+       unsigned bclock, now;
+       
+       rdtscl(bclock);
+       do
+       {
+               rep_nop(); 
+               rdtscl(now);
+       }
+       while((now-bclock) < cycles);
+}
+
+inline void __const_udelay(unsigned long xsecs)
+{
+       __delay(
+         (xsecs * cpu_info[this_cpu].arch.tsc_khz * 1000)  /* cycles * 2**32 */
+         >> 32                                             /* div by 2**32 */
+       );
+}
+
+void __udelay(unsigned long usecs)
+{
+       __const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
+}
+
+void __ndelay(unsigned long nsecs)
+{
+       __const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+}
+
diff --git a/kitten/arch/x86_64/lib/extable.c b/kitten/arch/x86_64/lib/extable.c
new file mode 100644 (file)
index 0000000..8956ea6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * lwk/arch/x86_64/lib/extable.c
+ */
+
+#include <lwk/stddef.h>
+#include <lwk/extable.h>
+
+/* Simple binary search */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+              const struct exception_table_entry *last,
+              unsigned long value)
+{
+       /* Work around a B stepping K8 bug */
+       if ((value >> 32) == 0)
+               value |= 0xffffffffUL << 32; 
+
+        while (first <= last) {
+               const struct exception_table_entry *mid;
+               long diff;
+
+               mid = (last - first) / 2 + first;
+               diff = mid->insn - value;
+                if (diff == 0)
+                        return mid;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return NULL;
+}
diff --git a/kitten/arch/x86_64/lib/getuser.S b/kitten/arch/x86_64/lib/getuser.S
new file mode 100644 (file)
index 0000000..b8ceb88
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * __get_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
+ */
+
+/*
+ * __get_user_X
+ *
+ * Inputs:     %rcx contains the address.
+ *             The register is modified, but all changes are undone
+ *             before returning because the C code doesn't know about it.
+ *
+ * Outputs:    %rax is error code (0 or -EFAULT)
+ *             %rdx contains zero-extended value
+ * 
+ * %r8 is destroyed.
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#include <lwk/linkage.h>
+#include <arch/dwarf2.h>
+#include <arch/page.h>
+#include <arch/errno.h>
+#include <arch/asm-offsets.h>
+#include <arch/current.h>
+
+       .text
+ENTRY(__get_user_1)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae bad_get_user
+1:     movzb (%rcx),%edx
+       xorl %eax,%eax
+       ret
+       CFI_ENDPROC
+ENDPROC(__get_user_1)
+
+ENTRY(__get_user_2)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       addq $1,%rcx
+       jc 20f
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae 20f
+       decq   %rcx
+2:     movzwl (%rcx),%edx
+       xorl %eax,%eax
+       ret
+20:    decq    %rcx
+       jmp     bad_get_user
+       CFI_ENDPROC
+ENDPROC(__get_user_2)
+
+ENTRY(__get_user_4)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       addq $3,%rcx
+       jc 30f
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae 30f
+       subq $3,%rcx
+3:     movl (%rcx),%edx
+       xorl %eax,%eax
+       ret
+30:    subq $3,%rcx
+       jmp bad_get_user
+       CFI_ENDPROC
+ENDPROC(__get_user_4)
+
+ENTRY(__get_user_8)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       addq $7,%rcx
+       jc 40f
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae     40f
+       subq    $7,%rcx
+4:     movq (%rcx),%rdx
+       xorl %eax,%eax
+       ret
+40:    subq $7,%rcx
+       jmp bad_get_user
+       CFI_ENDPROC
+ENDPROC(__get_user_8)
+
+bad_get_user:
+       CFI_STARTPROC
+       xorl %edx,%edx
+       movq $(-EFAULT),%rax
+       ret
+       CFI_ENDPROC
+END(bad_get_user)
+
+.section __ex_table,"a"
+       .quad 1b,bad_get_user
+       .quad 2b,bad_get_user
+       .quad 3b,bad_get_user
+       .quad 4b,bad_get_user
+.previous
diff --git a/kitten/arch/x86_64/lib/memcpy.S b/kitten/arch/x86_64/lib/memcpy.S
new file mode 100644 (file)
index 0000000..aa333e4
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright 2002 Andi Kleen */
+       
+       #include <arch/cpufeature.h>            
+/*
+ * memcpy - Copy a memory block.
+ *
+ * Input:      
+ * rdi destination
+ * rsi source
+ * rdx count
+ * 
+ * Output:
+ * rax original destination
+ */    
+
+       .globl __memcpy
+       .globl memcpy
+       .p2align 4
+__memcpy:
+memcpy:                
+       pushq %rbx
+       movq %rdi,%rax
+
+       movl %edx,%ecx
+       shrl $6,%ecx
+       jz .Lhandle_tail
+
+       .p2align 4
+.Lloop_64:
+       decl %ecx
+
+       movq (%rsi),%r11
+       movq 8(%rsi),%r8
+
+       movq %r11,(%rdi)
+       movq %r8,1*8(%rdi)
+
+       movq 2*8(%rsi),%r9
+       movq 3*8(%rsi),%r10
+
+       movq %r9,2*8(%rdi)
+       movq %r10,3*8(%rdi)
+
+       movq 4*8(%rsi),%r11
+       movq 5*8(%rsi),%r8
+
+       movq %r11,4*8(%rdi)
+       movq %r8,5*8(%rdi)
+
+       movq 6*8(%rsi),%r9
+       movq 7*8(%rsi),%r10
+
+       movq %r9,6*8(%rdi)
+       movq %r10,7*8(%rdi)
+
+       leaq 64(%rsi),%rsi
+       leaq 64(%rdi),%rdi
+       jnz  .Lloop_64
+
+.Lhandle_tail:
+       movl %edx,%ecx
+       andl $63,%ecx
+       shrl $3,%ecx
+       jz   .Lhandle_7
+       .p2align 4
+.Lloop_8:
+       decl %ecx
+       movq (%rsi),%r8
+       movq %r8,(%rdi)
+       leaq 8(%rdi),%rdi
+       leaq 8(%rsi),%rsi
+       jnz  .Lloop_8
+
+.Lhandle_7:
+       movl %edx,%ecx
+       andl $7,%ecx
+       jz .Lende
+       .p2align 4
+.Lloop_1:
+       movb (%rsi),%r8b
+       movb %r8b,(%rdi)
+       incq %rdi
+       incq %rsi
+       decl %ecx
+       jnz .Lloop_1
+
+.Lende:
+       popq %rbx
+       ret
+.Lfinal:
+
+       /* Some CPUs run faster using the string copy instructions.
+          It is also a lot simpler. Use this when possible */
+
+       .section .altinstructions,"a"
+       .align 8
+       .quad  memcpy
+       .quad  memcpy_c
+       .byte  X86_FEATURE_REP_GOOD
+       .byte  .Lfinal-memcpy
+       .byte  memcpy_c_end-memcpy_c
+       .previous
+
+       .section .altinstr_replacement,"ax"
+ /* rdi        destination
+  * rsi source
+  * rdx count
+  */
+memcpy_c:
+       movq %rdi,%rax
+       movl %edx,%ecx
+       shrl $3,%ecx
+       andl $7,%edx    
+       rep 
+       movsq 
+       movl %edx,%ecx
+       rep
+       movsb
+       ret
+memcpy_c_end:
+       .previous
diff --git a/kitten/arch/x86_64/lib/memmove.c b/kitten/arch/x86_64/lib/memmove.c
new file mode 100644 (file)
index 0000000..a3e6e93
--- /dev/null
@@ -0,0 +1,19 @@
+/* Normally compiler builtins are used, but sometimes the compiler calls out
+   of line code. Based on asm-i386/string.h.
+ */
+#define _STRING_C
+#include <lwk/string.h>
+
+#undef memmove
+void *memmove(void * dest, const void *src, size_t count)
+{
+       if (dest < src) { 
+               __inline_memcpy(dest,src,count);
+       } else {
+               char *p = (char *) dest + count;
+               char *s = (char *) src + count;
+               while (count--)
+                       *--p = *--s;
+       }
+       return dest;
+} 
diff --git a/kitten/arch/x86_64/lib/memset.c b/kitten/arch/x86_64/lib/memset.c
new file mode 100644 (file)
index 0000000..26de799
--- /dev/null
@@ -0,0 +1,14 @@
+/* Normally compiler builtins are used, but sometimes the compiler calls out
+   of line code. Based on asm-i386/string.h.
+ */
+#define _STRING_C
+#include <lwk/string.h>
+
+#undef memset
+void *memset(void *dest, int c, size_t count)
+{
+       char *p = (char *) dest + count;
+       while (count--)
+               *--p = c;
+       return dest;
+} 
diff --git a/kitten/arch/x86_64/lib/putuser.S b/kitten/arch/x86_64/lib/putuser.S
new file mode 100644 (file)
index 0000000..7b5de15
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * __put_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
+ */
+
+/*
+ * __put_user_X
+ *
+ * Inputs:     %rcx contains the address
+ *             %rdx contains new value
+ *
+ * Outputs:    %rax is error code (0 or -EFAULT)
+ *
+ * %r8 is destroyed.
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#include <lwk/linkage.h>
+#include <arch/dwarf2.h>
+#include <arch/page.h>
+#include <arch/errno.h>
+#include <arch/asm-offsets.h>
+#include <arch/current.h>
+
+       .text
+ENTRY(__put_user_1)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae bad_put_user
+1:     movb %dl,(%rcx)
+       xorl %eax,%eax
+       ret
+       CFI_ENDPROC
+ENDPROC(__put_user_1)
+
+ENTRY(__put_user_2)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       addq $1,%rcx
+       jc 20f
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae 20f
+       decq %rcx
+2:     movw %dx,(%rcx)
+       xorl %eax,%eax
+       ret
+20:    decq %rcx
+       jmp bad_put_user
+       CFI_ENDPROC
+ENDPROC(__put_user_2)
+
+ENTRY(__put_user_4)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       addq $3,%rcx
+       jc 30f
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae 30f
+       subq $3,%rcx
+3:     movl %edx,(%rcx)
+       xorl %eax,%eax
+       ret
+30:    subq $3,%rcx
+       jmp bad_put_user
+       CFI_ENDPROC
+ENDPROC(__put_user_4)
+
+ENTRY(__put_user_8)
+       CFI_STARTPROC
+       GET_CURRENT(%r8)
+       addq $7,%rcx
+       jc 40f
+       cmpq tsk_arch_addr_limit(%r8),%rcx
+       jae 40f
+       subq $7,%rcx
+4:     movq %rdx,(%rcx)
+       xorl %eax,%eax
+       ret
+40:    subq $7,%rcx
+       jmp bad_put_user
+       CFI_ENDPROC
+ENDPROC(__put_user_8)
+
+bad_put_user:
+       CFI_STARTPROC
+       movq $(-EFAULT),%rax
+       ret
+       CFI_ENDPROC
+END(bad_put_user)
+
+.section __ex_table,"a"
+       .quad 1b,bad_put_user
+       .quad 2b,bad_put_user
+       .quad 3b,bad_put_user
+       .quad 4b,bad_put_user
+.previous
diff --git a/kitten/arch/x86_64/lib/thunk.S b/kitten/arch/x86_64/lib/thunk.S
new file mode 100644 (file)
index 0000000..802cdff
--- /dev/null
@@ -0,0 +1,93 @@
+       /*
+        * Save registers before calling assembly functions. This avoids
+        * disturbance of register allocation in some inline assembly constructs.
+        * Copyright 2001,2002 by Andi Kleen, SuSE Labs.
+        * Subject to the GNU public license, v.2. No warranty of any kind.
+        * $Id: thunk.S,v 1.2 2002/03/13 20:06:58 ak Exp $
+        */
+
+       #include <lwk/linkage.h>
+       #include <arch/dwarf2.h>
+       #include <arch/calling.h>                       
+       #include <arch/rwlock.h>
+               
+       /* rdi: arg1 ... normal C conventions. rax is saved/restored. */        
+       .macro thunk name,func
+       .globl \name
+\name: 
+       CFI_STARTPROC
+       SAVE_ARGS
+       call \func
+       jmp  restore
+       CFI_ENDPROC
+       .endm
+
+       /* rdi: arg1 ... normal C conventions. rax is passed from C. */         
+       .macro thunk_retrax name,func
+       .globl \name
+\name: 
+       CFI_STARTPROC
+       SAVE_ARGS
+       call \func
+       jmp  restore_norax
+       CFI_ENDPROC
+       .endm
+       
+
+#if 0
+       .section .sched.text
+#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
+       thunk rwsem_down_read_failed_thunk,rwsem_down_read_failed
+       thunk rwsem_down_write_failed_thunk,rwsem_down_write_failed
+       thunk rwsem_wake_thunk,rwsem_wake
+       thunk rwsem_downgrade_thunk,rwsem_downgrade_wake
+#endif 
+       
+       thunk __down_failed,__down
+       thunk_retrax __down_failed_interruptible,__down_interruptible
+       thunk_retrax __down_failed_trylock,__down_trylock
+       thunk __up_wakeup,__up
+#endif
+       
+       /* SAVE_ARGS below is used only for the .cfi directives it contains. */
+       CFI_STARTPROC
+       SAVE_ARGS
+restore:
+       RESTORE_ARGS
+       ret     
+       CFI_ENDPROC
+       
+       CFI_STARTPROC
+       SAVE_ARGS
+restore_norax: 
+       RESTORE_ARGS 1
+       ret
+       CFI_ENDPROC
+
+/* Support for read/write spinlocks. */
+       .text
+/* rax:        pointer to rwlock_t */  
+ENTRY(__write_lock_failed)
+       lock
+       addl $RW_LOCK_BIAS,(%rax)
+1:     rep
+       nop
+       cmpl $RW_LOCK_BIAS,(%rax)
+       jne 1b
+       lock 
+       subl $RW_LOCK_BIAS,(%rax)
+       jnz  __write_lock_failed
+       ret
+
+/* rax:        pointer to rwlock_t */  
+ENTRY(__read_lock_failed)
+       lock
+       incl (%rax)
+1:     rep
+       nop
+       cmpl $1,(%rax)
+       js 1b
+       lock
+       decl (%rax)
+       js __read_lock_failed
+       ret
diff --git a/kitten/arch/x86_64/lib/usercopy.c b/kitten/arch/x86_64/lib/usercopy.c
new file mode 100644 (file)
index 0000000..d92277b
--- /dev/null
@@ -0,0 +1,155 @@
+/* 
+ * User address space access functions.
+ *
+ * Copyright 1997 Andi Kleen <ak@muc.de>
+ * Copyright 1997 Linus Torvalds
+ * Copyright 2002 Andi Kleen <ak@suse.de>
+ */
+#include <arch/uaccess.h>
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+#define __do_strncpy_from_user(dst,src,count,res)                         \
+do {                                                                      \
+       long __d0, __d1, __d2;                                             \
+       __asm__ __volatile__(                                              \
+               "       testq %1,%1\n"                                     \
+               "       jz 2f\n"                                           \
+               "0:     lodsb\n"                                           \
+               "       stosb\n"                                           \
+               "       testb %%al,%%al\n"                                 \
+               "       jz 1f\n"                                           \
+               "       decq %1\n"                                         \
+               "       jnz 0b\n"                                          \
+               "1:     subq %1,%0\n"                                      \
+               "2:\n"                                                     \
+               ".section .fixup,\"ax\"\n"                                 \
+               "3:     movq %5,%0\n"                                      \
+               "       jmp 2b\n"                                          \
+               ".previous\n"                                              \
+               ".section __ex_table,\"a\"\n"                              \
+               "       .align 8\n"                                        \
+               "       .quad 0b,3b\n"                                     \
+               ".previous"                                                \
+               : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),      \
+                 "=&D" (__d2)                                             \
+               : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
+               : "memory");                                               \
+} while (0)
+
+long
+__strncpy_from_user(char *dst, const char __user *src, long count)
+{
+       long res;
+       __do_strncpy_from_user(dst, src, count, res);
+       return res;
+}
+
+long
+strncpy_from_user(char *dst, const char __user *src, long count)
+{
+       long res = -EFAULT;
+       if (access_ok(VERIFY_READ, src, 1))
+               return __strncpy_from_user(dst, src, count);
+       return res;
+}
+
+/*
+ * Zero Userspace
+ */
+
+unsigned long __clear_user(void __user *addr, unsigned long size)
+{
+       long __d0;
+       /* no memory constraint because it doesn't change any memory gcc knows
+          about */
+       asm volatile(
+               "       testq  %[size8],%[size8]\n"
+               "       jz     4f\n"
+               "0:     movq %[zero],(%[dst])\n"
+               "       addq   %[eight],%[dst]\n"
+               "       decl %%ecx ; jnz   0b\n"
+               "4:     movq  %[size1],%%rcx\n"
+               "       testl %%ecx,%%ecx\n"
+               "       jz     2f\n"
+               "1:     movb   %b[zero],(%[dst])\n"
+               "       incq   %[dst]\n"
+               "       decl %%ecx ; jnz  1b\n"
+               "2:\n"
+               ".section .fixup,\"ax\"\n"
+               "3:     lea 0(%[size1],%[size8],8),%[size8]\n"
+               "       jmp 2b\n"
+               ".previous\n"
+               ".section __ex_table,\"a\"\n"
+               "       .align 8\n"
+               "       .quad 0b,3b\n"
+               "       .quad 1b,2b\n"
+               ".previous"
+               : [size8] "=c"(size), [dst] "=&D" (__d0)
+               : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
+                 [zero] "r" (0UL), [eight] "r" (8UL));
+       return size;
+}
+
+unsigned long clear_user(void __user *to, unsigned long n)
+{
+       if (access_ok(VERIFY_WRITE, to, n))
+               return __clear_user(to, n);
+       return n;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+
+long __strnlen_user(const char __user *s, long n)
+{
+       long res = 0;
+       char c;
+
+       while (1) {
+               if (res>n)
+                       return n+1;
+               if (__get_user(c, s))
+                       return 0;
+               if (!c)
+                       return res+1;
+               res++;
+               s++;
+       }
+}
+
+long strnlen_user(const char __user *s, long n)
+{
+       if (!access_ok(VERIFY_READ, s, n))
+               return 0;
+       return __strnlen_user(s, n);
+}
+
+long strlen_user(const char __user *s)
+{
+       long res = 0;
+       char c;
+
+       for (;;) {
+               if (get_user(c, s))
+                       return 0;
+               if (!c)
+                       return res+1;
+               res++;
+               s++;
+       }
+}
+
+unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
+{
+       if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { 
+               return copy_user_generic((__force void *)to, (__force void *)from, len);
+       } 
+       return len;             
+}
+
diff --git a/kitten/arch/x86_64/mm/Makefile b/kitten/arch/x86_64/mm/Makefile
new file mode 100644 (file)
index 0000000..f3ac82a
--- /dev/null
@@ -0,0 +1 @@
+obj-y := init.o fault.o phys_addr.o aspace.o
diff --git a/kitten/arch/x86_64/mm/aspace.c b/kitten/arch/x86_64/mm/aspace.c
new file mode 100644 (file)
index 0000000..4078bf5
--- /dev/null
@@ -0,0 +1,449 @@
+/* Copyright (c) 2007,2008 Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/aspace.h>
+#include <lwk/task.h>
+#include <lwk/init_task.h>
+#include <arch/page.h>      /* TODO: remove */
+#include <arch/pgtable.h>   /* TODO: remove */
+#include <arch/page_table.h>
+
+
+/**
+ * Architecture specific address space initialization. This allocates a new
+ * page table root for the aspace and copies the kernel page tables into it.
+ */
+int
+arch_aspace_create(
+       struct aspace * aspace
+)
+{
+       unsigned int i;
+
+       /* Allocate a root page table for the address space */
+       if ((aspace->arch.pgd = kmem_get_pages(0)) == NULL)
+               return -ENOMEM;
+       
+       /* Copy the current kernel page tables into the address space */
+       for (i = pgd_index(PAGE_OFFSET); i < PTRS_PER_PGD; i++)
+               aspace->arch.pgd[i] = bootstrap_task.aspace->arch.pgd[i];
+
+       return 0;
+}
+
+
+/**
+ * Architecture specific address space destruction. This frees all page table
+ * memory that the aspace was using.
+ */
+void
+arch_aspace_destroy(
+       struct aspace * aspace
+)
+{
+       unsigned int i, j, k;
+
+       xpte_t *pgd;    /* Page Global Directory: level 0 (root of tree) */
+       xpte_t *pud;    /* Page Upper Directory:  level 1 */
+       xpte_t *pmd;    /* Page Middle Directory: level 2 */
+       xpte_t *ptd;    /* Page Table Directory:  level 3 */
+
+       /* Walk and then free the Page Global Directory */
+       pgd = aspace->arch.pgd;
+       for (i = 0; i < pgd_index(PAGE_OFFSET); i++) {
+               if (!pgd[i].present)
+                       continue;
+
+               /* Walk and then free the Page Upper Directory */
+               pud = __va(pgd[i].base_paddr << 12);
+               for (j = 0; j < 512; j++) {
+                       if (!pud[j].present || pud[j].pagesize)
+                               continue;
+
+                       /* Walk and then free the Page Middle Directory */
+                       pmd = __va(pud[j].base_paddr << 12);
+                       for (k = 0; k < 512; k++) {
+                               if (!pmd[k].present || pmd[k].pagesize)
+                                       continue;
+                               
+                               /* Free the last level Page Table Directory */
+                               ptd = __va(pmd[k].base_paddr << 12);
+                               kmem_free_pages(ptd, 0);
+                       }
+                       kmem_free_pages(pmd, 0);
+               }
+               kmem_free_pages(pud, 0);
+       }
+       kmem_free_pages(pgd, 0);
+}
+
+
+/**
+ * Loads the address space object's root page table pointer into the calling
+ * CPU's CR3 register, causing the aspace to become active.
+ */
+void
+arch_aspace_activate(
+       struct aspace * aspace
+)
+{
+       asm volatile(
+               "movq %0,%%cr3" :: "r" (__pa(aspace->arch.pgd)) : "memory"
+       );
+}
+
+
+/**
+ * Allocates a new page table and links it to a parent page table entry.
+ */
+static xpte_t *
+alloc_page_table(
+       xpte_t *        parent_pte
+)
+{
+       xpte_t *new_table;
+
+       new_table = kmem_get_pages(0);
+       if (!new_table)
+               return NULL;
+       
+       if (parent_pte) {
+               xpte_t _pte;
+
+               memset(&_pte, 0, sizeof(_pte));
+               _pte.present     = 1;
+               _pte.write       = 1;
+               _pte.user        = 1;
+               _pte.base_paddr  = __pa(new_table) >> 12;
+
+               *parent_pte = _pte;
+       }
+
+       return new_table;
+}
+
+
+/**
+ * Locates an existing page table entry or creates a new one if none exists.
+ * Returns a pointer to the page table entry.
+ */
+static xpte_t *
+find_or_create_pte(
+       struct aspace * aspace,
+       vaddr_t         vaddr,
+       vmpagesize_t    pagesz
+)
+{
+       xpte_t *pgd;    /* Page Global Directory: level 0 (root of tree) */
+       xpte_t *pud;    /* Page Upper Directory:  level 1 */
+       xpte_t *pmd;    /* Page Middle Directory: level 2 */
+       xpte_t *ptd;    /* Page Table Directory:  level 3 */
+
+       xpte_t *pge;    /* Page Global Directory Entry */
+       xpte_t *pue;    /* Page Upper Directory Entry */
+       xpte_t *pme;    /* Page Middle Directory Entry */
+       xpte_t *pte;    /* Page Table Directory Entry */
+
+       /* Calculate indices into above directories based on vaddr specified */
+       const unsigned int pgd_index = (vaddr >> 39) & 0x1FF;
+       const unsigned int pud_index = (vaddr >> 30) & 0x1FF;
+       const unsigned int pmd_index = (vaddr >> 21) & 0x1FF;
+       const unsigned int ptd_index = (vaddr >> 12) & 0x1FF;
+
+       /* Traverse the Page Global Directory */
+       pgd = aspace->arch.pgd;
+       pge = &pgd[pgd_index];
+       if (!pge->present && !alloc_page_table(pge))
+               return NULL;
+
+       /* Traverse the Page Upper Directory */
+       pud = __va(pge->base_paddr << 12);
+       pue = &pud[pud_index];
+       if (pagesz == VM_PAGE_1GB)
+               return pue;
+       else if (!pue->present && !alloc_page_table(pue))
+               return NULL;
+       else if (pue->pagesize)
+               panic("BUG: Can't follow PUD entry, pagesize bit set.");
+
+       /* Traverse the Page Middle Directory */
+       pmd = __va(pue->base_paddr << 12);
+       pme = &pmd[pmd_index];
+       if (pagesz == VM_PAGE_2MB)
+               return pme;
+       else if (!pme->present && !alloc_page_table(pme))
+               return NULL;
+       else if (pme->pagesize)
+               panic("BUG: Can't follow PMD entry, pagesize bit set.");
+
+       /* Traverse the Page Table Entry Directory */
+       ptd = __va(pme->base_paddr << 12);
+       pte = &ptd[ptd_index];
+       return pte;
+}
+
+
+/**
+ * Examines a page table to determine if it has any active entries. If not,
+ * the page table is freed.
+ */
+static int
+try_to_free_table(
+       xpte_t *        table,
+       xpte_t *        parent_pte
+)
+{
+       int i;
+
+       /* Determine if the table can be freed */
+       for (i = 0; i < 512; i++) {
+               if (table[i].present)
+                       return -1; /* Nope */
+       }
+
+       /* Yup, free the page table */
+       kmem_free_pages(table, 0);
+       memset(parent_pte, 0, sizeof(xpte_t));
+       return 0;
+}
+
+
+/**
+ * Zeros a page table entry. If the page table that the PTE was in becomes
+ * empty (contains no active mappings), it is freed. Page table freeing
+ * continues up to the top of the page table tree (e.g., a single call may
+ * result in a PTD, PMD, and PUD being freed; the PGD is never freed by this
+ * function).
+ */
+static void
+find_and_delete_pte(
+       struct aspace * aspace,
+       vaddr_t         vaddr,
+       vmpagesize_t    pagesz
+)
+{
+       xpte_t *pgd;    /* Page Global Directory: level 0 (root of tree) */
+       xpte_t *pud;    /* Page Upper Directory:  level 1 */
+       xpte_t *pmd;    /* Page Middle Directory: level 2 */
+       xpte_t *ptd;    /* Page Table Directory:  level 3 */
+
+       xpte_t *pge;    /* Page Global Directory Entry */
+       xpte_t *pue;    /* Page Upper Directory Entry */
+       xpte_t *pme;    /* Page Middle Directory Entry */
+       xpte_t *pte;    /* Page Table Directory Entry */
+
+       /* Calculate indices into above directories based on vaddr specified */
+       const unsigned int pgd_index = (vaddr >> 39) & 0x1FF;
+       const unsigned int pud_index = (vaddr >> 30) & 0x1FF;
+       const unsigned int pmd_index = (vaddr >> 21) & 0x1FF;
+       const unsigned int ptd_index = (vaddr >> 12) & 0x1FF;
+
+       /* Traverse the Page Global Directory */
+       pgd = aspace->arch.pgd;
+       pge = &pgd[pgd_index];
+       if (!pge->present)
+               return;
+
+       /* Traverse the Page Upper Directory */
+       pud = __va(pge->base_paddr << 12);
+       pue = &pud[pud_index];
+       if (!pue->present) {
+               return;
+       } else if (pagesz == VM_PAGE_1GB) {
+               if (!pue->pagesize)
+                       panic("BUG: 1GB PTE has child page table attached.\n");
+
+               /* Unmap the 1GB page that this PTE was mapping */
+               memset(pue, 0, sizeof(xpte_t));
+
+               /* Try to free PUD that the PTE was in */
+               try_to_free_table(pud, pge);
+               return;
+       }
+
+       /* Traverse the Page Middle Directory */
+       pmd = __va(pue->base_paddr << 12);
+       pme = &pmd[pmd_index];
+       if (!pme->present) {
+               return;
+       } else if (pagesz == VM_PAGE_2MB) {
+               if (!pme->pagesize)
+                       panic("BUG: 2MB PTE has child page table attached.\n");
+
+               /* Unmap the 2MB page that this PTE was mapping */
+               memset(pme, 0, sizeof(xpte_t));
+
+               /* Try to free the PMD that the PTE was in */
+               if (try_to_free_table(pmd, pue))
+                       return;  /* nope, couldn't free it */
+
+               /* Try to free the PUD that contained the PMD just freed */
+               try_to_free_table(pud, pge);
+               return;
+       }
+
+       /* Traverse the Page Table Entry Directory */
+       ptd = __va(pme->base_paddr << 12);
+       pte = &ptd[ptd_index];
+       if (pte->present) {
+               return;
+       } else {
+               /* Unmap the 4KB page that this PTE was mapping */
+               memset(pme, 0, sizeof(xpte_t));
+
+               /* Try to free the PTD that the PTE was in */
+               if (try_to_free_table(ptd, pme))
+                       return;  /* nope, couldn't free it */
+
+               /* Try to free the PMD that contained the PTD just freed */
+               if (try_to_free_table(pmd, pue))
+                       return;  /* nope, couldn't free it */
+
+               /* Try to free the PUD that contained the PMD just freed */
+               try_to_free_table(pud, pge);
+               return;
+       }
+}
+
+
+/**
+ * Writes a new value to a PTE.
+ * TODO: Determine if this is atomic enough.
+ */
+static void
+write_pte(
+       xpte_t *        pte,
+       paddr_t         paddr,
+       vmflags_t       flags,
+       vmpagesize_t    pagesz
+)
+{
+       xpte_t _pte;
+       memset(&_pte, 0, sizeof(_pte));
+
+       _pte.present = 1;
+       if (flags & VM_WRITE)
+               _pte.write = 1;
+       if (flags & VM_USER)
+               _pte.user = 1;
+       if (flags & VM_GLOBAL)
+               _pte.global = 1;
+       if ((flags & VM_EXEC) == 0)
+               _pte.no_exec = 1;
+
+       if (pagesz == VM_PAGE_4KB) {
+               _pte.base_paddr = paddr >> 12;
+       } else if (pagesz == VM_PAGE_2MB) {
+               _pte.pagesize = 1;
+               _pte.base_paddr = paddr >> 21;
+       } else if (pagesz == VM_PAGE_1GB) {
+               _pte.pagesize = 1;
+               _pte.base_paddr = paddr >> 30;
+       } else {
+               panic("Invalid page size 0x%lx.", pagesz);
+       }
+
+       *pte = _pte;
+}
+
+
+/**
+ * Maps a page into an address space.
+ *
+ * Arguments:
+ *       [IN] aspace: Address space to map page into.
+ *       [IN] start:  Address in aspace to map page to.
+ *       [IN] paddr:  Physical address of the page to map.
+ *       [IN] flags:  Protection and memory type flags.
+ *       [IN] pagesz: Size of the page being mapped, in bytes.
+ *
+ * Returns:
+ *       Success: 0
+ *       Failure: Error Code, the page was not mapped.
+ */
+int
+arch_aspace_map_page(
+       struct aspace * aspace,
+       vaddr_t         start,
+       paddr_t         paddr,
+       vmflags_t       flags,
+       vmpagesize_t    pagesz
+)
+{
+       xpte_t *pte;
+
+       /* Locate page table entry that needs to be updated to map the page */
+       pte = find_or_create_pte(aspace, start, pagesz);
+       if (!pte)
+               return -ENOMEM;
+
+       /* Update the page table entry */
+       write_pte(pte, paddr, flags, pagesz);
+
+       return 0;
+}
+
+
+/**
+ * Unmaps a page from an address space.
+ *
+ * Arguments:
+ *       [IN] aspace: Address space to unmap page from.
+ *       [IN] start:  Address in aspace to unmap page from.
+ *       [IN] pagesz: Size of the page to unmap.
+ */
+void
+arch_aspace_unmap_page(
+       struct aspace * aspace,
+       vaddr_t         start,
+       vmpagesize_t    pagesz
+)
+{
+       find_and_delete_pte(aspace, start, pagesz);
+}
+
+int
+arch_aspace_smartmap(struct aspace *src, struct aspace *dst,
+                     vaddr_t start, size_t extent)
+{
+       size_t n = extent / SMARTMAP_ALIGN;
+       size_t i;
+       xpte_t *src_pgd = src->arch.pgd;
+       xpte_t *dst_pgd = dst->arch.pgd;
+       xpte_t *src_pge, *dst_pge;
+
+       /* Make sure all of the source PGD entries are present */
+       for (i = 0; i < n; i++) {
+               src_pge = &src_pgd[i];
+               if (!src_pge->present && !alloc_page_table(src_pge))
+                       return -ENOMEM;
+       }
+
+       /* Perform the SMARTMAP... just copy src PGEs to the dst PGD */
+       for (i = 0; i < n; i++) {
+               src_pge = &src_pgd[i];
+               dst_pge = &dst_pgd[(start >> 39) & 0x1FF];
+               BUG_ON(dst_pge->present);
+               dst_pge = src_pge;
+       }
+
+       return 0;
+}
+
+int
+arch_aspace_unsmartmap(struct aspace *src, struct aspace *dst,
+                       vaddr_t start, size_t extent)
+{
+       size_t n = extent / SMARTMAP_ALIGN;
+       size_t i;
+       xpte_t *dst_pgd = dst->arch.pgd;
+       xpte_t *dst_pge;
+
+       /* Unmap the SMARTMAP PGEs */
+       for (i = 0; i < n; i++) {
+               dst_pge = &dst_pgd[(start >> 39) & 0x1FF];
+               dst_pge->present = 0;
+       }
+
+       return 0;
+}
diff --git a/kitten/arch/x86_64/mm/fault.c b/kitten/arch/x86_64/mm/fault.c
new file mode 100644 (file)
index 0000000..afd4f75
--- /dev/null
@@ -0,0 +1,19 @@
+#include <lwk/task.h>
+#include <lwk/signal.h>
+#include <lwk/ptrace.h>
+
+/**
+ * Determines if a signal is unhandled.
+ * Returns 1 if the signal is unhandled, 0 otherwise.
+ */
+int
+unhandled_signal(struct task_struct *tsk, int sig)
+{
+       if (is_init(tsk))
+               return 1;
+       if (tsk->ptrace & PT_PTRACED)
+               return 0;
+       return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
+               (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
+}
+
diff --git a/kitten/arch/x86_64/mm/init.c b/kitten/arch/x86_64/mm/init.c
new file mode 100644 (file)
index 0000000..eda4459
--- /dev/null
@@ -0,0 +1,346 @@
+#include <lwk/kernel.h>
+#include <lwk/bootmem.h>
+#include <lwk/string.h>
+#include <lwk/pmem.h>
+#include <arch/page.h>
+#include <arch/pgtable.h>
+#include <arch/e820.h> 
+#include <arch/tlbflush.h>
+#include <arch/proto.h>
+
+/**
+ * Start and end page frame numbers of the kernel page tables.
+ */
+unsigned long __initdata table_start, table_end;  /* page frame numbers */
+
+static __init void *early_ioremap(unsigned long addr, unsigned long size)
+{
+       unsigned long vaddr;
+       pmd_t *pmd, *last_pmd;
+       int i, pmds;
+
+       pmds = ((addr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
+       vaddr = __START_KERNEL_map;
+       pmd = level2_kernel_pgt;
+       last_pmd = level2_kernel_pgt + PTRS_PER_PMD - 1;
+       for (; pmd <= last_pmd; pmd++, vaddr += PMD_SIZE) {
+               for (i = 0; i < pmds; i++) {
+                       if (pmd_present(pmd[i]))
+                               goto next;
+               }
+               vaddr += addr & ~PMD_MASK;
+               addr &= PMD_MASK;
+               for (i = 0; i < pmds; i++, addr += PMD_SIZE)
+                       set_pmd(pmd + i,__pmd(addr | _KERNPG_TABLE | _PAGE_PSE));
+               __flush_tlb();
+               return (void *)vaddr;
+       next:
+               ;
+       }
+       printk("early_ioremap(0x%lx, %lu) failed\n", addr, size);
+       return NULL;
+}
+
+/* To avoid virtual aliases later */
+static __init void early_iounmap(void *addr, unsigned long size)
+{
+       unsigned long vaddr;
+       pmd_t *pmd;
+       int i, pmds;
+
+       vaddr = (unsigned long)addr;
+       pmds = ((vaddr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
+       pmd = level2_kernel_pgt + pmd_index(vaddr);
+       for (i = 0; i < pmds; i++)
+               pmd_clear(pmd + i);
+       __flush_tlb();
+}
+
+static __init void *alloc_low_page(unsigned long *phys)
+{ 
+       unsigned long pfn = table_end++;
+       void *adr;
+
+       if (pfn >= end_pfn) 
+               panic("alloc_low_page: ran out of memory"); 
+
+       adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
+       memset(adr, 0, PAGE_SIZE);
+       *phys  = pfn * PAGE_SIZE;
+       return adr;
+}
+
+/**
+ * Destroys a temporary mapping that was setup by alloc_low_page().
+ */
+static void __init unmap_low_page(void *adr)
+{ 
+       early_iounmap(adr, PAGE_SIZE);
+} 
+
+/**
+ * Initializes a fixmap entry to point to a given physical page.
+ */
+void __init
+__set_fixmap(
+       enum fixed_addresses fixmap_index, /* fixmap entry index to setup */
+       unsigned long        phys_addr,    /* map fixmap entry to this addr */
+       pgprot_t             prot          /* page protection bits */
+)
+{
+       unsigned long virt_addr;
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte, new_pte;
+
+       if (fixmap_index >= __end_of_fixed_addresses)
+               panic("Invalid FIXMAP index");
+
+       /* Calculate the virtual address of the fixmap entry */
+       virt_addr = __fix_to_virt(fixmap_index);
+
+       /* Look up PGD entry covering the fixmap entry */
+       pgd = pgd_offset_k(virt_addr);
+       if (pgd_none(*pgd))
+               panic("PGD FIXMAP MISSING, it should be setup in head.S!\n");
+
+       /* Look up the PMD entry covering the fixmap entry */
+       pud = pud_offset(pgd, virt_addr);
+       if (pud_none(*pud)) {
+               /* PUD entry is empty... allocate a new PMD directory for it */
+               pmd = (pmd_t *) alloc_bootmem_aligned(PAGE_SIZE, PAGE_SIZE);
+               set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
+               BUG_ON(pmd != pmd_offset(pud, 0));
+       }
+
+       /* Look up the PMD entry covering the fixmap entry */
+       pmd = pmd_offset(pud, virt_addr);
+       if (pmd_none(*pmd)) {
+               /* PMD entry is empty... allocate a new PTE directory for it */
+               pte = (pte_t *) alloc_bootmem_aligned(PAGE_SIZE, PAGE_SIZE);
+               set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
+               BUG_ON(pte != pte_offset_kernel(pmd, 0));
+       }
+
+       /*
+        * Construct and install a new PTE that maps the fixmap entry
+        * to the requested physical address.
+        */
+       pte     = pte_offset_kernel(pmd, virt_addr);
+       new_pte = pfn_pte(phys_addr >> PAGE_SHIFT, prot);
+       set_pte(pte, new_pte);
+       __flush_tlb_one(virt_addr);
+}
+
+/**
+ * Finds enough space for the kernel page tables.
+ */
+static void __init
+find_early_table_space(unsigned long end)
+{
+       unsigned long puds;     /* # of pud page tables needed */
+       unsigned long pmds;     /* # of pmd page tables needed */
+       unsigned long tables;   /* page table memory needed, in bytes */
+       unsigned long start;    /* start address for kernel page tables */
+
+       /*
+        * The kernel page tables map memory using 2 MB pages.
+        * This means only puds and pmds are needed.
+        */
+       puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
+       pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
+       tables = round_up(puds * sizeof(pud_t), PAGE_SIZE) +
+                round_up(pmds * sizeof(pmd_t), PAGE_SIZE);
+
+       /*
+        * Consult the memory map to find a region of suitable size.
+        */
+       start = 0x8000;
+       table_start = find_e820_area(start, end, tables);
+       if (table_start == -1UL)
+               panic("Cannot find space for the kernel page tables");
+
+       /*
+        * Store table_start and table_end as page frame numbers.
+        * table_end starts out as the same as table_start.
+        * It will be incremented for each page table allocated.
+        */
+       table_start >>= PAGE_SHIFT;
+       table_end = table_start;
+}
+
+
+/**
+ * Configures the input Page Middle Directory to map physical addresses
+ * [address, end).  PMD entries outside of this range are zeroed.
+ *
+ * Each PMD table maps 1 GB of memory (512 entries, each mapping 2 MB).
+ */
+static void __init
+phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end)
+{
+       int i;
+
+       for (i = 0; i < PTRS_PER_PMD; pmd++, i++, address += PMD_SIZE) {
+               unsigned long entry;
+
+               if (address > end) {
+                       for (; i < PTRS_PER_PMD; i++, pmd++)
+                               set_pmd(pmd, __pmd(0));
+                       break;
+               }
+               entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
+               entry &= __supported_pte_mask;
+               set_pmd(pmd, __pmd(entry));
+       }
+}
+
+/**
+ * Configures the input Page Upper Directory to map physical addresses
+ * [address, end).  PUD entries outside of this range are zeroed.
+ *
+ * Each PUD table maps 512 GB of memory (512 entries, each pointing to a PMD).
+ */
+static void __init
+phys_pud_init(pud_t *pud, unsigned long address, unsigned long end)
+{ 
+       long i = pud_index(address);
+
+       pud = pud + i;
+
+       for (; i < PTRS_PER_PUD; pud++, i++) {
+               unsigned long paddr, pmd_phys;
+               pmd_t *pmd;
+
+               paddr = (address & PGDIR_MASK) + i*PUD_SIZE;
+               if (paddr >= end)
+                       break;
+
+               if (!e820_any_mapped(paddr, paddr+PUD_SIZE, 0)) {
+                       set_pud(pud, __pud(0)); 
+                       continue;
+               } 
+
+               pmd = alloc_low_page(&pmd_phys);
+               set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
+               phys_pmd_init(pmd, paddr, end);
+               unmap_low_page(pmd);
+       }
+       __flush_tlb();
+} 
+
+/**
+ * Setup the initial kernel page tables,  These map all of physical memory
+ * (0 to the top of physical memory) starting at virtual address PAGE_OFFSET.
+ * This runs before bootmem is initialized and therefore has to get pages
+ * directly from physical memory.
+ */
+void __init
+init_kernel_pgtables(unsigned long start, unsigned long end)
+{ 
+       unsigned long next; 
+
+       /* 
+        * Find a contiguous region of memory large enough to hold the
+        * kernel page tables.
+        */
+       find_early_table_space(end);
+
+       /*
+        * Calculate the start and end kernel virtual addresses
+        * corresponding to the input physical address range.
+        */
+       start = (unsigned long)__va(start);
+       end   = (unsigned long)__va(end);
+
+       for (; start < end; start = next) {
+               unsigned long pud_phys; 
+               pud_t *pud;
+
+               /*
+                * Allocate a new page for the Page Upper Directory.
+                * 
+                *     pud      = kernel virtual address where the new
+                *                page can be accessed.
+                *     pud_phys = physical address of the new page.
+                *     map      = cookie needed to free the temporary mapping.
+                */
+               pud = alloc_low_page(&pud_phys);
+
+               /*
+                * Calculate the upper bound address for the PUD.
+                * The PUD maps [start, next).
+                */
+               next = start + PGDIR_SIZE;
+               if (next > end) 
+                       next = end; 
+
+               /*
+                * Initialize the new PUD.
+                * phys_pud_init internally calls phys_pmd_init for
+                * each entry in the PUD.
+                */
+               phys_pud_init(pud, __pa(start), __pa(next));
+
+               /*
+                * Point the Page Global Directory at the new PUD.
+                * The PGD is the root of the page tables.
+                */
+               set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
+
+               /* Destroy the temporary kernel mapping of the new PUD */
+               unmap_low_page(pud);   
+       } 
+
+       asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+       __flush_tlb_all();
+
+       printk(KERN_DEBUG
+               "Allocated %lu KB for kernel page tables [0x%lx - 0x%lx)\n",
+               ((table_end - table_start) << PAGE_SHIFT) / 1024,
+               table_start << PAGE_SHIFT,
+               table_end   << PAGE_SHIFT);
+}
+
+/**
+ * This performs architecture-specific memory subsystem initialization. It is
+ * called from the platform-independent memsys_init(). For x86_64, the only
+ * thing that needs to be done is to relocate the initrd image to user memory.
+ */
+void __init
+arch_memsys_init(size_t kmem_size)
+{
+       struct pmem_region query, result;
+       size_t initrd_size, umem_size;
+
+       if (!initrd_start)
+               return;
+
+       initrd_size = initrd_end - initrd_start;
+       umem_size   = round_up(initrd_size, PAGE_SIZE);
+
+       /* Relocate the initrd image to an unallocated chunk of umem */
+       if (pmem_alloc_umem(umem_size, PAGE_SIZE, &result))
+               panic("Failed to allocate umem for initrd image.");
+       result.type = PMEM_TYPE_INITRD;
+       pmem_update(&result);
+       memmove(__va(result.start), __va(initrd_start), initrd_size);
+
+       /* Free the memory used by the old initrd location */
+       pmem_region_unset_all(&query);
+       query.start = round_down( initrd_start, PAGE_SIZE );
+       query.end   = round_up(   initrd_end,   PAGE_SIZE );
+       while (pmem_query(&query, &result) == 0) {
+               result.type = (result.start < kmem_size) ? PMEM_TYPE_KMEM
+                                                        : PMEM_TYPE_UMEM;
+               result.allocated = false;
+               BUG_ON(pmem_update(&result));
+               query.start = result.end;
+       }
+       
+       /* Update initrd_start and initrd_end to their new values */
+       initrd_start = result.start;
+       initrd_end   = initrd_start + initrd_size;
+}
+
diff --git a/kitten/arch/x86_64/mm/phys_addr.c b/kitten/arch/x86_64/mm/phys_addr.c
new file mode 100644 (file)
index 0000000..90e6097
--- /dev/null
@@ -0,0 +1,21 @@
+#include <arch/page.h>
+
+extern unsigned long phys_base;
+
+/**
+ * This converts a kernel virtual address to a physical address.
+ *
+ * NOTE: This function only works for kernel virtual addresses in the kernel's
+ *       identity mapping of all of physical memory. It will not work for the
+ *       fixmap, vmalloc() areas, or any other type of virtual address.
+ */
+unsigned long
+__phys_addr(unsigned long virt_addr)
+{
+       /* Handle kernel symbols */
+       if (virt_addr >= __START_KERNEL_map)
+               return virt_addr - __START_KERNEL_map + phys_base;
+       /* Handle kernel data */
+       return virt_addr - PAGE_OFFSET;
+}
+
diff --git a/kitten/boot-kitten b/kitten/boot-kitten
new file mode 100755 (executable)
index 0000000..dc5b9f7
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+exec /usr/local/qemu/bin/qemu-system-x86_64 \
+       -m 1024 \
+        -nographic \
+        -cdrom ./arch/x86_64/boot/image.iso  \
+       < /dev/null
+
diff --git a/kitten/boot-kitten2 b/kitten/boot-kitten2
new file mode 100755 (executable)
index 0000000..cf5dfe4
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+exec /usr/local/qemu/bin/qemu-system-x86_64 \
+       -smp 1 \
+       -m 1024 \
+       -serial file:./serial.out \
+        -cdrom ./arch/x86_64/boot/image.iso  \
+       < /dev/null
+
diff --git a/kitten/drivers/Makefile b/kitten/drivers/Makefile
new file mode 100644 (file)
index 0000000..a417398
--- /dev/null
@@ -0,0 +1 @@
+obj-y += console/
diff --git a/kitten/drivers/console/Makefile b/kitten/drivers/console/Makefile
new file mode 100644 (file)
index 0000000..4c2ee8a
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VGA_CONSOLE)      += vga.o
+obj-$(CONFIG_SERIAL_CONSOLE)   += serial.o
+obj-$(CONFIG_RCAL0_CONSOLE)    += rcal0.o
diff --git a/kitten/drivers/console/rcal0.c b/kitten/drivers/console/rcal0.c
new file mode 100644 (file)
index 0000000..09af433
--- /dev/null
@@ -0,0 +1,89 @@
+#include <lwk/driver.h>
+#include <lwk/console.h>
+#include <lwk/string.h>
+#include <lwk/delay.h>
+#include <rca/rca_l0.h>
+
+/** Template event heder with static fields filled in. */
+static rs_event_t ev_hdr = {0};
+
+/** Set when L0 console has been initialized. */
+static int initialized = 0;
+
+/**
+ * Writes a message to the Cray L0 console.
+ */
+static void l0_write(struct console *con, const char *str)
+{
+       int ret = 0;
+       unsigned int n = strlen(str);
+
+       while (n) {
+               if ((ret =
+                       ch_send_data(L0RCA_CH_CON_UP, &ev_hdr, (void *)str, n))
+                    <= 0)
+               {
+                       /* either error or we are done */
+                       break;
+               }
+
+               if (n > ret) {
+                       /* some bytes were sent, point to the remaining data */
+                       str += (n - ret);
+                       n = ret;
+               }
+
+               /* busy wait if the buf is full */
+                udelay(1000);
+       }
+
+       /* if error, give up and spin forever */
+       if (ret < 0)
+               while (1) {}
+
+       return;
+}
+
+/**
+ * Cray L0 console device.
+ */
+static struct console l0_console = {
+       .name  = "Cray RCA L0 Console",
+       .write = l0_write
+};
+
+/**
+ * Initializes the Cray XT L0 console.
+ */
+void l0_console_init(void)
+{
+       if (initialized) {
+               printk(KERN_ERR "RCA L0 console already initialized.\n");
+               return;
+       }
+
+       /* Read the configuration information provided by the L0 */
+       l0rca_init_config();
+
+       /* Setup the event template to use for outgoing events */
+       ev_hdr.ev_id            =       ec_console_log;
+       ev_hdr.ev_gen           =       RCA_MKSVC(
+                                               RCA_INST_ANY,
+                                               RCA_SVCTYPE_CONS,
+                                               l0rca_get_proc_id()
+                                       );
+       ev_hdr.ev_src           =       ev_hdr.ev_gen;
+       ev_hdr.ev_priority      =       RCA_LOG_DEBUG;
+       ev_hdr.ev_flag          =       0;
+       /* Timestamp, len & data is filled at the time of sending event */
+       
+       /* Register with the Cray RCA subsystem */
+       register_ch_up(L0RCA_CH_CON_UP, NULL, 0, -1);
+
+       /* Register the L0 console with the LWK */
+       console_register(&l0_console);
+       initialized = 1;
+}
+
+driver_init(l0_console_init);
+
diff --git a/kitten/drivers/console/serial.c b/kitten/drivers/console/serial.c
new file mode 100644 (file)
index 0000000..6b7248f
--- /dev/null
@@ -0,0 +1,117 @@
+#include <lwk/driver.h>
+#include <lwk/console.h>
+#include <lwk/interrupt.h>
+#include <arch/io.h>
+
+// Serial port registers
+#define TXB            0       // Transmitter Holding Buffer            W
+#define RXB            0       // Receiver Buffer                       R
+#define DLL            0       // Divisor Latch Low Byte               R/W
+#define IER            1       // Interrupt Enable Register            R/W
+#define DLH            1       // Divisor Latch High Byte              R/W
+#define IIR            2       // Interrupt Identification Register     R
+#define FCR            2       // FIFO Control Register                 W
+#define LCR            3       // Line Control Register                R/W
+#define MCR            4       // Modem Control Register               R/W
+#define LSR            5       // Line Status Register                  R
+#define MSR            6       // Modem Status Register                 R
+#define SCR            7       // Scratch Register                     R/W
+
+// IER bits
+#define IER_RLSI       0x08    // RX interrupt
+#define IER_THRI       0x02    // TX interrupt
+#define IER_RDI                0x01    // Reciver data interrupt
+
+// MCR bits
+#define MCR_DTR                0x01    // Enable DTR
+#define MCR_RTS                0x02    // Enable RTS
+#define MCR_OUT2       0x08    // Enable Out2 (?)
+
+// LSR bits
+#define LSR_TXEMPT     0x20    // Empty TX holding register
+#define LSR_RXRDY      0x01    // Ready to receive
+
+// LCR bits
+#define LCR_DLAB       0x80    // Divisor latch access bit
+
+/** IO port address of the serial port. */
+static unsigned int port = 0x3F8;  // COM1
+
+/** Serial port baud rate. */
+static unsigned int baud = 9600;
+#define SERIAL_MAX_BAUD        115200
+
+/** Set when serial console has been initialized. */
+static int initialized = 0;
+
+/**
+ * Prints a single character to the serial port.
+ */
+static void serial_putc(unsigned char c)
+{
+       // Wait until the TX buffer is empty
+       while ((inb_p(port + LSR) & LSR_TXEMPT) == 0)
+               ;
+       // Slam the 8 bits down the 1 bit pipe... meeeooowwwy!
+       outb(c, port);
+}
+
+/**
+ * Writes a string to the serial port.
+ */
+static void serial_write(struct console *con, const char *str)
+{
+       unsigned char c;
+       while ((c = *str++) != '\0') {
+               serial_putc(c);
+               if (c == '\n')                  // new line
+                       serial_putc('\r');      // tack on carriage return
+       }
+}
+
+/**
+ * Serial port console device.
+ */
+static struct console serial_console = {
+       .name  = "Serial Console",
+       .write = serial_write
+};
+
+/**
+ * Initializes and registers the serial console driver.
+ */
+void serial_console_init(void)
+{
+       // Setup the divisor latch registers for the specified baud rate
+       unsigned int div = SERIAL_MAX_BAUD / baud;
+
+       if (initialized) {
+               printk(KERN_ERR "Serial console already initialized.\n");
+               return;
+       }
+
+       outb( inb(port+LCR) | LCR_DLAB  , port+LCR ); // set DLAB
+       outb( (div>>0) & 0xFF           , port+DLL ); // set divisor low byte
+       outb( (div>>8) & 0xFF           , port+DLH ); // set divisor high byte
+       outb( inb(port+LCR) & ~LCR_DLAB , port+LCR ); // unset DLAB
+       
+       outb( 0x0 , port+IER ); // Disable serial port interrupts
+       outb( 0x0 , port+FCR ); // Don't use the FIFOs
+       outb( 0x3 , port+LCR ); // 8n1
+
+       // Setup modem control register
+       outb( MCR_RTS | MCR_DTR | MCR_OUT2 , port+MCR);
+
+       console_register(&serial_console);
+       initialized = 1;
+}
+
+driver_init(serial_console_init);
+
+/**
+ * Configurable parameters for controlling the serial port
+ * I/O port address and baud.
+ */
+driver_param(port, uint);
+driver_param(baud, uint);
+
diff --git a/kitten/drivers/console/vga.c b/kitten/drivers/console/vga.c
new file mode 100644 (file)
index 0000000..55e8253
--- /dev/null
@@ -0,0 +1,144 @@
+#include <lwk/driver.h>
+#include <lwk/console.h>
+#include <lwk/string.h>
+
+/** Base address of the VGA frame buffer. */
+static volatile uint8_t * const vga_fb = (uint8_t *) 0xffffffff800b8000ul;
+
+/** Current cursor row coordinate. */
+static int row = 0;
+
+/** Current cursor column coordinate. */
+static int col = 0;
+
+/** Number of rows on the screen. */
+static int nrows = 25;
+
+/** Number of columns on the screen. */
+static int ncols = 80;
+
+/** Set when vga console has been initialized. */
+static int initialized = 0;
+
+/** Calculates the offset in the vga_fb corresponding to (row, col). */
+static inline int cursor(int row, int col)
+{
+       return (row * ncols * 2) + col * 2;
+}
+
+/**
+ * Scrolls everything on the screen up by one row.
+ */ 
+static void vga_scroll(void)
+{
+       int i;
+
+       // Move all existing lines up by one
+       memmove(
+               (void *) vga_fb,
+               (void *) (vga_fb + cursor(1, 0)),
+               (nrows - 1) * ncols * sizeof(uint16_t)
+       );
+
+       // Blank the new line at the bottom of the screen
+       for (i = 0; i < ncols; i++)
+               vga_fb[cursor(nrows-1, i)] = ' ';
+}
+
+/**
+ * Moves cursor to the next line.
+ */ 
+static void vga_newline(void)
+{
+       row = row + 1;
+       col = 0;
+
+       if (row == nrows) {
+               row = nrows - 1;
+               vga_scroll();
+       }
+}
+
+/**
+ * Sets the VGA font color.
+ */
+static void vga_set_font_color(uint8_t color)
+{
+       int i, j;
+       for (i = 0; i < nrows; i++)
+               for (j = 0; j < ncols; j++)
+                       vga_fb[cursor(i, j) + 1] = color;
+}
+
+/**
+ * Prints a single character to the screen.
+ */
+static void vga_putc(unsigned char c)
+{
+       // Print the character
+       vga_fb[cursor(row, col)] = c;
+
+       // Move cursor
+       if (++col == ncols)
+               vga_newline();
+}
+
+/**
+ * Writes a string to the screen at the current cursor location.
+ */
+static void vga_write(struct console *con, const char *str)
+{
+       unsigned char c;
+
+       while ((c = *str++) != '\0') {
+               switch (c) {
+                       case '\n':
+                               vga_newline();
+                               break;
+
+                       case '\t':
+                               /* Emulate a TAB */
+                               vga_putc(' ');
+                               while ((col % 8) != 0)
+                                       vga_putc(' ');
+                               break;
+
+                       default: 
+                               vga_putc(c);
+               }
+       }
+}
+
+/**
+ * VGA console device.
+ */
+static struct console vga_console = {
+       .name  = "VGA Console",
+       .write = vga_write
+};
+
+/**
+ * Initializes and registers the VGA console driver.
+ */
+void vga_console_init(void)
+{
+       if (initialized) {
+               printk(KERN_ERR "VGA console already initialized.\n");
+               return;
+       }
+
+       vga_set_font_color(0x0F /* White */);
+       console_register(&vga_console);
+       initialized = 1;
+}
+
+driver_init(vga_console_init);
+
+/**
+ * Sets the row on the screen to start printing at.
+ * This is used to avoid overwriting BIOS/boot messages.
+ * At least on x86-64, this is set automatically as part
+ * of the bootstrap process.
+ */
+driver_param(row, int);
+
diff --git a/kitten/include/arch-generic/atomic.h b/kitten/include/arch-generic/atomic.h
new file mode 100644 (file)
index 0000000..afd66ea
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef _ASM_GENERIC_ATOMIC_H
+#define _ASM_GENERIC_ATOMIC_H
+/*
+ * Copyright (C) 2005 Silicon Graphics, Inc.
+ *     Christoph Lameter <clameter@sgi.com>
+ *
+ * Allows to provide arch independent atomic definitions without the need to
+ * edit all arch specific atomic.h files.
+ */
+
+#include <arch/types.h>
+
+/*
+ * Suppport for atomic_long_t
+ *
+ * Casts for parameters are avoided for existing atomic functions in order to
+ * avoid issues with cast-as-lval under gcc 4.x and other limitations that the
+ * macros of a platform may have.
+ */
+
+#if BITS_PER_LONG == 64
+
+typedef atomic64_t atomic_long_t;
+
+#define ATOMIC_LONG_INIT(i)    ATOMIC64_INIT(i)
+
+static inline long atomic_long_read(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_read(v);
+}
+
+static inline void atomic_long_set(atomic_long_t *l, long i)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_set(v, i);
+}
+
+static inline void atomic_long_inc(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_inc(v);
+}
+
+static inline void atomic_long_dec(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_dec(v);
+}
+
+static inline void atomic_long_add(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_add(i, v);
+}
+
+static inline void atomic_long_sub(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_sub(i, v);
+}
+
+#else
+
+typedef atomic_t atomic_long_t;
+
+#define ATOMIC_LONG_INIT(i)    ATOMIC_INIT(i)
+static inline long atomic_long_read(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_read(v);
+}
+
+static inline void atomic_long_set(atomic_long_t *l, long i)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_set(v, i);
+}
+
+static inline void atomic_long_inc(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_inc(v);
+}
+
+static inline void atomic_long_dec(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_dec(v);
+}
+
+static inline void atomic_long_add(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_add(i, v);
+}
+
+static inline void atomic_long_sub(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_sub(i, v);
+}
+
+#endif
+#endif
diff --git a/kitten/include/arch-generic/bitops/hweight.h b/kitten/include/arch-generic/bitops/hweight.h
new file mode 100644 (file)
index 0000000..d2e5aa8
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
+
+#include <arch/types.h>
+
+extern unsigned int hweight32(unsigned int w);
+extern unsigned int hweight16(unsigned int w);
+extern unsigned int hweight8(unsigned int w);
+extern unsigned long hweight64(__u64 w);
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
diff --git a/kitten/include/arch-generic/bug.h b/kitten/include/arch-generic/bug.h
new file mode 100644 (file)
index 0000000..dcb10a2
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _ARCH_GENERIC_BUG_H
+#define _ARCH_GENERIC_BUG_H
+
+#include <lwk/compiler.h>
+
+#ifndef HAVE_ARCH_BUG
+#define BUG() do { \
+       printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
+       panic("BUG!"); \
+} while (0)
+#endif
+
+#ifndef HAVE_ARCH_BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef HAVE_ARCH_ASSERT
+#define ASSERT(condition) do { if (unlikely((condition)!=1)) BUG(); } while(0)
+#endif
+
+#ifndef HAVE_ARCH_WARN_ON
+#define WARN_ON(condition) do { \
+       if (unlikely((condition)!=0)) { \
+               printk("BUG: warning at %s:%d/%s()\n", __FILE__, __LINE__, __FUNCTION__); \
+               /* TODO FIX ME */ \
+               /* dump_stack(); */ \
+       } \
+} while (0)
+#endif
+
+#endif
diff --git a/kitten/include/arch-generic/div64.h b/kitten/include/arch-generic/div64.h
new file mode 100644 (file)
index 0000000..9cfa5f0
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _ARCH_GENERIC_DIV64_H
+#define _ARCH_GENERIC_DIV64_H
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h
+ *
+ * The semantics of do_div() are:
+ *
+ * uint32_t do_div(uint64_t *n, uint32_t base)
+ * {
+ *     uint32_t remainder = *n % base;
+ *     *n = *n / base;
+ *     return remainder;
+ * }
+ *
+ * NOTE: macro parameter n is evaluated multiple times,
+ *       beware of side effects!
+ */
+
+#include <lwk/types.h>
+#include <lwk/compiler.h>
+
+#if BITS_PER_LONG == 64
+
+# define do_div(n,base) ({                                     \
+       uint32_t __base = (base);                               \
+       uint32_t __rem;                                         \
+       __rem = ((uint64_t)(n)) % __base;                       \
+       (n) = ((uint64_t)(n)) / __base;                         \
+       __rem;                                                  \
+ })
+
+#elif BITS_PER_LONG == 32
+
+extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({                             \
+       uint32_t __base = (base);                       \
+       uint32_t __rem;                                 \
+       (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
+       if (likely(((n) >> 32) == 0)) {                 \
+               __rem = (uint32_t)(n) % __base;         \
+               (n) = (uint32_t)(n) / __base;           \
+       } else                                          \
+               __rem = __div64_32(&(n), __base);       \
+       __rem;                                          \
+ })
+
+#else /* BITS_PER_LONG == ?? */
+
+# error do_div() does not yet support the C64
+
+#endif /* BITS_PER_LONG */
+
+#endif /* _ARCH_GENERIC_DIV64_H */
diff --git a/kitten/include/arch-generic/errno-base.h b/kitten/include/arch-generic/errno-base.h
new file mode 100644 (file)
index 0000000..43197de
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _ARCH_GENERIC_ERRNO_BASE_H
+#define _ARCH_GENERIC_ERRNO_BASE_H
+
+#define        EPERM            1      /* Operation not permitted */
+#define        ENOENT           2      /* No such file or directory */
+#define        ESRCH            3      /* No such process */
+#define        EINTR            4      /* Interrupted system call */
+#define        EIO              5      /* I/O error */
+#define        ENXIO            6      /* No such device or address */
+#define        E2BIG            7      /* Argument list too long */
+#define        ENOEXEC          8      /* Exec format error */
+#define        EBADF            9      /* Bad file number */
+#define        ECHILD          10      /* No child processes */
+#define        EAGAIN          11      /* Try again */
+#define        ENOMEM          12      /* Out of memory */
+#define        EACCES          13      /* Permission denied */
+#define        EFAULT          14      /* Bad address */
+#define        ENOTBLK         15      /* Block device required */
+#define        EBUSY           16      /* Device or resource busy */
+#define        EEXIST          17      /* File exists */
+#define        EXDEV           18      /* Cross-device link */
+#define        ENODEV          19      /* No such device */
+#define        ENOTDIR         20      /* Not a directory */
+#define        EISDIR          21      /* Is a directory */
+#define        EINVAL          22      /* Invalid argument */
+#define        ENFILE          23      /* File table overflow */
+#define        EMFILE          24      /* Too many open files */
+#define        ENOTTY          25      /* Not a typewriter */
+#define        ETXTBSY         26      /* Text file busy */
+#define        EFBIG           27      /* File too large */
+#define        ENOSPC          28      /* No space left on device */
+#define        ESPIPE          29      /* Illegal seek */
+#define        EROFS           30      /* Read-only file system */
+#define        EMLINK          31      /* Too many links */
+#define        EPIPE           32      /* Broken pipe */
+#define        EDOM            33      /* Math argument out of domain of func */
+#define        ERANGE          34      /* Math result not representable */
+
+#endif
diff --git a/kitten/include/arch-generic/errno.h b/kitten/include/arch-generic/errno.h
new file mode 100644 (file)
index 0000000..c220bc8
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _ARCH_GENERIC_ERRNO_H
+#define _ARCH_GENERIC_ERRNO_H
+
+#include <arch-generic/errno-base.h>
+
+#define        EDEADLK         35      /* Resource deadlock would occur */
+#define        ENAMETOOLONG    36      /* File name too long */
+#define        ENOLCK          37      /* No record locks available */
+#define        ENOSYS          38      /* Function not implemented */
+#define        ENOTEMPTY       39      /* Directory not empty */
+#define        ELOOP           40      /* Too many symbolic links encountered */
+#define        EWOULDBLOCK     EAGAIN  /* Operation would block */
+#define        ENOMSG          42      /* No message of desired type */
+#define        EIDRM           43      /* Identifier removed */
+#define        ECHRNG          44      /* Channel number out of range */
+#define        EL2NSYNC        45      /* Level 2 not synchronized */
+#define        EL3HLT          46      /* Level 3 halted */
+#define        EL3RST          47      /* Level 3 reset */
+#define        ELNRNG          48      /* Link number out of range */
+#define        EUNATCH         49      /* Protocol driver not attached */
+#define        ENOCSI          50      /* No CSI structure available */
+#define        EL2HLT          51      /* Level 2 halted */
+#define        EBADE           52      /* Invalid exchange */
+#define        EBADR           53      /* Invalid request descriptor */
+#define        EXFULL          54      /* Exchange full */
+#define        ENOANO          55      /* No anode */
+#define        EBADRQC         56      /* Invalid request code */
+#define        EBADSLT         57      /* Invalid slot */
+
+#define        EDEADLOCK       EDEADLK
+
+#define        EBFONT          59      /* Bad font file format */
+#define        ENOSTR          60      /* Device not a stream */
+#define        ENODATA         61      /* No data available */
+#define        ETIME           62      /* Timer expired */
+#define        ENOSR           63      /* Out of streams resources */
+#define        ENONET          64      /* Machine is not on the network */
+#define        ENOPKG          65      /* Package not installed */
+#define        EREMOTE         66      /* Object is remote */
+#define        ENOLINK         67      /* Link has been severed */
+#define        EADV            68      /* Advertise error */
+#define        ESRMNT          69      /* Srmount error */
+#define        ECOMM           70      /* Communication error on send */
+#define        EPROTO          71      /* Protocol error */
+#define        EMULTIHOP       72      /* Multihop attempted */
+#define        EDOTDOT         73      /* RFS specific error */
+#define        EBADMSG         74      /* Not a data message */
+#define        EOVERFLOW       75      /* Value too large for defined data type */
+#define        ENOTUNIQ        76      /* Name not unique on network */
+#define        EBADFD          77      /* File descriptor in bad state */
+#define        EREMCHG         78      /* Remote address changed */
+#define        ELIBACC         79      /* Can not access a needed shared library */
+#define        ELIBBAD         80      /* Accessing a corrupted shared library */
+#define        ELIBSCN         81      /* .lib section in a.out corrupted */
+#define        ELIBMAX         82      /* Attempting to link in too many shared libraries */
+#define        ELIBEXEC        83      /* Cannot exec a shared library directly */
+#define        EILSEQ          84      /* Illegal byte sequence */
+#define        ERESTART        85      /* Interrupted system call should be restarted */
+#define        ESTRPIPE        86      /* Streams pipe error */
+#define        EUSERS          87      /* Too many users */
+#define        ENOTSOCK        88      /* Socket operation on non-socket */
+#define        EDESTADDRREQ    89      /* Destination address required */
+#define        EMSGSIZE        90      /* Message too long */
+#define        EPROTOTYPE      91      /* Protocol wrong type for socket */
+#define        ENOPROTOOPT     92      /* Protocol not available */
+#define        EPROTONOSUPPORT 93      /* Protocol not supported */
+#define        ESOCKTNOSUPPORT 94      /* Socket type not supported */
+#define        EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
+#define        EPFNOSUPPORT    96      /* Protocol family not supported */
+#define        EAFNOSUPPORT    97      /* Address family not supported by protocol */
+#define        EADDRINUSE      98      /* Address already in use */
+#define        EADDRNOTAVAIL   99      /* Cannot assign requested address */
+#define        ENETDOWN        100     /* Network is down */
+#define        ENETUNREACH     101     /* Network is unreachable */
+#define        ENETRESET       102     /* Network dropped connection because of reset */
+#define        ECONNABORTED    103     /* Software caused connection abort */
+#define        ECONNRESET      104     /* Connection reset by peer */
+#define        ENOBUFS         105     /* No buffer space available */
+#define        EISCONN         106     /* Transport endpoint is already connected */
+#define        ENOTCONN        107     /* Transport endpoint is not connected */
+#define        ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
+#define        ETOOMANYREFS    109     /* Too many references: cannot splice */
+#define        ETIMEDOUT       110     /* Connection timed out */
+#define        ECONNREFUSED    111     /* Connection refused */
+#define        EHOSTDOWN       112     /* Host is down */
+#define        EHOSTUNREACH    113     /* No route to host */
+#define        EALREADY        114     /* Operation already in progress */
+#define        EINPROGRESS     115     /* Operation now in progress */
+#define        ESTALE          116     /* Stale NFS file handle */
+#define        EUCLEAN         117     /* Structure needs cleaning */
+#define        ENOTNAM         118     /* Not a XENIX named type file */
+#define        ENAVAIL         119     /* No XENIX semaphores available */
+#define        EISNAM          120     /* Is a named type file */
+#define        EREMOTEIO       121     /* Remote I/O error */
+#define        EDQUOT          122     /* Quota exceeded */
+
+#define        ENOMEDIUM       123     /* No medium found */
+#define        EMEDIUMTYPE     124     /* Wrong medium type */
+#define        ECANCELED       125     /* Operation Canceled */
+#define        ENOKEY          126     /* Required key not available */
+#define        EKEYEXPIRED     127     /* Key has expired */
+#define        EKEYREVOKED     128     /* Key has been revoked */
+#define        EKEYREJECTED    129     /* Key was rejected by service */
+
+/* for robust mutexes */
+#define        EOWNERDEAD      130     /* Owner died */
+#define        ENOTRECOVERABLE 131     /* State not recoverable */
+
+#endif
diff --git a/kitten/include/arch-generic/iomap.h b/kitten/include/arch-generic/iomap.h
new file mode 100644 (file)
index 0000000..d762984
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __GENERIC_IO_H
+#define __GENERIC_IO_H
+
+#include <lwk/linkage.h>
+#include <arch/byteorder.h>
+
+/*
+ * These are the "generic" interfaces for doing new-style
+ * memory-mapped or PIO accesses. Architectures may do
+ * their own arch-optimized versions, these just act as
+ * wrappers around the old-style IO register access functions:
+ * read[bwl]/write[bwl]/in[bwl]/out[bwl]
+ *
+ * Don't include this directly, include it from <asm/io.h>.
+ */
+
+/*
+ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
+ * access or a MMIO access, these functions don't care. The info is
+ * encoded in the hardware mapping set up by the mapping functions
+ * (or the cookie itself, depending on implementation and hw).
+ *
+ * The generic routines just encode the PIO/MMIO as part of the
+ * cookie, and coldly assume that the MMIO IO mappings are not
+ * in the low address range. Architectures for which this is not
+ * true can't use this generic implementation.
+ */
+extern unsigned int fastcall ioread8(void __iomem *);
+extern unsigned int fastcall ioread16(void __iomem *);
+extern unsigned int fastcall ioread16be(void __iomem *);
+extern unsigned int fastcall ioread32(void __iomem *);
+extern unsigned int fastcall ioread32be(void __iomem *);
+
+extern void fastcall iowrite8(u8, void __iomem *);
+extern void fastcall iowrite16(u16, void __iomem *);
+extern void fastcall iowrite16be(u16, void __iomem *);
+extern void fastcall iowrite32(u32, void __iomem *);
+extern void fastcall iowrite32be(u32, void __iomem *);
+
+/*
+ * "string" versions of the above. Note that they
+ * use native byte ordering for the accesses (on
+ * the assumption that IO and memory agree on a
+ * byte order, and CPU byteorder is irrelevant).
+ *
+ * They do _not_ update the port address. If you
+ * want MMIO that copies stuff laid out in MMIO
+ * memory across multiple ports, use "memcpy_toio()"
+ * and friends.
+ */
+extern void fastcall ioread8_rep(void __iomem *port, void *buf, unsigned long count);
+extern void fastcall ioread16_rep(void __iomem *port, void *buf, unsigned long count);
+extern void fastcall ioread32_rep(void __iomem *port, void *buf, unsigned long count);
+
+extern void fastcall iowrite8_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void fastcall iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void fastcall iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);
+
+/* Create a virtual mapping cookie for an IO port range */
+extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+extern void ioport_unmap(void __iomem *);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+
+#endif
diff --git a/kitten/include/arch-generic/mman.h b/kitten/include/arch-generic/mman.h
new file mode 100644 (file)
index 0000000..5e3dde2
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _ASM_GENERIC_MMAN_H
+#define _ASM_GENERIC_MMAN_H
+
+/*
+ Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd.
+ Based on: asm-xxx/mman.h
+*/
+
+#define PROT_READ      0x1             /* page can be read */
+#define PROT_WRITE     0x2             /* page can be written */
+#define PROT_EXEC      0x4             /* page can be executed */
+#define PROT_SEM       0x8             /* page may be used for atomic ops */
+#define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED     0x01            /* Share changes */
+#define MAP_PRIVATE    0x02            /* Changes are private */
+#define MAP_TYPE       0x0f            /* Mask for type of mapping */
+#define MAP_FIXED      0x10            /* Interpret addr exactly */
+#define MAP_ANONYMOUS  0x20            /* don't use a file */
+
+#define MS_ASYNC       1               /* sync memory asynchronously */
+#define MS_INVALIDATE  2               /* invalidate the caches */
+#define MS_SYNC                4               /* synchronous memory sync */
+
+#define MADV_NORMAL    0               /* no further special treatment */
+#define MADV_RANDOM    1               /* expect random page references */
+#define MADV_SEQUENTIAL        2               /* expect sequential page references */
+#define MADV_WILLNEED  3               /* will need these pages */
+#define MADV_DONTNEED  4               /* don't need these pages */
+
+/* common parameters: try to keep these consistent across architectures */
+#define MADV_REMOVE    9               /* remove these pages & resources */
+#define MADV_DONTFORK  10              /* don't inherit across fork */
+#define MADV_DOFORK    11              /* do inherit across fork */
+
+/* compatibility flags */
+#define MAP_FILE       0
+
+#endif
diff --git a/kitten/include/arch-generic/pgtable.h b/kitten/include/arch-generic/pgtable.h
new file mode 100644 (file)
index 0000000..c2059a3
--- /dev/null
@@ -0,0 +1,235 @@
+#ifndef _ASM_GENERIC_PGTABLE_H
+#define _ASM_GENERIC_PGTABLE_H
+
+#ifndef __HAVE_ARCH_PTEP_ESTABLISH
+/*
+ * Establish a new mapping:
+ *  - flush the old one
+ *  - update the page tables
+ *  - inform the TLB about the new one
+ *
+ * We hold the mm semaphore for reading, and the pte lock.
+ *
+ * Note: the old pte is known to not be writable, so we don't need to
+ * worry about dirty bits etc getting lost.
+ */
+#ifndef __HAVE_ARCH_SET_PTE_ATOMIC
+#define ptep_establish(__vma, __address, __ptep, __entry)              \
+do {                                                                   \
+       set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);       \
+       flush_tlb_page(__vma, __address);                               \
+} while (0)
+#else /* __HAVE_ARCH_SET_PTE_ATOMIC */
+#define ptep_establish(__vma, __address, __ptep, __entry)              \
+do {                                                                   \
+       set_pte_atomic(__ptep, __entry);                                \
+       flush_tlb_page(__vma, __address);                               \
+} while (0)
+#endif /* __HAVE_ARCH_SET_PTE_ATOMIC */
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+/*
+ * Largely same as above, but only sets the access flags (dirty,
+ * accessed, and writable). Furthermore, we know it always gets set
+ * to a "more permissive" setting, which allows most architectures
+ * to optimize this.
+ */
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+do {                                                                     \
+       set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);         \
+       flush_tlb_page(__vma, __address);                                 \
+} while (0)
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(__vma, __address, __ptep)            \
+({                                                                     \
+       pte_t __pte = *(__ptep);                                        \
+       int r = 1;                                                      \
+       if (!pte_young(__pte))                                          \
+               r = 0;                                                  \
+       else                                                            \
+               set_pte_at((__vma)->vm_mm, (__address),                 \
+                          (__ptep), pte_mkold(__pte));                 \
+       r;                                                              \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+#define ptep_clear_flush_young(__vma, __address, __ptep)               \
+({                                                                     \
+       int __young;                                                    \
+       __young = ptep_test_and_clear_young(__vma, __address, __ptep);  \
+       if (__young)                                                    \
+               flush_tlb_page(__vma, __address);                       \
+       __young;                                                        \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define ptep_test_and_clear_dirty(__vma, __address, __ptep)            \
+({                                                                     \
+       pte_t __pte = *__ptep;                                          \
+       int r = 1;                                                      \
+       if (!pte_dirty(__pte))                                          \
+               r = 0;                                                  \
+       else                                                            \
+               set_pte_at((__vma)->vm_mm, (__address), (__ptep),       \
+                          pte_mkclean(__pte));                         \
+       r;                                                              \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
+#define ptep_clear_flush_dirty(__vma, __address, __ptep)               \
+({                                                                     \
+       int __dirty;                                                    \
+       __dirty = ptep_test_and_clear_dirty(__vma, __address, __ptep);  \
+       if (__dirty)                                                    \
+               flush_tlb_page(__vma, __address);                       \
+       __dirty;                                                        \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define ptep_get_and_clear(__mm, __address, __ptep)                    \
+({                                                                     \
+       pte_t __pte = *(__ptep);                                        \
+       pte_clear((__mm), (__address), (__ptep));                       \
+       __pte;                                                          \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
+#define ptep_get_and_clear_full(__mm, __address, __ptep, __full)       \
+({                                                                     \
+       pte_t __pte;                                                    \
+       __pte = ptep_get_and_clear((__mm), (__address), (__ptep));      \
+       __pte;                                                          \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
+#define pte_clear_full(__mm, __address, __ptep, __full)                        \
+do {                                                                   \
+       pte_clear((__mm), (__address), (__ptep));                       \
+} while (0)
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
+#define ptep_clear_flush(__vma, __address, __ptep)                     \
+({                                                                     \
+       pte_t __pte;                                                    \
+       __pte = ptep_get_and_clear((__vma)->vm_mm, __address, __ptep);  \
+       flush_tlb_page(__vma, __address);                               \
+       __pte;                                                          \
+})
+#endif
+
+#ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT
+struct mm_struct;
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
+{
+       pte_t old_pte = *ptep;
+       set_pte_at(mm, address, ptep, pte_wrprotect(old_pte));
+}
+#endif
+
+#ifndef __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B)  (pte_val(A) == pte_val(B))
+#endif
+
+#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+#define page_test_and_clear_dirty(page) (0)
+#define pte_maybe_dirty(pte)           pte_dirty(pte)
+#else
+#define pte_maybe_dirty(pte)           (1)
+#endif
+
+#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
+#define page_test_and_clear_young(page) (0)
+#endif
+
+#ifndef __HAVE_ARCH_PGD_OFFSET_GATE
+#define pgd_offset_gate(mm, addr)      pgd_offset(mm, addr)
+#endif
+
+#ifndef __HAVE_ARCH_LAZY_MMU_PROT_UPDATE
+#define lazy_mmu_prot_update(pte)      do { } while (0)
+#endif
+
+#ifndef __HAVE_ARCH_MOVE_PTE
+#define move_pte(pte, prot, old_addr, new_addr)        (pte)
+#endif
+
+/*
+ * When walking page tables, get the address of the next boundary,
+ * or the end address of the range if that comes earlier.  Although no
+ * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout.
+ */
+
+#define pgd_addr_end(addr, end)                                                \
+({     unsigned long __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK;  \
+       (__boundary - 1 < (end) - 1)? __boundary: (end);                \
+})
+
+#ifndef pud_addr_end
+#define pud_addr_end(addr, end)                                                \
+({     unsigned long __boundary = ((addr) + PUD_SIZE) & PUD_MASK;      \
+       (__boundary - 1 < (end) - 1)? __boundary: (end);                \
+})
+#endif
+
+#ifndef pmd_addr_end
+#define pmd_addr_end(addr, end)                                                \
+({     unsigned long __boundary = ((addr) + PMD_SIZE) & PMD_MASK;      \
+       (__boundary - 1 < (end) - 1)? __boundary: (end);                \
+})
+#endif
+
+#ifndef __ASSEMBLY__
+/*
+ * When walking page tables, we usually want to skip any p?d_none entries;
+ * and any p?d_bad entries - reporting the error before resetting to none.
+ * Do the tests inline, but report and clear the bad entry in mm/memory.c.
+ */
+void pgd_clear_bad(pgd_t *);
+void pud_clear_bad(pud_t *);
+void pmd_clear_bad(pmd_t *);
+
+static inline int pgd_none_or_clear_bad(pgd_t *pgd)
+{
+       if (pgd_none(*pgd))
+               return 1;
+       if (unlikely(pgd_bad(*pgd))) {
+               pgd_clear_bad(pgd);
+               return 1;
+       }
+       return 0;
+}
+
+static inline int pud_none_or_clear_bad(pud_t *pud)
+{
+       if (pud_none(*pud))
+               return 1;
+       if (unlikely(pud_bad(*pud))) {
+               pud_clear_bad(pud);
+               return 1;
+       }
+       return 0;
+}
+
+static inline int pmd_none_or_clear_bad(pmd_t *pmd)
+{
+       if (pmd_none(*pmd))
+               return 1;
+       if (unlikely(pmd_bad(*pmd))) {
+               pmd_clear_bad(pmd);
+               return 1;
+       }
+       return 0;
+}
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_GENERIC_PGTABLE_H */
diff --git a/kitten/include/arch-generic/sections.h b/kitten/include/arch-generic/sections.h
new file mode 100644 (file)
index 0000000..53f595b
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ARCH_GENERIC_SECTIONS_H_
+#define _ARCH_GENERIC_SECTIONS_H_
+
+/* References to section boundaries */
+
+extern char _text[], _stext[], _etext[];
+extern char _data[], _sdata[], _edata[];
+extern char __bss_start[], __bss_stop[];
+extern char __init_begin[], __init_end[];
+extern char _sinittext[], _einittext[];
+extern char _sextratext[] __attribute__((weak));
+extern char _eextratext[] __attribute__((weak));
+extern char _end[];
+extern char __per_cpu_start[], __per_cpu_end[];
+extern char __kprobes_text_start[], __kprobes_text_end[];
+extern char __initdata_begin[], __initdata_end[];
+
+#endif /* _ARCH_GENERIC_SECTIONS_H_ */
diff --git a/kitten/include/arch-generic/siginfo.h b/kitten/include/arch-generic/siginfo.h
new file mode 100644 (file)
index 0000000..b149531
--- /dev/null
@@ -0,0 +1,294 @@
+#ifndef _ASM_GENERIC_SIGINFO_H
+#define _ASM_GENERIC_SIGINFO_H
+
+#include <lwk/compiler.h>
+#include <lwk/types.h>
+
+typedef union sigval {
+       int sival_int;
+       void __user *sival_ptr;
+} sigval_t;
+
+/*
+ * This is the size (including padding) of the part of the
+ * struct siginfo that is before the union.
+ */
+#ifndef __ARCH_SI_PREAMBLE_SIZE
+#define __ARCH_SI_PREAMBLE_SIZE        (3 * sizeof(int))
+#endif
+
+#define SI_MAX_SIZE    128
+#ifndef SI_PAD_SIZE
+#define SI_PAD_SIZE    ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int))
+#endif
+
+#ifndef __ARCH_SI_UID_T
+#define __ARCH_SI_UID_T        uid_t
+#endif
+
+/*
+ * The default "si_band" type is "long", as specified by POSIX.
+ * However, some architectures want to override this to "int"
+ * for historical compatibility reasons, so we allow that.
+ */
+#ifndef __ARCH_SI_BAND_T
+#define __ARCH_SI_BAND_T long
+#endif
+
+#ifndef HAVE_ARCH_SIGINFO_T
+
+typedef struct siginfo {
+       int si_signo;
+       int si_errno;
+       int si_code;
+
+       union {
+               int _pad[SI_PAD_SIZE];
+
+               /* kill() */
+               struct {
+                       pid_t _pid;             /* sender's pid */
+                       __ARCH_SI_UID_T _uid;   /* sender's uid */
+               } _kill;
+
+               /* POSIX.1b timers */
+               struct {
+                       timer_t _tid;           /* timer id */
+                       int _overrun;           /* overrun count */
+                       char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+                       sigval_t _sigval;       /* same as below */
+                       int _sys_private;       /* not to be passed to user */
+               } _timer;
+
+               /* POSIX.1b signals */
+               struct {
+                       pid_t _pid;             /* sender's pid */
+                       __ARCH_SI_UID_T _uid;   /* sender's uid */
+                       sigval_t _sigval;
+               } _rt;
+
+               /* SIGCHLD */
+               struct {
+                       pid_t _pid;             /* which child */
+                       __ARCH_SI_UID_T _uid;   /* sender's uid */
+                       int _status;            /* exit code */
+                       clock_t _utime;
+                       clock_t _stime;
+               } _sigchld;
+
+               /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+               struct {
+                       void __user *_addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+                       int _trapno;    /* TRAP # which caused the signal */
+#endif
+               } _sigfault;
+
+               /* SIGPOLL */
+               struct {
+                       __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+                       int _fd;
+               } _sigpoll;
+       } _sifields;
+} siginfo_t;
+
+#endif
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid         _sifields._kill._pid
+#define si_uid         _sifields._kill._uid
+#define si_tid         _sifields._timer._tid
+#define si_overrun     _sifields._timer._overrun
+#define si_sys_private  _sifields._timer._sys_private
+#define si_status      _sifields._sigchld._status
+#define si_utime       _sifields._sigchld._utime
+#define si_stime       _sifields._sigchld._stime
+#define si_value       _sifields._rt._sigval
+#define si_int         _sifields._rt._sigval.sival_int
+#define si_ptr         _sifields._rt._sigval.sival_ptr
+#define si_addr                _sifields._sigfault._addr
+#ifdef __ARCH_SI_TRAPNO
+#define si_trapno      _sifields._sigfault._trapno
+#endif
+#define si_band                _sifields._sigpoll._band
+#define si_fd          _sifields._sigpoll._fd
+
+#ifdef __KERNEL__
+#define __SI_MASK      0xffff0000u
+#define __SI_KILL      (0 << 16)
+#define __SI_TIMER     (1 << 16)
+#define __SI_POLL      (2 << 16)
+#define __SI_FAULT     (3 << 16)
+#define __SI_CHLD      (4 << 16)
+#define __SI_RT                (5 << 16)
+#define __SI_MESGQ     (6 << 16)
+#define __SI_CODE(T,N) ((T) | ((N) & 0xffff))
+#else
+#define __SI_KILL      0
+#define __SI_TIMER     0
+#define __SI_POLL      0
+#define __SI_FAULT     0
+#define __SI_CHLD      0
+#define __SI_RT                0
+#define __SI_MESGQ     0
+#define __SI_CODE(T,N) (N)
+#endif
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER                0               /* sent by kill, sigsend, raise */
+#define SI_KERNEL      0x80            /* sent by the kernel from somewhere */
+#define SI_QUEUE       -1              /* sent by sigqueue */
+#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
+#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */
+#define SI_ASYNCIO     -4              /* sent by AIO completion */
+#define SI_SIGIO       -5              /* sent by queued SIGIO */
+#define SI_TKILL       -6              /* sent by tkill system call */
+#define SI_DETHREAD    -7              /* sent by execve() killing subsidiary threads */
+
+#define SI_FROMUSER(siptr)     ((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)   ((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC     (__SI_FAULT|1)  /* illegal opcode */
+#define ILL_ILLOPN     (__SI_FAULT|2)  /* illegal operand */
+#define ILL_ILLADR     (__SI_FAULT|3)  /* illegal addressing mode */
+#define ILL_ILLTRP     (__SI_FAULT|4)  /* illegal trap */
+#define ILL_PRVOPC     (__SI_FAULT|5)  /* privileged opcode */
+#define ILL_PRVREG     (__SI_FAULT|6)  /* privileged register */
+#define ILL_COPROC     (__SI_FAULT|7)  /* coprocessor error */
+#define ILL_BADSTK     (__SI_FAULT|8)  /* internal stack error */
+#define NSIGILL                8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV     (__SI_FAULT|1)  /* integer divide by zero */
+#define FPE_INTOVF     (__SI_FAULT|2)  /* integer overflow */
+#define FPE_FLTDIV     (__SI_FAULT|3)  /* floating point divide by zero */
+#define FPE_FLTOVF     (__SI_FAULT|4)  /* floating point overflow */
+#define FPE_FLTUND     (__SI_FAULT|5)  /* floating point underflow */
+#define FPE_FLTRES     (__SI_FAULT|6)  /* floating point inexact result */
+#define FPE_FLTINV     (__SI_FAULT|7)  /* floating point invalid operation */
+#define FPE_FLTSUB     (__SI_FAULT|8)  /* subscript out of range */
+#define NSIGFPE                8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR    (__SI_FAULT|1)  /* address not mapped to object */
+#define SEGV_ACCERR    (__SI_FAULT|2)  /* invalid permissions for mapped object */
+#define NSIGSEGV       2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN     (__SI_FAULT|1)  /* invalid address alignment */
+#define BUS_ADRERR     (__SI_FAULT|2)  /* non-existant physical address */
+#define BUS_OBJERR     (__SI_FAULT|3)  /* object specific hardware error */
+#define NSIGBUS                3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT     (__SI_FAULT|1)  /* process breakpoint */
+#define TRAP_TRACE     (__SI_FAULT|2)  /* process trace trap */
+#define NSIGTRAP       2
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED     (__SI_CHLD|1)   /* child has exited */
+#define CLD_KILLED     (__SI_CHLD|2)   /* child was killed */
+#define CLD_DUMPED     (__SI_CHLD|3)   /* child terminated abnormally */
+#define CLD_TRAPPED    (__SI_CHLD|4)   /* traced child has trapped */
+#define CLD_STOPPED    (__SI_CHLD|5)   /* child has stopped */
+#define CLD_CONTINUED  (__SI_CHLD|6)   /* stopped child has continued */
+#define NSIGCHLD       6
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN                (__SI_POLL|1)   /* data input available */
+#define POLL_OUT       (__SI_POLL|2)   /* output buffers available */
+#define POLL_MSG       (__SI_POLL|3)   /* input message available */
+#define POLL_ERR       (__SI_POLL|4)   /* i/o error */
+#define POLL_PRI       (__SI_POLL|5)   /* high priority input available */
+#define POLL_HUP       (__SI_POLL|6)   /* device disconnected */
+#define NSIGPOLL       6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL   0       /* notify via signal */
+#define SIGEV_NONE     1       /* other notification: meaningless */
+#define SIGEV_THREAD   2       /* deliver via thread creation */
+#define SIGEV_THREAD_ID 4      /* deliver to thread */
+
+/*
+ * This works because the alignment is ok on all current architectures
+ * but we leave open this being overridden in the future
+ */
+#ifndef __ARCH_SIGEV_PREAMBLE_SIZE
+#define __ARCH_SIGEV_PREAMBLE_SIZE     (sizeof(int) * 2 + sizeof(sigval_t))
+#endif
+
+#define SIGEV_MAX_SIZE 64
+#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \
+               / sizeof(int))
+
+typedef struct sigevent {
+       sigval_t sigev_value;
+       int sigev_signo;
+       int sigev_notify;
+       union {
+               int _pad[SIGEV_PAD_SIZE];
+                int _tid;
+
+               struct {
+                       void (*_function)(sigval_t);
+                       void *_attribute;       /* really pthread_attr_t */
+               } _sigev_thread;
+       } _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function  _sigev_un._sigev_thread._function
+#define sigev_notify_attributes        _sigev_un._sigev_thread._attribute
+#define sigev_notify_thread_id  _sigev_un._tid
+
+#ifdef __KERNEL__
+
+struct siginfo;
+void do_schedule_next_timer(struct siginfo *info);
+
+#ifndef HAVE_ARCH_COPY_SIGINFO
+
+#include <lwk/string.h>
+
+static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
+{
+       if (from->si_code < 0)
+               memcpy(to, from, sizeof(*to));
+       else
+               /* _sigchld is currently the largest know union member */
+               memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+}
+
+#endif
+
+extern int copy_siginfo_to_user(struct siginfo __user *to, struct siginfo *from);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/kitten/include/arch-generic/signal.h b/kitten/include/arch-generic/signal.h
new file mode 100644 (file)
index 0000000..d7bc924
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __ASM_GENERIC_SIGNAL_H
+#define __ASM_GENERIC_SIGNAL_H
+
+#include <lwk/compiler.h>
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK          0   /* for blocking signals */
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK        1   /* for unblocking signals */
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK        2   /* for setting the signal mask */
+#endif
+
+#ifndef __ASSEMBLY__
+typedef void __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
+
+typedef void __restorefn_t(void);
+typedef __restorefn_t __user *__sigrestore_t;
+
+#define SIG_DFL        ((__force __sighandler_t)0)     /* default signal handling */
+#define SIG_IGN        ((__force __sighandler_t)1)     /* ignore signal */
+#define SIG_ERR        ((__force __sighandler_t)-1)    /* error return from signal */
+#endif
+
+#endif /* __ASM_GENERIC_SIGNAL_H */
diff --git a/kitten/include/arch-generic/vmlwk.lds.h b/kitten/include/arch-generic/vmlwk.lds.h
new file mode 100644 (file)
index 0000000..9a9d3f4
--- /dev/null
@@ -0,0 +1,247 @@
+#ifndef LOAD_OFFSET
+#define LOAD_OFFSET 0
+#endif
+
+#ifndef VMLWK_SYMBOL
+#define VMLWK_SYMBOL(_sym_) _sym_
+#endif
+
+/* Align . to a 8 byte boundary equals to maximum function alignment. */
+#define ALIGN_FUNCTION()  . = ALIGN(8)
+
+/* .data section */
+#define DATA_DATA                                                      \
+       *(.data)                                                        \
+       *(.data.init.refok)
+
+#define RO_DATA(align)                                                 \
+       . = ALIGN((align));                                             \
+       .rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {           \
+               VMLWK_SYMBOL(__start_rodata) = .;                       \
+               *(.rodata) *(.rodata.*)                                 \
+               *(__vermagic)           /* Kernel version magic */      \
+       }                                                               \
+                                                                       \
+       .rodata1          : AT(ADDR(.rodata1) - LOAD_OFFSET) {          \
+               *(.rodata1)                                             \
+       }                                                               \
+                                                                       \
+       /* PCI quirks */                                                \
+       .pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {        \
+               VMLWK_SYMBOL(__start_pci_fixups_early) = .;             \
+               *(.pci_fixup_early)                                     \
+               VMLWK_SYMBOL(__end_pci_fixups_early) = .;               \
+               VMLWK_SYMBOL(__start_pci_fixups_header) = .;            \
+               *(.pci_fixup_header)                                    \
+               VMLWK_SYMBOL(__end_pci_fixups_header) = .;              \
+               VMLWK_SYMBOL(__start_pci_fixups_final) = .;             \
+               *(.pci_fixup_final)                                     \
+               VMLWK_SYMBOL(__end_pci_fixups_final) = .;               \
+               VMLWK_SYMBOL(__start_pci_fixups_enable) = .;            \
+               *(.pci_fixup_enable)                                    \
+               VMLWK_SYMBOL(__end_pci_fixups_enable) = .;              \
+               VMLWK_SYMBOL(__start_pci_fixups_resume) = .;            \
+               *(.pci_fixup_resume)                                    \
+               VMLWK_SYMBOL(__end_pci_fixups_resume) = .;              \
+       }                                                               \
+                                                                       \
+       /* RapidIO route ops */                                         \
+       .rio_route        : AT(ADDR(.rio_route) - LOAD_OFFSET) {        \
+               VMLWK_SYMBOL(__start_rio_route_ops) = .;                \
+               *(.rio_route_ops)                                       \
+               VMLWK_SYMBOL(__end_rio_route_ops) = .;                  \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: Normal symbols */                       \
+       __ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {         \
+               VMLWK_SYMBOL(__start___ksymtab) = .;                    \
+               *(__ksymtab)                                            \
+               VMLWK_SYMBOL(__stop___ksymtab) = .;                     \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only symbols */                     \
+       __ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {     \
+               VMLWK_SYMBOL(__start___ksymtab_gpl) = .;                \
+               *(__ksymtab_gpl)                                        \
+               VMLWK_SYMBOL(__stop___ksymtab_gpl) = .;                 \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: Normal unused symbols */                \
+       __ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {  \
+               VMLWK_SYMBOL(__start___ksymtab_unused) = .;             \
+               *(__ksymtab_unused)                                     \
+               VMLWK_SYMBOL(__stop___ksymtab_unused) = .;              \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only unused symbols */              \
+       __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
+               VMLWK_SYMBOL(__start___ksymtab_unused_gpl) = .;         \
+               *(__ksymtab_unused_gpl)                                 \
+               VMLWK_SYMBOL(__stop___ksymtab_unused_gpl) = .;          \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-future-only symbols */              \
+       __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+               VMLWK_SYMBOL(__start___ksymtab_gpl_future) = .;         \
+               *(__ksymtab_gpl_future)                                 \
+               VMLWK_SYMBOL(__stop___ksymtab_gpl_future) = .;          \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: Normal symbols */                       \
+       __kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {         \
+               VMLWK_SYMBOL(__start___kcrctab) = .;                    \
+               *(__kcrctab)                                            \
+               VMLWK_SYMBOL(__stop___kcrctab) = .;                     \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only symbols */                     \
+       __kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {     \
+               VMLWK_SYMBOL(__start___kcrctab_gpl) = .;                \
+               *(__kcrctab_gpl)                                        \
+               VMLWK_SYMBOL(__stop___kcrctab_gpl) = .;                 \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: Normal unused symbols */                \
+       __kcrctab_unused  : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) {  \
+               VMLWK_SYMBOL(__start___kcrctab_unused) = .;             \
+               *(__kcrctab_unused)                                     \
+               VMLWK_SYMBOL(__stop___kcrctab_unused) = .;              \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-only unused symbols */              \
+       __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
+               VMLWK_SYMBOL(__start___kcrctab_unused_gpl) = .;         \
+               *(__kcrctab_unused_gpl)                                 \
+               VMLWK_SYMBOL(__stop___kcrctab_unused_gpl) = .;          \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: GPL-future-only symbols */              \
+       __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+               VMLWK_SYMBOL(__start___kcrctab_gpl_future) = .;         \
+               *(__kcrctab_gpl_future)                                 \
+               VMLWK_SYMBOL(__stop___kcrctab_gpl_future) = .;          \
+       }                                                               \
+                                                                       \
+       /* Kernel symbol table: strings */                              \
+        __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {        \
+               *(__ksymtab_strings)                                    \
+       }                                                               \
+                                                                       \
+       /* Built-in module parameters. */                               \
+       __param : AT(ADDR(__param) - LOAD_OFFSET) {                     \
+               VMLWK_SYMBOL(__start___param) = .;                      \
+               *(__param)                                              \
+               VMLWK_SYMBOL(__stop___param) = .;                       \
+               VMLWK_SYMBOL(__end_rodata) = .;                         \
+       }                                                               \
+                                                                       \
+       . = ALIGN((align));
+
+/* RODATA provided for backward compatibility.
+ * All archs are supposed to use RO_DATA() */
+#define RODATA RO_DATA(4096)
+
+#define SECURITY_INIT                                                  \
+       .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
+               VMLWK_SYMBOL(__security_initcall_start) = .;            \
+               *(.security_initcall.init)                              \
+               VMLWK_SYMBOL(__security_initcall_end) = .;              \
+       }
+
+/* .text section. Map to function alignment to avoid address changes
+ * during second ld run in second ld pass when generating System.map */
+#define TEXT_TEXT                                                      \
+               ALIGN_FUNCTION();                                       \
+               *(.text)                                                \
+               *(.text.init.refok)
+
+/* sched.text is aling to function alignment to secure we have same
+ * address even at second ld pass when generating System.map */
+#define SCHED_TEXT                                                     \
+               ALIGN_FUNCTION();                                       \
+               VMLWK_SYMBOL(__sched_text_start) = .;                   \
+               *(.sched.text)                                          \
+               VMLWK_SYMBOL(__sched_text_end) = .;
+
+/* spinlock.text is aling to function alignment to secure we have same
+ * address even at second ld pass when generating System.map */
+#define LOCK_TEXT                                                      \
+               ALIGN_FUNCTION();                                       \
+               VMLWK_SYMBOL(__lock_text_start) = .;                    \
+               *(.spinlock.text)                                       \
+               VMLWK_SYMBOL(__lock_text_end) = .;
+
+#define KPROBES_TEXT                                                   \
+               ALIGN_FUNCTION();                                       \
+               VMLWK_SYMBOL(__kprobes_text_start) = .;                 \
+               *(.kprobes.text)                                        \
+               VMLWK_SYMBOL(__kprobes_text_end) = .;
+
+               /* DWARF debug sections.
+               Symbols in the DWARF debugging sections are relative to
+               the beginning of the section so we begin them at 0.  */
+#define DWARF_DEBUG                                                    \
+               /* DWARF 1 */                                           \
+               .debug          0 : { *(.debug) }                       \
+               .line           0 : { *(.line) }                        \
+               /* GNU DWARF 1 extensions */                            \
+               .debug_srcinfo  0 : { *(.debug_srcinfo) }               \
+               .debug_sfnames  0 : { *(.debug_sfnames) }               \
+               /* DWARF 1.1 and DWARF 2 */                             \
+               .debug_aranges  0 : { *(.debug_aranges) }               \
+               .debug_pubnames 0 : { *(.debug_pubnames) }              \
+               /* DWARF 2 */                                           \
+               .debug_info     0 : { *(.debug_info                     \
+                               .gnu.linkonce.wi.*) }                   \
+               .debug_abbrev   0 : { *(.debug_abbrev) }                \
+               .debug_line     0 : { *(.debug_line) }                  \
+               .debug_frame    0 : { *(.debug_frame) }                 \
+               .debug_str      0 : { *(.debug_str) }                   \
+               .debug_loc      0 : { *(.debug_loc) }                   \
+               .debug_macinfo  0 : { *(.debug_macinfo) }               \
+               /* SGI/MIPS DWARF 2 extensions */                       \
+               .debug_weaknames 0 : { *(.debug_weaknames) }            \
+               .debug_funcnames 0 : { *(.debug_funcnames) }            \
+               .debug_typenames 0 : { *(.debug_typenames) }            \
+               .debug_varnames  0 : { *(.debug_varnames) }             \
+
+               /* Stabs debugging sections.  */
+#define STABS_DEBUG                                                    \
+               .stab 0 : { *(.stab) }                                  \
+               .stabstr 0 : { *(.stabstr) }                            \
+               .stab.excl 0 : { *(.stab.excl) }                        \
+               .stab.exclstr 0 : { *(.stab.exclstr) }                  \
+               .stab.index 0 : { *(.stab.index) }                      \
+               .stab.indexstr 0 : { *(.stab.indexstr) }                \
+               .comment 0 : { *(.comment) }
+
+#define BUG_TABLE                                                      \
+       . = ALIGN(8);                                                   \
+       __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) {             \
+               __start___bug_table = .;                                \
+               *(__bug_table)                                          \
+               __stop___bug_table = .;                                 \
+       }
+
+#define NOTES                                                          \
+       .notes : { *(.note.*) } :note
+
+#define INITCALLS                                                      \
+       *(.initcall0.init)                                              \
+       *(.initcall0s.init)                                             \
+       *(.initcall1.init)                                              \
+       *(.initcall1s.init)                                             \
+       *(.initcall2.init)                                              \
+       *(.initcall2s.init)                                             \
+       *(.initcall3.init)                                              \
+       *(.initcall3s.init)                                             \
+       *(.initcall4.init)                                              \
+       *(.initcall4s.init)                                             \
+       *(.initcall5.init)                                              \
+       *(.initcall5s.init)                                             \
+       *(.initcallrootfs.init)                                         \
+       *(.initcall6.init)                                              \
+       *(.initcall6s.init)                                             \
+       *(.initcall7.init)                                              \
+       *(.initcall7s.init)
+
diff --git a/kitten/include/arch-x86_64/apic.h b/kitten/include/arch-x86_64/apic.h
new file mode 100644 (file)
index 0000000..4839a16
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef __ASM_APIC_H
+#define __ASM_APIC_H
+
+#include <lwk/init.h>
+#include <arch/fixmap.h>
+#include <arch/apicdef.h>
+#include <arch/system.h>
+
+/*
+ * Debugging macros
+ */
+#define APIC_QUIET   0
+#define APIC_VERBOSE 1
+#define APIC_DEBUG   2
+
+extern int apic_verbosity;
+extern int apic_runs_main_timer;
+
+extern unsigned long lapic_phys_addr;
+
+/*
+ * Define the default level of output to be very little
+ * This can be turned up by using apic=verbose for more
+ * information and apic=debug for _lots_ of information.
+ * apic_verbosity is defined in apic.c
+ */
+#define apic_printk(v, s, a...) do {       \
+               if ((v) <= apic_verbosity) \
+                       printk(s, ##a);    \
+       } while (0)
+
+struct pt_regs;
+
+/*
+ * Basic functions accessing APICs.
+ */
+
+static __inline void apic_write(unsigned long reg, uint32_t val)
+{
+       *((volatile uint32_t *)(APIC_BASE+reg)) = val;
+}
+
+static __inline uint32_t apic_read(unsigned long reg)
+{
+       return *((volatile uint32_t *)(APIC_BASE+reg));
+}
+
+static inline void lapic_ack_interrupt(void)
+{
+       /*
+        * This gets compiled to a single instruction:
+        *      movl   $0x0,0xffffffffffdfe0b0
+        *
+        * Docs say use 0 for future compatibility.
+        */
+       apic_write(APIC_EOI, 0);
+}
+
+extern void clear_local_APIC (void);
+extern void connect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (int virt_wire_setup);
+extern void disable_local_APIC (void);
+extern int verify_local_APIC (void);
+extern void cache_APIC_registers (void);
+extern void sync_Arb_IDs (void);
+extern void init_bsp_APIC (void);
+extern void setup_local_APIC (void);
+extern void init_apic_mappings (void);
+extern void smp_local_timer_interrupt (struct pt_regs * regs);
+extern void setup_boot_APIC_clock (void);
+extern void setup_secondary_APIC_clock (void);
+extern void setup_apic_nmi_watchdog (void);
+extern int reserve_lapic_nmi(void);
+extern void release_lapic_nmi(void);
+extern void disable_timer_nmi_watchdog(void);
+extern void enable_timer_nmi_watchdog(void);
+extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
+extern int APIC_init_uniprocessor (void);
+extern void disable_APIC_timer(void);
+extern void enable_APIC_timer(void);
+extern void clustered_apic_check(void);
+
+extern void nmi_watchdog_default(void);
+extern int setup_nmi_watchdog(char *);
+
+extern unsigned int nmi_watchdog;
+#define NMI_DEFAULT    -1
+#define NMI_NONE       0
+#define NMI_IO_APIC    1
+#define NMI_LOCAL_APIC 2
+#define NMI_INVALID    3
+
+extern int disable_timer_pin_1;
+
+extern void setup_threshold_lvt(unsigned long lvt_off);
+
+void smp_send_timer_broadcast_ipi(void);
+void switch_APIC_timer_to_ipi(void *cpumask);
+void switch_ipi_to_APIC_timer(void *cpumask);
+
+#define ARCH_APICTIMER_STOPS_ON_C3     1
+
+extern unsigned boot_cpu_id;
+
+extern void __init lapic_map(void);
+extern void __init lapic_init(void);
+extern void lapic_set_timer(uint32_t count);
+extern unsigned int lapic_calibrate_timer(void);
+extern void lapic_dump(void);
+extern void lapic_send_init_ipi(unsigned int cpu);
+extern void lapic_send_startup_ipi(unsigned int cpu, unsigned long start_rip);
+extern void lapic_send_ipi(unsigned int cpu, unsigned int vector);
+
+#endif /* __ASM_APIC_H */
diff --git a/kitten/include/arch-x86_64/apicdef.h b/kitten/include/arch-x86_64/apicdef.h
new file mode 100644 (file)
index 0000000..35c0580
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __ASM_APICDEF_H
+#define __ASM_APICDEF_H
+
+/*
+ * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
+ *
+ * Alan Cox <Alan.Cox@linux.org>, 1995.
+ * Ingo Molnar <mingo@redhat.com>, 1999, 2000
+ */
+
+#define                APIC_DEFAULT_PHYS_BASE  0xfee00000
+#define                APIC_ID         0x20
+#define                        APIC_ID_MASK            (0xFFu<<24)
+#define                        GET_APIC_ID(x)          (((x)>>24)&0xFFu)
+#define                        SET_APIC_ID(x)          (((x)<<24))
+#define                APIC_LVR        0x30
+#define                        APIC_LVR_MASK           0xFF00FF
+#define                        GET_APIC_VERSION(x)     ((x)&0xFFu)
+#define                        GET_APIC_MAXLVT(x)      (((x)>>16)&0xFFu)
+#define                        APIC_INTEGRATED(x)      ((x)&0xF0u)
+#define                APIC_TASKPRI    0x80
+#define                        APIC_TPRI_MASK          0xFFu
+#define                APIC_ARBPRI     0x90
+#define                        APIC_ARBPRI_MASK        0xFFu
+#define                APIC_PROCPRI    0xA0
+#define                APIC_EOI        0xB0
+#define                        APIC_EIO_ACK            0x0             /* Write this to the EOI register */
+#define                APIC_RRR        0xC0
+#define                APIC_LDR        0xD0
+#define                        APIC_LDR_MASK           (0xFFu<<24)
+#define                        GET_APIC_LOGICAL_ID(x)  (((x)>>24)&0xFFu)
+#define                        SET_APIC_LOGICAL_ID(x)  (((x)<<24))
+#define                        APIC_ALL_CPUS           0xFFu
+#define                APIC_DFR        0xE0
+#define                        APIC_DFR_CLUSTER                0x0FFFFFFFul
+#define                        APIC_DFR_FLAT                   0xFFFFFFFFul
+#define                APIC_SPIV       0xF0
+#define                        APIC_SPIV_FOCUS_DISABLED        (1<<9)
+#define                        APIC_SPIV_APIC_ENABLED          (1<<8)
+#define                APIC_ISR        0x100
+#define                APIC_ISR_NR     0x8     /* Number of 32 bit ISR registers. */
+#define                APIC_TMR        0x180
+#define        APIC_IRR        0x200
+#define        APIC_ESR        0x280
+#define                        APIC_ESR_SEND_CS        0x00001
+#define                        APIC_ESR_RECV_CS        0x00002
+#define                        APIC_ESR_SEND_ACC       0x00004
+#define                        APIC_ESR_RECV_ACC       0x00008
+#define                        APIC_ESR_SENDILL        0x00020
+#define                        APIC_ESR_RECVILL        0x00040
+#define                        APIC_ESR_ILLREGA        0x00080
+#define                APIC_ICR        0x300
+#define                        APIC_DEST_SELF          0x40000
+#define                        APIC_DEST_ALLINC        0x80000
+#define                        APIC_DEST_ALLBUT        0xC0000
+#define                        APIC_ICR_RR_MASK        0x30000
+#define                        APIC_ICR_RR_INVALID     0x00000
+#define                        APIC_ICR_RR_INPROG      0x10000
+#define                        APIC_ICR_RR_VALID       0x20000
+#define                        APIC_INT_LEVELTRIG      0x08000
+#define                        APIC_INT_ASSERT         0x04000
+#define                        APIC_ICR_BUSY           0x01000
+#define                        APIC_DEST_LOGICAL       0x00800
+#define                        APIC_DEST_PHYSICAL      0x00000
+#define                        APIC_DM_FIXED           0x00000
+#define                        APIC_DM_LOWEST          0x00100
+#define                        APIC_DM_SMI             0x00200
+#define                        APIC_DM_REMRD           0x00300
+#define                        APIC_DM_NMI             0x00400
+#define                        APIC_DM_INIT            0x00500
+#define                        APIC_DM_STARTUP         0x00600
+#define                        APIC_DM_EXTINT          0x00700
+#define                        APIC_VECTOR_MASK        0x000FF
+#define                APIC_ICR2       0x310
+#define                        GET_APIC_DEST_FIELD(x)  (((x)>>24)&0xFF)
+#define                        SET_APIC_DEST_FIELD(x)  ((x)<<24)
+#define                APIC_LVTT       0x320
+#define                APIC_LVTTHMR    0x330
+#define                APIC_LVTPC      0x340
+#define                APIC_LVT0       0x350
+#define                        APIC_LVT_TIMER_BASE_MASK        (0x3<<18)
+#define                        GET_APIC_TIMER_BASE(x)          (((x)>>18)&0x3)
+#define                        SET_APIC_TIMER_BASE(x)          (((x)<<18))
+#define                        APIC_TIMER_BASE_CLKIN           0x0
+#define                        APIC_TIMER_BASE_TMBASE          0x1
+#define                        APIC_TIMER_BASE_DIV             0x2
+#define                        APIC_LVT_TIMER_PERIODIC         (1<<17)
+#define                        APIC_LVT_MASKED                 (1<<16)
+#define                        APIC_LVT_LEVEL_TRIGGER          (1<<15)
+#define                        APIC_LVT_REMOTE_IRR             (1<<14)
+#define                        APIC_INPUT_POLARITY             (1<<13)
+#define                        APIC_SEND_PENDING               (1<<12)
+#define                        APIC_MODE_MASK                  0x700
+#define                        GET_APIC_DELIVERY_MODE(x)       (((x)>>8)&0x7)
+#define                        SET_APIC_DELIVERY_MODE(x,y)     (((x)&~0x700)|((y)<<8))
+#define                                APIC_MODE_FIXED         0x0
+#define                                APIC_MODE_NMI           0x4
+#define                                APIC_MODE_EXTINT        0x7
+#define        APIC_LVT1       0x360
+#define                APIC_LVTERR     0x370
+#define                APIC_TMICT      0x380
+#define                APIC_TMCCT      0x390
+#define                APIC_TDCR       0x3E0
+#define                        APIC_TDR_DIV_TMBASE     (1<<2)
+#define                        APIC_TDR_DIV_1          0xB
+#define                        APIC_TDR_DIV_2          0x0
+#define                        APIC_TDR_DIV_4          0x1
+#define                        APIC_TDR_DIV_8          0x2
+#define                        APIC_TDR_DIV_16         0x3
+#define                        APIC_TDR_DIV_32         0x8
+#define                        APIC_TDR_DIV_64         0x9
+#define                        APIC_TDR_DIV_128        0xA
+
+#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
+
+#define MAX_IO_APICS 16
+#define MAX_LOCAL_APIC 256
+
+/*
+ * All x86-64 systems are xAPIC compatible.
+ * In the following, "apicid" is a physical APIC ID.
+ */
+#define XAPIC_DEST_CPUS_SHIFT  4
+#define XAPIC_DEST_CPUS_MASK   ((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
+#define XAPIC_DEST_CLUSTER_MASK        (XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)
+#define APIC_CLUSTER(apicid)   ((apicid) & XAPIC_DEST_CLUSTER_MASK)
+#define APIC_CLUSTERID(apicid) (APIC_CLUSTER(apicid) >> XAPIC_DEST_CPUS_SHIFT)
+#define APIC_CPUID(apicid)     ((apicid) & XAPIC_DEST_CPUS_MASK)
+#define NUM_APIC_CLUSTERS      ((BAD_APICID + 1) >> XAPIC_DEST_CPUS_SHIFT)
+
+#define BAD_APICID 0xFFu
+
+#endif
diff --git a/kitten/include/arch-x86_64/aspace.h b/kitten/include/arch-x86_64/aspace.h
new file mode 100644 (file)
index 0000000..2fc31d5
--- /dev/null
@@ -0,0 +1,16 @@
+/* Copyright (c) 2007, Sandia National Laboratories */
+
+#ifndef _ARCH_X86_64_ASPACE_H
+#define _ARCH_X86_64_ASPACE_H
+
+#ifdef __KERNEL__
+#include <arch/page_table.h>
+
+struct arch_aspace {
+       xpte_t *pgd;    /* Page global directory... root page table */
+};
+#endif
+
+#define SMARTMAP_ALIGN 0x8000000000UL  /* Each PML4T entry covers 512 GB */
+
+#endif
diff --git a/kitten/include/arch-x86_64/atomic.h b/kitten/include/arch-x86_64/atomic.h
new file mode 100644 (file)
index 0000000..1eccfc3
--- /dev/null
@@ -0,0 +1,427 @@
+#ifndef _X86_64_ATOMIC_H
+#define _X86_64_ATOMIC_H
+
+/* atomic_t should be 32 bit signed type */
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically reads the value of @v.
+ */ 
+#define atomic_read(v)         ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ * 
+ * Atomically sets the value of @v to @i.
+ */ 
+#define atomic_set(v,i)                (((v)->counter) = (i))
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically adds @i to @v.
+ */
+static __inline__ void atomic_add(int i, atomic_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; addl %1,%0"
+               :"=m" (v->counter)
+               :"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically subtracts @i from @v.
+ */
+static __inline__ void atomic_sub(int i, atomic_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; subl %1,%0"
+               :"=m" (v->counter)
+               :"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; subl %2,%0; sete %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"ir" (i), "m" (v->counter) : "memory");
+       return c;
+}
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1.
+ */ 
+static __inline__ void atomic_inc(atomic_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; incl %0"
+               :"=m" (v->counter)
+               :"m" (v->counter));
+}
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1.
+ */ 
+static __inline__ void atomic_dec(atomic_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; decl %0"
+               :"=m" (v->counter)
+               :"m" (v->counter));
+}
+
+/**
+ * atomic_dec_and_test - decrement and test
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */ 
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; decl %0; sete %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"m" (v->counter) : "memory");
+       return c != 0;
+}
+
+/**
+ * atomic_inc_and_test - increment and test 
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */ 
+static __inline__ int atomic_inc_and_test(atomic_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; incl %0; sete %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"m" (v->counter) : "memory");
+       return c != 0;
+}
+
+/**
+ * atomic_add_negative - add and test if negative
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */ 
+static __inline__ int atomic_add_negative(int i, atomic_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; addl %2,%0; sets %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"ir" (i), "m" (v->counter) : "memory");
+       return c;
+}
+
+/**
+ * atomic_add_return - add and return
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v and returns @i + @v
+ */
+static __inline__ int atomic_add_return(int i, atomic_t *v)
+{
+       int __i = i;
+       __asm__ __volatile__(
+               "lock ; xaddl %0, %1;"
+               :"=r"(i)
+               :"m"(v->counter), "0"(i));
+       return i + __i;
+}
+
+static __inline__ int atomic_sub_return(int i, atomic_t *v)
+{
+       return atomic_add_return(-i,v);
+}
+
+#define atomic_inc_return(v)  (atomic_add_return(1,v))
+#define atomic_dec_return(v)  (atomic_sub_return(1,v))
+
+/* An 64bit atomic type */
+
+typedef struct { volatile long counter; } atomic64_t;
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+/**
+ * atomic64_read - read atomic64 variable
+ * @v: pointer of type atomic64_t
+ *
+ * Atomically reads the value of @v.
+ * Doesn't imply a read memory barrier.
+ */
+#define atomic64_read(v)               ((v)->counter)
+
+/**
+ * atomic64_set - set atomic64 variable
+ * @v: pointer to type atomic64_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.
+ */
+#define atomic64_set(v,i)              (((v)->counter) = (i))
+
+/**
+ * atomic64_add - add integer to atomic64 variable
+ * @i: integer value to add
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically adds @i to @v.
+ */
+static __inline__ void atomic64_add(long i, atomic64_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; addq %1,%0"
+               :"=m" (v->counter)
+               :"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic64_sub - subtract the atomic64 variable
+ * @i: integer value to subtract
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically subtracts @i from @v.
+ */
+static __inline__ void atomic64_sub(long i, atomic64_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; subq %1,%0"
+               :"=m" (v->counter)
+               :"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic64_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int atomic64_sub_and_test(long i, atomic64_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; subq %2,%0; sete %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"ir" (i), "m" (v->counter) : "memory");
+       return c;
+}
+
+/**
+ * atomic64_inc - increment atomic64 variable
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically increments @v by 1.
+ */
+static __inline__ void atomic64_inc(atomic64_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; incq %0"
+               :"=m" (v->counter)
+               :"m" (v->counter));
+}
+
+/**
+ * atomic64_dec - decrement atomic64 variable
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically decrements @v by 1.
+ */
+static __inline__ void atomic64_dec(atomic64_t *v)
+{
+       __asm__ __volatile__(
+               "lock ; decq %0"
+               :"=m" (v->counter)
+               :"m" (v->counter));
+}
+
+/**
+ * atomic64_dec_and_test - decrement and test
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+static __inline__ int atomic64_dec_and_test(atomic64_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; decq %0; sete %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"m" (v->counter) : "memory");
+       return c != 0;
+}
+
+/**
+ * atomic64_inc_and_test - increment and test
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int atomic64_inc_and_test(atomic64_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; incq %0; sete %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"m" (v->counter) : "memory");
+       return c != 0;
+}
+
+/**
+ * atomic64_add_negative - add and test if negative
+ * @i: integer value to add
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+static __inline__ int atomic64_add_negative(long i, atomic64_t *v)
+{
+       unsigned char c;
+
+       __asm__ __volatile__(
+               "lock ; addq %2,%0; sets %1"
+               :"=m" (v->counter), "=qm" (c)
+               :"ir" (i), "m" (v->counter) : "memory");
+       return c;
+}
+
+/**
+ * atomic64_add_return - add and return
+ * @i: integer value to add
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically adds @i to @v and returns @i + @v
+ */
+static __inline__ long atomic64_add_return(long i, atomic64_t *v)
+{
+       long __i = i;
+       __asm__ __volatile__(
+               "lock ; xaddq %0, %1;"
+               :"=r"(i)
+               :"m"(v->counter), "0"(i));
+       return i + __i;
+}
+
+static __inline__ long atomic64_sub_return(long i, atomic64_t *v)
+{
+       return atomic64_add_return(-i,v);
+}
+
+#define atomic64_inc_return(v)  (atomic64_add_return(1,v))
+#define atomic64_dec_return(v)  (atomic64_sub_return(1,v))
+
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)                             \
+({                                                             \
+       int c, old;                                             \
+       c = atomic_read(v);                                     \
+       for (;;) {                                              \
+               if (unlikely(c == (u)))                         \
+                       break;                                  \
+               old = atomic_cmpxchg((v), c, c + (a));          \
+               if (likely(old == c))                           \
+                       break;                                  \
+               c = old;                                        \
+       }                                                       \
+       c != (u);                                               \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+/* These are x86-specific, used by some header files */
+#define atomic_clear_mask(mask, addr) \
+__asm__ __volatile__("lock ; andl %0,%1" \
+: : "r" (~(mask)),"m" (*addr) : "memory")
+
+#define atomic_set_mask(mask, addr) \
+__asm__ __volatile__("lock ; orl %0,%1" \
+: : "r" ((unsigned)mask),"m" (*(addr)) : "memory")
+
+/* Atomic operations are already serializing on x86 */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec()     barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc()     barrier()
+
+#include <arch-generic/atomic.h>
+#endif
diff --git a/kitten/include/arch-x86_64/auxvec.h b/kitten/include/arch-x86_64/auxvec.h
new file mode 100644 (file)
index 0000000..1d5ab0d
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_X86_64_AUXVEC_H
+#define __ASM_X86_64_AUXVEC_H
+
+#define AT_SYSINFO_EHDR                33
+
+#endif
diff --git a/kitten/include/arch-x86_64/bitops.h b/kitten/include/arch-x86_64/bitops.h
new file mode 100644 (file)
index 0000000..18d8f3d
--- /dev/null
@@ -0,0 +1,402 @@
+#ifndef _X86_64_BITOPS_H
+#define _X86_64_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ */
+
+#define ADDR (*(volatile long *) addr)
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static __inline__ void set_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__(
+               "lock ; btsl %1,%0"
+               :"+m" (ADDR)
+               :"dIr" (nr) : "memory");
+}
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void __set_bit(int nr, volatile void * addr)
+{
+       __asm__ volatile(
+               "btsl %1,%0"
+               :"+m" (ADDR)
+               :"dIr" (nr) : "memory");
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
+static __inline__ void clear_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__(
+               "lock ; btrl %1,%0"
+               :"+m" (ADDR)
+               :"dIr" (nr));
+}
+
+static __inline__ void __clear_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__(
+               "btrl %1,%0"
+               :"+m" (ADDR)
+               :"dIr" (nr));
+}
+
+#define smp_mb__before_clear_bit()     barrier()
+#define smp_mb__after_clear_bit()      barrier()
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to change
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__(
+               "btcl %1,%0"
+               :"+m" (ADDR)
+               :"dIr" (nr));
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static __inline__ void change_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__(
+               "lock ; btcl %1,%0"
+               :"+m" (ADDR)
+               :"dIr" (nr));
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "lock ; btsl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"+m" (ADDR)
+               :"dIr" (nr) : "memory");
+       return oldbit;
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__(
+               "btsl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"+m" (ADDR)
+               :"dIr" (nr));
+       return oldbit;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "lock ; btrl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"+m" (ADDR)
+               :"dIr" (nr) : "memory");
+       return oldbit;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__(
+               "btrl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"+m" (ADDR)
+               :"dIr" (nr));
+       return oldbit;
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "btcl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"+m" (ADDR)
+               :"dIr" (nr) : "memory");
+       return oldbit;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_change_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "lock ; btcl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"+m" (ADDR)
+               :"dIr" (nr) : "memory");
+       return oldbit;
+}
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet */
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static int test_bit(int nr, const volatile void * addr);
+#endif
+
+static __inline__ int constant_test_bit(int nr, const volatile void * addr)
+{
+       return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
+}
+
+static __inline__ int variable_test_bit(int nr, volatile const void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "btl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit)
+               :"m" (ADDR),"dIr" (nr));
+       return oldbit;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ constant_test_bit((nr),(addr)) : \
+ variable_test_bit((nr),(addr)))
+
+#undef ADDR
+
+extern long find_first_zero_bit(const unsigned long * addr, unsigned long size);
+extern long find_next_zero_bit (const unsigned long * addr, long size, long offset);
+extern long find_first_bit(const unsigned long * addr, unsigned long size);
+extern long find_next_bit(const unsigned long * addr, long size, long offset);
+
+/* return index of first bet set in val or max when no bit is set */
+static inline unsigned long __scanbit(unsigned long val, unsigned long max)
+{
+       asm("bsfq %1,%0 ; cmovz %2,%0" : "=&r" (val) : "r" (val), "r" (max));
+       return val;
+}
+
+#define find_first_bit(addr,size) \
+((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ? \
+  (__scanbit(*(unsigned long *)addr,(size))) : \
+  find_first_bit(addr,size)))
+
+#define find_next_bit(addr,size,off) \
+((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ?        \
+  ((off) + (__scanbit((*(unsigned long *)addr) >> (off),(size)-(off)))) : \
+       find_next_bit(addr,size,off)))
+
+#define find_first_zero_bit(addr,size) \
+((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ? \
+  (__scanbit(~*(unsigned long *)addr,(size))) : \
+       find_first_zero_bit(addr,size)))
+       
+#define find_next_zero_bit(addr,size,off) \
+((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ?        \
+  ((off)+(__scanbit(~(((*(unsigned long *)addr)) >> (off)),(size)-(off)))) : \
+       find_next_zero_bit(addr,size,off)))
+
+/* 
+ * Find string of zero bits in a bitmap. -1 when not found.
+ */ 
+extern unsigned long 
+find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len);
+
+static inline void set_bit_string(unsigned long *bitmap, unsigned long i, 
+                                 int len) 
+{ 
+       unsigned long end = i + len; 
+       while (i < end) {
+               __set_bit(i, bitmap); 
+               i++;
+       }
+} 
+
+static inline void __clear_bit_string(unsigned long *bitmap, unsigned long i, 
+                                   int len) 
+{ 
+       unsigned long end = i + len; 
+       while (i < end) {
+               __clear_bit(i, bitmap); 
+               i++;
+       }
+} 
+
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static __inline__ unsigned long ffz(unsigned long word)
+{
+       __asm__("bsfq %1,%0"
+               :"=r" (word)
+               :"r" (~word));
+       return word;
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+       __asm__("bsfq %1,%0"
+               :"=r" (word)
+               :"rm" (word));
+       return word;
+}
+
+/*
+ * __fls: find last bit set.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static __inline__ unsigned long __fls(unsigned long word)
+{
+       __asm__("bsrq %1,%0"
+               :"=r" (word)
+               :"rm" (word));
+       return word;
+}
+
+#ifdef __KERNEL__
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static __inline__ int ffs(int x)
+{
+       int r;
+
+       __asm__("bsfl %1,%0\n\t"
+               "cmovzl %2,%0" 
+               : "=r" (r) : "rm" (x), "r" (-1));
+       return r+1;
+}
+
+/**
+ * fls64 - find last bit set in 64 bit word
+ * @x: the word to search
+ *
+ * This is defined the same way as fls.
+ */
+static __inline__ int fls64(__u64 x)
+{
+       if (x == 0)
+               return 0;
+       return __fls(x) + 1;
+}
+
+/**
+ * fls - find last bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ */
+static __inline__ int fls(int x)
+{
+       int r;
+
+       __asm__("bsrl %1,%0\n\t"
+               "cmovzl %2,%0"
+               : "=&r" (r) : "rm" (x), "rm" (-1));
+       return r+1;
+}
+
+#include <arch-generic/bitops/hweight.h>
+
+#endif /* __KERNEL__ */
+
+#endif /* _X86_64_BITOPS_H */
diff --git a/kitten/include/arch-x86_64/boot.h b/kitten/include/arch-x86_64/boot.h
new file mode 100644 (file)
index 0000000..f9a2f29
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _ARCH_BOOT_H
+#define _ARCH_BOOT_H
+
+/* Don't touch these, unless you really know what you're doing. */
+#define DEF_INITSEG    0x9000
+#define DEF_SYSSEG     0x1000
+#define DEF_SETUPSEG   0x9020
+#define DEF_SYSSIZE    0x7F00
+
+#endif
diff --git a/kitten/include/arch-x86_64/bootsetup.h b/kitten/include/arch-x86_64/bootsetup.h
new file mode 100644 (file)
index 0000000..e58a721
--- /dev/null
@@ -0,0 +1,47 @@
+
+#ifndef _X86_64_BOOTSETUP_H
+#define _X86_64_BOOTSETUP_H 1
+
+#define BOOT_PARAM_SIZE                4096
+extern char x86_boot_params[BOOT_PARAM_SIZE];
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM  ((unsigned char *)x86_boot_params)
+#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
+#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
+#define ALT_MEM_K (*(unsigned int *) (PARAM+0x1e0))
+#define E820_MAP_NR (*(char*) (PARAM+E820NR))
+#define E820_MAP    ((struct e820entry *) (PARAM+E820MAP))
+#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
+#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
+#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
+#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
+#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
+#define SAVED_VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
+#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
+#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
+#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+#define KERNEL_START (*(unsigned int *) (PARAM+0x214))
+#define INITRD_START (*(unsigned int *) (PARAM+0x218))
+#define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c))
+#define EDID_INFO (*(struct edid_info *) (PARAM+0x140))
+#define EDD_NR     (*(unsigned char *) (PARAM+EDDNR))
+#define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF))
+#define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
+#define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
+#define COMMAND_LINE saved_command_line
+
+#define RAMDISK_IMAGE_START_MASK       0x07FF
+#define RAMDISK_PROMPT_FLAG            0x8000
+#define RAMDISK_LOAD_FLAG              0x4000  
+
+/* Defines needed to find the kernel boot command line... sigh. */
+#define NEW_CL_POINTER                 0x228   /* Relative to real mode data */
+#define OLD_CL_MAGIC_ADDR              0x90020
+#define OLD_CL_MAGIC                   0xA33F
+#define OLD_CL_BASE_ADDR               0x90000
+#define OLD_CL_OFFSET                  0x90022
+
+#endif
diff --git a/kitten/include/arch-x86_64/bug.h b/kitten/include/arch-x86_64/bug.h
new file mode 100644 (file)
index 0000000..dca9ae5
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __ARCH_BUG_H
+#define __ARCH_BUG_H
+
+#include <lwk/stringify.h>
+
+/*
+ * Tell the user there is some problem.  The exception handler decodes 
+ * this frame.
+ */
+struct bug_frame {
+       unsigned char ud2[2];
+       unsigned char push;
+       signed int filename;
+       unsigned char ret;
+       unsigned short line;
+} __attribute__((packed));
+
+#define HAVE_ARCH_BUG
+/* We turn the bug frame into valid instructions to not confuse
+   the disassembler. Thanks to Jan Beulich & Suresh Siddha
+   for nice instruction selection.
+   The magic numbers generate mov $64bitimm,%eax ; ret $offset. */
+#define BUG()                                                          \
+       asm volatile(                                                   \
+       "ud2 ; pushq $%c1 ; ret $%c0" ::                                \
+                    "i"(__LINE__), "i" (__FILE__))
+void out_of_line_bug(void);
+
+#include <arch-generic/bug.h>
+#endif
diff --git a/kitten/include/arch-x86_64/byteorder.h b/kitten/include/arch-x86_64/byteorder.h
new file mode 100644 (file)
index 0000000..9e7afa3
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _X86_64_BYTEORDER_H
+#define _X86_64_BYTEORDER_H
+
+#include <arch/types.h>
+#include <lwk/compiler.h>
+
+#ifdef __GNUC__
+
+static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x)
+{
+       __asm__("bswapq %0" : "=r" (x) : "0" (x));
+       return x;
+}
+
+static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
+{
+       __asm__("bswapl %0" : "=r" (x) : "0" (x));
+       return x;
+}
+
+/* Do not define swab16.  Gcc is smart enough to recognize "C" version and
+   convert it into rotation or exhange.  */
+
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab64(x) ___arch__swab64(x)
+
+#endif /* __GNUC__ */
+
+#define __BYTEORDER_HAS_U64__
+
+#include <lwk/byteorder/little_endian.h>
+
+#endif /* _X86_64_BYTEORDER_H */
diff --git a/kitten/include/arch-x86_64/cache.h b/kitten/include/arch-x86_64/cache.h
new file mode 100644 (file)
index 0000000..2ad1879
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * include/arch-x86_64/cache.h
+ */
+#ifndef _ARCH_CACHE_H
+#define _ARCH_CACHE_H
+
+/* L1 cache line size */
+#define L1_CACHE_SHIFT         (CONFIG_X86_L1_CACHE_SHIFT)
+#define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
+
+/* Inter-node cache line size for NUMA systems */
+#define INTERNODE_CACHE_SHIFT  (CONFIG_X86_INTERNODE_CACHE_SHIFT)
+#define INTERNODE_CACHE_BYTES  (1 << INTERNODE_CACHE_SHIFT)
+
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+
+#endif
diff --git a/kitten/include/arch-x86_64/calling.h b/kitten/include/arch-x86_64/calling.h
new file mode 100644 (file)
index 0000000..6f4f63a
--- /dev/null
@@ -0,0 +1,162 @@
+/* 
+ * Some macros to handle stack frames in assembly.
+ */ 
+
+
+#define R15 0
+#define R14 8
+#define R13 16
+#define R12 24
+#define RBP 32
+#define RBX 40
+/* arguments: interrupts/non tracing syscalls only save upto here*/
+#define R11 48
+#define R10 56 
+#define R9 64
+#define R8 72
+#define RAX 80
+#define RCX 88
+#define RDX 96
+#define RSI 104
+#define RDI 112
+#define ORIG_RAX 120       /* + error_code */ 
+/* end of arguments */         
+/* cpu exception frame or undefined in case of fast syscall. */
+#define RIP 128
+#define CS 136
+#define EFLAGS 144
+#define RSP 152
+#define SS 160
+#define ARGOFFSET R11
+#define SWFRAME ORIG_RAX
+
+       .macro SAVE_ARGS addskip=0,norcx=0,nor891011=0
+       subq  $9*8+\addskip,%rsp
+       CFI_ADJUST_CFA_OFFSET   9*8+\addskip
+       movq  %rdi,8*8(%rsp) 
+       CFI_REL_OFFSET  rdi,8*8
+       movq  %rsi,7*8(%rsp) 
+       CFI_REL_OFFSET  rsi,7*8
+       movq  %rdx,6*8(%rsp)
+       CFI_REL_OFFSET  rdx,6*8
+       .if \norcx
+       .else
+       movq  %rcx,5*8(%rsp)
+       CFI_REL_OFFSET  rcx,5*8
+       .endif
+       movq  %rax,4*8(%rsp) 
+       CFI_REL_OFFSET  rax,4*8
+       .if \nor891011
+       .else
+       movq  %r8,3*8(%rsp) 
+       CFI_REL_OFFSET  r8,3*8
+       movq  %r9,2*8(%rsp) 
+       CFI_REL_OFFSET  r9,2*8
+       movq  %r10,1*8(%rsp) 
+       CFI_REL_OFFSET  r10,1*8
+       movq  %r11,(%rsp) 
+       CFI_REL_OFFSET  r11,0*8
+       .endif
+       .endm
+
+#define ARG_SKIP 9*8
+       .macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0,skipr8910=0,skiprdx=0
+       .if \skipr11
+       .else
+       movq (%rsp),%r11
+       CFI_RESTORE r11
+       .endif
+       .if \skipr8910
+       .else
+       movq 1*8(%rsp),%r10
+       CFI_RESTORE r10
+       movq 2*8(%rsp),%r9
+       CFI_RESTORE r9
+       movq 3*8(%rsp),%r8
+       CFI_RESTORE r8
+       .endif
+       .if \skiprax
+       .else
+       movq 4*8(%rsp),%rax
+       CFI_RESTORE rax
+       .endif
+       .if \skiprcx
+       .else
+       movq 5*8(%rsp),%rcx
+       CFI_RESTORE rcx
+       .endif
+       .if \skiprdx
+       .else
+       movq 6*8(%rsp),%rdx
+       CFI_RESTORE rdx
+       .endif
+       movq 7*8(%rsp),%rsi
+       CFI_RESTORE rsi
+       movq 8*8(%rsp),%rdi
+       CFI_RESTORE rdi
+       .if ARG_SKIP+\addskip > 0
+       addq $ARG_SKIP+\addskip,%rsp
+       CFI_ADJUST_CFA_OFFSET   -(ARG_SKIP+\addskip)
+       .endif
+       .endm   
+
+       .macro LOAD_ARGS offset
+       movq \offset(%rsp),%r11
+       movq \offset+8(%rsp),%r10
+       movq \offset+16(%rsp),%r9
+       movq \offset+24(%rsp),%r8
+       movq \offset+40(%rsp),%rcx
+       movq \offset+48(%rsp),%rdx
+       movq \offset+56(%rsp),%rsi
+       movq \offset+64(%rsp),%rdi
+       movq \offset+72(%rsp),%rax
+       .endm
+                       
+#define REST_SKIP 6*8                  
+       .macro SAVE_REST
+       subq $REST_SKIP,%rsp
+       CFI_ADJUST_CFA_OFFSET   REST_SKIP
+       movq %rbx,5*8(%rsp) 
+       CFI_REL_OFFSET  rbx,5*8
+       movq %rbp,4*8(%rsp) 
+       CFI_REL_OFFSET  rbp,4*8
+       movq %r12,3*8(%rsp) 
+       CFI_REL_OFFSET  r12,3*8
+       movq %r13,2*8(%rsp) 
+       CFI_REL_OFFSET  r13,2*8
+       movq %r14,1*8(%rsp) 
+       CFI_REL_OFFSET  r14,1*8
+       movq %r15,(%rsp) 
+       CFI_REL_OFFSET  r15,0*8
+       .endm           
+
+       .macro RESTORE_REST
+       movq (%rsp),%r15
+       CFI_RESTORE r15
+       movq 1*8(%rsp),%r14
+       CFI_RESTORE r14
+       movq 2*8(%rsp),%r13
+       CFI_RESTORE r13
+       movq 3*8(%rsp),%r12
+       CFI_RESTORE r12
+       movq 4*8(%rsp),%rbp
+       CFI_RESTORE rbp
+       movq 5*8(%rsp),%rbx
+       CFI_RESTORE rbx
+       addq $REST_SKIP,%rsp
+       CFI_ADJUST_CFA_OFFSET   -(REST_SKIP)
+       .endm
+               
+       .macro SAVE_ALL
+       SAVE_ARGS
+       SAVE_REST
+       .endm
+               
+       .macro RESTORE_ALL addskip=0
+       RESTORE_REST
+       RESTORE_ARGS 0,\addskip
+       .endm
+
+       .macro icebp
+       .byte 0xf1
+       .endm
diff --git a/kitten/include/arch-x86_64/cpufeature.h b/kitten/include/arch-x86_64/cpufeature.h
new file mode 100644 (file)
index 0000000..f7be790
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * cpufeature.h
+ *
+ * Defines x86 CPU feature bits
+ */
+
+#ifndef _X86_64_CPUFEATURE_H
+#define _X86_64_CPUFEATURE_H
+
+#define NCAPINTS       8       /* N 32-bit words worth of info */
+
+/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
+#define X86_FEATURE_FPU                (0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME                (0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE         (0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE        (0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC                (0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR                (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE                (0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE                (0*32+ 7) /* Machine Check Architecture */
+#define X86_FEATURE_CX8                (0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC       (0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP                (0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR       (0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE                (0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA                (0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV       (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT                (0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36      (0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN         (0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLSH     (0*32+19) /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DS         (0*32+21) /* Debug Store */
+#define X86_FEATURE_ACPI       (0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX                (0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR       (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
+                                         /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM                (0*32+25) /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2       (0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP  (0*32+27) /* CPU self snoop */
+#define X86_FEATURE_HT         (0*32+28) /* Hyper-Threading */
+#define X86_FEATURE_ACC                (0*32+29) /* Automatic clock control */
+#define X86_FEATURE_IA64       (0*32+30) /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL    (1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MP         (1*32+19) /* MP Capable. */
+#define X86_FEATURE_NX         (1*32+20) /* Execute Disable */
+#define X86_FEATURE_MMXEXT     (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_RDTSCP     (1*32+27) /* RDTSCP */
+#define X86_FEATURE_LM         (1*32+29) /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT   (1*32+30) /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW      (1*32+31) /* 3DNow! */
+
+/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
+#define X86_FEATURE_RECOVERY   (2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN    (2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI       (2*32+ 3) /* LongRun table interface */
+
+/* Other features, Linux-defined mapping, word 3 */
+/* This range is used for feature bits which conflict or are synthesized */
+#define X86_FEATURE_CXMMX      (3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR    (3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR  (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR        (3*32+ 3) /* Centaur MCRs (= MTRRs) */
+/* cpu types for specific tunings: */
+#define X86_FEATURE_K8         (3*32+ 4) /* Opteron, Athlon64 */
+#define X86_FEATURE_K7         (3*32+ 5) /* Athlon */
+#define X86_FEATURE_P3         (3*32+ 6) /* P3 */
+#define X86_FEATURE_P4         (3*32+ 7) /* P4 */
+#define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
+#define X86_FEATURE_UP         (3*32+ 9) /* smp kernel running on up */
+#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */
+#define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
+#define X86_FEATURE_PEBS       (3*32+12)  /* Precise-Event Based Sampling */
+#define X86_FEATURE_BTS                (3*32+13)  /* Branch Trace Store */
+/* 14 free */
+#define X86_FEATURE_SYNC_RDTSC (3*32+15)  /* RDTSC synchronizes the CPU */
+#define X86_FEATURE_REP_GOOD   (3*32+16) /* rep microcode works well on this CPU */
+
+/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+#define X86_FEATURE_XMM3       (4*32+ 0) /* Streaming SIMD Extensions-3 */
+#define X86_FEATURE_MWAIT      (4*32+ 3) /* Monitor/Mwait support */
+#define X86_FEATURE_DSCPL      (4*32+ 4) /* CPL Qualified Debug Store */
+#define X86_FEATURE_EST                (4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_TM2                (4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_CID                (4*32+10) /* Context ID */
+#define X86_FEATURE_CX16        (4*32+13) /* CMPXCHG16B */
+#define X86_FEATURE_XTPR       (4*32+14) /* Send Task Priority Messages */
+
+/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
+#define X86_FEATURE_XSTORE     (5*32+ 2) /* on-CPU RNG present (xstore insn) */
+#define X86_FEATURE_XSTORE_EN  (5*32+ 3) /* on-CPU RNG enabled */
+#define X86_FEATURE_XCRYPT     (5*32+ 6) /* on-CPU crypto (xcrypt insn) */
+#define X86_FEATURE_XCRYPT_EN  (5*32+ 7) /* on-CPU crypto enabled */
+#define X86_FEATURE_ACE2       (5*32+ 8) /* Advanced Cryptography Engine v2 */
+#define X86_FEATURE_ACE2_EN    (5*32+ 9) /* ACE v2 enabled */
+#define X86_FEATURE_PHE                (5*32+ 10) /* PadLock Hash Engine */
+#define X86_FEATURE_PHE_EN     (5*32+ 11) /* PHE enabled */
+#define X86_FEATURE_PMM                (5*32+ 12) /* PadLock Montgomery Multiplier */
+#define X86_FEATURE_PMM_EN     (5*32+ 13) /* PMM enabled */
+
+/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
+#define X86_FEATURE_LAHF_LM    (6*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
+
+/*
+ * Auxiliary flags: Linux defined - For features scattered in various
+ * CPUID levels like 0x6, 0xA etc
+ */
+#define X86_FEATURE_IDA                (7*32+ 0) /* Intel Dynamic Acceleration */
+
+#define cpu_has(c, bit)                test_bit(bit, (c)->arch.x86_capability)
+#define boot_cpu_has(bit)      test_bit(bit, boot_cpu_data.arch.x86_capability)
+
+#define cpu_has_fpu            1
+#define cpu_has_vme            0
+#define cpu_has_de             1
+#define cpu_has_pse            1
+#define cpu_has_tsc            1
+#define cpu_has_pae            ___BUG___
+#define cpu_has_pge            1
+#define cpu_has_apic           boot_cpu_has(X86_FEATURE_APIC)
+#define cpu_has_mtrr           1
+#define cpu_has_mmx            1
+#define cpu_has_fxsr           1
+#define cpu_has_xmm            1
+#define cpu_has_xmm2           1
+#define cpu_has_xmm3           boot_cpu_has(X86_FEATURE_XMM3)
+#define cpu_has_ht             boot_cpu_has(X86_FEATURE_HT)
+#define cpu_has_mp             1 /* XXX */
+#define cpu_has_k6_mtrr        0
+#define cpu_has_cyrix_arr      0
+#define cpu_has_centaur_mcr    0
+#define cpu_has_clflush               boot_cpu_has(X86_FEATURE_CLFLSH)
+
+#endif /* _X86_64_CPUFEATURE_H */
diff --git a/kitten/include/arch-x86_64/cpuinfo.h b/kitten/include/arch-x86_64/cpuinfo.h
new file mode 100644 (file)
index 0000000..e9f6973
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * Portions derived from Linux include/asm-x86_64/processor.h
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef _X86_64_CPUINFO_H
+#define _X86_64_CPUINFO_H
+
+#include <arch/cpufeature.h>
+
+/**
+ * arch_cpuinfo.x86_cache_size first dimension indicies.
+ * and
+ * arch_cpuinfo.x86_tlbsize first dimension indicies.
+ */
+#define INST   0       /* Instruction */
+#define DATA   1       /* Data */
+#define UNIF   2       /* Unified Instruction and Data */
+
+/**
+ * arch_cpuinfo.x86_cache_size second dimension indices.
+ * and
+ * arch_cpuinfo.x86_tlbsize second dimension indices.
+ */
+#define L1     0
+#define L2     1
+#define L3     2
+
+/**
+ * arch_cpuinfo.x86_tlbsize third dimension indices.
+ */
+#define PAGE_4KB       0
+#define PAGE_2MB       1
+#define PAGE_1GB       2
+
+/**
+ * Architecture specific CPU information and hardware bug flags.
+ * CPU info is kept separately for each CPU.
+ */
+struct arch_cpuinfo {
+    uint8_t  x86_vendor;            /* CPU vendor */
+    uint8_t  x86_family;            /* CPU family */
+    uint8_t  x86_model;             /* CPU model */
+    uint8_t  x86_stepping;          /* CPU stepping */
+    uint32_t x86_capability[NCAPINTS]; /* optional CPU features */
+    char     x86_vendor_id[16];     /* Vendor ID string */
+    char     x86_model_id[64];      /* Model/Brand ID string */
+    uint16_t x86_cache_size[3][3];  /* [I|D|U][LEVEL], in KB */
+    uint16_t x86_cache_line[3][3];  /* [I|D|U][LEVEL], in bytes */
+    int      x86_clflush_size;      /* In bytes */
+    uint16_t x86_tlb_size[3][2][3]; /* [I|D|U][LEVEL][PAGE_SIZE], in #entries */
+    uint8_t  x86_virt_bits;         /* Bits of virt address space */
+    uint8_t  x86_phys_bits;         /* Bits of phys address space */
+    uint8_t  x86_pkg_cores;         /* Number of cores in this CPU's package */
+    uint32_t x86_power;             /* Power management features */
+    uint32_t cpuid_level;           /* Max supported CPUID level */
+    uint32_t extended_cpuid_level;  /* Max extended CPUID func supported */
+    uint32_t cur_cpu_khz;           /* Current CPU freq. in KHz */
+    uint32_t max_cpu_khz;           /* Maximum CPU freq. in KHz */
+    uint32_t min_cpu_khz;           /* Minimum CPU freq. in KHz */
+    uint32_t tsc_khz;               /* Time stamp counter freq. in KHz */
+    uint32_t lapic_khz;             /* Local APIC bus freq. in KHz */
+    uint8_t  apic_id;               /* Local APIC ID, phys CPU ID */
+    uint8_t  initial_lapic_id;      /* As reported by CPU ID */
+};
+
+extern struct cpuinfo boot_cpu_data;
+
+struct cpuinfo;
+extern void print_arch_cpuinfo(struct cpuinfo *);
+extern void early_identify_cpu(struct cpuinfo *);
+
+#endif
diff --git a/kitten/include/arch-x86_64/current.h b/kitten/include/arch-x86_64/current.h
new file mode 100644 (file)
index 0000000..9967cf6
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _X86_64_CURRENT_H
+#define _X86_64_CURRENT_H
+
+#if !defined(__ASSEMBLY__) 
+struct task_struct;
+
+#include <arch/pda.h>
+
+/**
+ * In normal operation, the current task pointer is read directly from
+ * the PDA.
+ *
+ * If the PDA has not been setup or is not available for some reason,
+ * the slower get_current_via_RSP() must be used instead.  This is
+ * sometimes necessary during the bootstrap process.
+ */
+static inline struct task_struct *
+get_current(void) 
+{ 
+       struct task_struct *t = read_pda(pcurrent); 
+       return t;
+} 
+#define current get_current()
+
+/**
+ * Derives the current task pointer from the current value of the
+ * stack pointer (RSP register).
+ *
+ * WARNING: Do not call this from interrupt context.  It won't work.
+ *          It is only safe to call this from task context.
+ */
+static inline struct task_struct *
+get_current_via_RSP(void)
+{
+       struct task_struct *tsk;
+       __asm__("andq %%rsp,%0; " : "=r" (tsk) : "0" (~(TASK_SIZE - 1)));
+       return tsk;
+}
+
+#else
+
+#ifndef ASM_OFFSET_H
+#include <arch/asm-offsets.h> 
+#endif
+
+#define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg
+
+#endif
+
+#endif /* !(_X86_64_CURRENT_H) */
diff --git a/kitten/include/arch-x86_64/debugreg.h b/kitten/include/arch-x86_64/debugreg.h
new file mode 100644 (file)
index 0000000..bd1aab1
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef _X86_64_DEBUGREG_H
+#define _X86_64_DEBUGREG_H
+
+
+/* Indicate the register numbers for a number of the specific
+   debug registers.  Registers 0-3 contain the addresses we wish to trap on */
+#define DR_FIRSTADDR 0        /* u_debugreg[DR_FIRSTADDR] */
+#define DR_LASTADDR 3         /* u_debugreg[DR_LASTADDR]  */
+
+#define DR_STATUS 6           /* u_debugreg[DR_STATUS]     */
+#define DR_CONTROL 7          /* u_debugreg[DR_CONTROL] */
+
+/* Define a few things for the status register.  We can use this to determine
+   which debugging register was responsible for the trap.  The other bits
+   are either reserved or not of interest to us. */
+
+#define DR_TRAP0       (0x1)           /* db0 */
+#define DR_TRAP1       (0x2)           /* db1 */
+#define DR_TRAP2       (0x4)           /* db2 */
+#define DR_TRAP3       (0x8)           /* db3 */
+
+#define DR_STEP                (0x4000)        /* single-step */
+#define DR_SWITCH      (0x8000)        /* task switch */
+
+/* Now define a bunch of things for manipulating the control register.
+   The top two bytes of the control register consist of 4 fields of 4
+   bits - each field corresponds to one of the four debug registers,
+   and indicates what types of access we trap on, and how large the data
+   field is that we are looking at */
+
+#define DR_CONTROL_SHIFT 16 /* Skip this many bits in ctl register */
+#define DR_CONTROL_SIZE 4   /* 4 control bits per register */
+
+#define DR_RW_EXECUTE (0x0)   /* Settings for the access types to trap on */
+#define DR_RW_WRITE (0x1)
+#define DR_RW_READ (0x3)
+
+#define DR_LEN_1 (0x0) /* Settings for data length to trap on */
+#define DR_LEN_2 (0x4)
+#define DR_LEN_4 (0xC)
+#define DR_LEN_8 (0x8)
+
+/* The low byte to the control register determine which registers are
+   enabled.  There are 4 fields of two bits.  One bit is "local", meaning
+   that the processor will reset the bit after a task switch and the other
+   is global meaning that we have to explicitly reset the bit.  With linux,
+   you can use either one, since we explicitly zero the register when we enter
+   kernel mode. */
+
+#define DR_LOCAL_ENABLE_SHIFT 0    /* Extra shift to the local enable bit */
+#define DR_GLOBAL_ENABLE_SHIFT 1   /* Extra shift to the global enable bit */
+#define DR_ENABLE_SIZE 2           /* 2 enable bits per register */
+
+#define DR_LOCAL_ENABLE_MASK (0x55)  /* Set  local bits for all 4 regs */
+#define DR_GLOBAL_ENABLE_MASK (0xAA) /* Set global bits for all 4 regs */
+
+/* The second byte to the control register has a few special things.
+   We can slow the instruction pipeline for instructions coming via the
+   gdt or the ldt if we want to.  I am not sure why this is an advantage */
+
+#define DR_CONTROL_RESERVED (0xFFFFFFFF0000FC00UL) /* Reserved */
+#define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
+#define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
+
+#endif
diff --git a/kitten/include/arch-x86_64/delay.h b/kitten/include/arch-x86_64/delay.h
new file mode 100644 (file)
index 0000000..4447396
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _X86_64_DELAY_H
+#define _X86_64_DELAY_H
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines calling functions in arch/x86_64/lib/delay.c
+ */
+extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
+
+extern void __udelay(unsigned long usecs);
+extern void __ndelay(unsigned long usecs);
+extern void __const_udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) (__builtin_constant_p(n) ? \
+       ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \
+       __udelay(n))
+
+#define ndelay(n) (__builtin_constant_p(n) ? \
+       ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
+       __ndelay(n))
+
+
+#endif /* defined(_X86_64_DELAY_H) */
diff --git a/kitten/include/arch-x86_64/desc.h b/kitten/include/arch-x86_64/desc.h
new file mode 100644 (file)
index 0000000..1f32600
--- /dev/null
@@ -0,0 +1,271 @@
+/* Written 2000 by Andi Kleen */ 
+#ifndef _ARCH_DESC_H
+#define _ARCH_DESC_H
+
+#include <arch/ldt.h>
+
+#ifndef __ASSEMBLY__
+
+#include <lwk/string.h>
+#include <lwk/smp.h>
+
+#include <arch/segment.h>
+#include <arch/mmu.h>
+
+// 8 byte segment descriptor
+struct desc_struct { 
+       u16 limit0;
+       u16 base0;
+       unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
+       unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
+} __attribute__((packed)); 
+
+struct n_desc_struct { 
+       unsigned int a,b;
+};     
+
+extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
+
+enum { 
+       GATE_INTERRUPT = 0xE, 
+       GATE_TRAP = 0xF,        
+       GATE_CALL = 0xC,
+};     
+
+/**
+ * Long-Mode Gate Descriptor (16-bytes)
+ */
+struct gate_struct {          
+       uint16_t offset_low;    /* [15-0] of target code segment offset */
+       uint16_t segment;       /* Target code segment selector */
+       unsigned ist    : 3;    /* Interrupt-Stack-Table index into TSS */
+       unsigned zero0  : 5;
+       unsigned type   : 5;    /* Gate descriptor type */
+       unsigned dpl    : 2;    /* Privilege level */
+       unsigned p      : 1;    /* Present bit... in use? */
+       uint16_t offset_middle; /* [31-24] of target code segment offset */
+       uint32_t offset_high;   /* [63-32] of target code segment offset */
+       uint32_t zero1;
+} __attribute__((packed));
+
+#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) 
+#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
+#define PTR_HIGH(x) ((unsigned long)(x) >> 32)
+
+enum { 
+       DESC_TSS = 0x9,
+       DESC_LDT = 0x2,
+}; 
+
+// LDT or TSS descriptor in the GDT. 16 bytes.
+struct ldttss_desc { 
+       u16 limit0;
+       u16 base0;
+       unsigned base1 : 8, type : 5, dpl : 2, p : 1;
+       unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
+       u32 base3;
+       u32 zero1; 
+} __attribute__((packed)); 
+
+struct desc_ptr {
+       unsigned short size;
+       unsigned long address;
+} __attribute__((packed)) ;
+
+#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8))
+#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8))
+#define clear_LDT()  asm volatile("lldt %w0"::"r" (0))
+
+/*
+ * This is the ldt that every process will get unless we need
+ * something other than this.
+ */
+extern struct desc_struct default_ldt[];
+extern struct gate_struct idt_table[]; 
+extern struct desc_ptr cpu_gdt_descr[];
+
+/* the cpu gdt accessor */
+#define cpu_gdt(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address)
+
+/**
+ * Installs a Long-Mode gate descriptor.
+ */
+static inline void
+_set_gate(
+       void *        adr,      /* Address to install gate descriptor at */
+       unsigned      type,     /* Type of gate */
+       unsigned long func,     /* The handler function for the gate */
+       unsigned      dpl,      /* Privilege level */
+       unsigned      ist       /* Interupt-Stack-Table index */
+)  
+{
+       struct gate_struct s;   
+       s.offset_low = PTR_LOW(func); 
+       s.segment = __KERNEL_CS;
+       s.ist = ist; 
+       s.p = 1;
+       s.dpl = dpl; 
+       s.zero0 = 0;
+       s.zero1 = 0; 
+       s.type = type; 
+       s.offset_middle = PTR_MIDDLE(func); 
+       s.offset_high = PTR_HIGH(func); 
+       /* does not need to be atomic because it is only done once at setup time */ 
+       memcpy(adr, &s, 16); 
+} 
+
+/**
+ * Installs an interrupt gate.
+ * The interrupt will execute on the normal kernel stack.
+ */
+static inline void
+set_intr_gate(int nr, void *func) 
+{ 
+       BUG_ON((unsigned)nr > 0xFF);
+       _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0); 
+} 
+
+/**
+ * Installs an interrupt gate.
+ * The interrupt will execute on the stack specified by the 'ist' argument.
+ */
+static inline void set_intr_gate_ist(int nr, void *func, unsigned ist) 
+{ 
+       BUG_ON((unsigned)nr > 0xFF);
+       _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist); 
+} 
+
+/**
+ * Installs a system interrupt gate.
+ * The privilege level is set to 3, meaning that user-mode can trigger it.
+ */
+static inline void set_system_gate(int nr, void *func) 
+{ 
+       BUG_ON((unsigned)nr > 0xFF);
+       _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0); 
+} 
+
+/**
+ * Installs a system interrupt gate.
+ * The privilege level is set to 3, meaning that user-mode can trigger it.
+ * The interrupt will execute on the stack specified by the 'ist' argument.
+ */
+static inline void set_system_gate_ist(int nr, void *func, unsigned ist)
+{
+       _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist);
+}
+
+static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, 
+                                        unsigned size) 
+{ 
+       struct ldttss_desc d;
+       memset(&d,0,sizeof(d)); 
+       d.limit0 = size & 0xFFFF;
+       d.base0 = PTR_LOW(tss); 
+       d.base1 = PTR_MIDDLE(tss) & 0xFF; 
+       d.type = type;
+       d.p = 1; 
+       d.limit1 = (size >> 16) & 0xF;
+       d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; 
+       d.base3 = PTR_HIGH(tss); 
+       memcpy(ptr, &d, 16); 
+}
+
+static inline void set_tss_desc(unsigned cpu, void *addr)
+{ 
+       /*
+        * sizeof(unsigned long) coming from an extra "long" at the end
+        * of the iobitmap. See tss_struct definition in processor.h
+        *
+        * -1? seg base+limit should be pointing to the address of the
+        * last valid byte
+        */
+       set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_TSS],
+               (unsigned long)addr, DESC_TSS,
+               IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1);
+} 
+
+static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
+{ 
+       set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_LDT], (unsigned long)addr,
+                             DESC_LDT, size * 8 - 1);
+}
+
+static inline void set_seg_base(unsigned cpu, int entry, void *base)
+{ 
+       struct desc_struct *d = &cpu_gdt(cpu)[entry];
+       u32 addr = (u32)(u64)base;
+       BUG_ON((u64)base >> 32); 
+       d->base0 = addr & 0xffff;
+       d->base1 = (addr >> 16) & 0xff;
+       d->base2 = (addr >> 24) & 0xff;
+} 
+
+#define LDT_entry_a(info) \
+       ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
+/* Don't allow setting of the lm bit. It is useless anyways because 
+   64bit system calls require __USER_CS. */ 
+#define LDT_entry_b(info) \
+       (((info)->base_addr & 0xff000000) | \
+       (((info)->base_addr & 0x00ff0000) >> 16) | \
+       ((info)->limit & 0xf0000) | \
+       (((info)->read_exec_only ^ 1) << 9) | \
+       ((info)->contents << 10) | \
+       (((info)->seg_not_present ^ 1) << 15) | \
+       ((info)->seg_32bit << 22) | \
+       ((info)->limit_in_pages << 23) | \
+       ((info)->useable << 20) | \
+       /* ((info)->lm << 21) | */ \
+       0x7000)
+
+#define LDT_empty(info) (\
+       (info)->base_addr       == 0    && \
+       (info)->limit           == 0    && \
+       (info)->contents        == 0    && \
+       (info)->read_exec_only  == 1    && \
+       (info)->seg_32bit       == 0    && \
+       (info)->limit_in_pages  == 0    && \
+       (info)->seg_not_present == 1    && \
+       (info)->useable         == 0    && \
+       (info)->lm              == 0)
+
+#if TLS_SIZE != 24
+# error update this code.
+#endif
+
+static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
+{
+       u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN);
+       gdt[0] = t->tls_array[0];
+       gdt[1] = t->tls_array[1];
+       gdt[2] = t->tls_array[2];
+} 
+
+/*
+ * load one particular LDT into the current CPU
+ */
+static inline void load_LDT_nolock (mm_context_t *pc, int cpu)
+{
+       int count = pc->size;
+
+       if (likely(!count)) {
+               clear_LDT();
+               return;
+       }
+               
+       set_ldt_desc(cpu, pc->ldt, count);
+       load_LDT_desc();
+}
+
+static inline void load_LDT(mm_context_t *pc)
+{
+       int cpu = get_cpu();
+       load_LDT_nolock(pc, cpu);
+       put_cpu();
+}
+
+extern struct desc_ptr idt_descr;
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/kitten/include/arch-x86_64/div64.h b/kitten/include/arch-x86_64/div64.h
new file mode 100644 (file)
index 0000000..a841abf
--- /dev/null
@@ -0,0 +1 @@
+#include <arch-generic/div64.h>
diff --git a/kitten/include/arch-x86_64/dwarf2.h b/kitten/include/arch-x86_64/dwarf2.h
new file mode 100644 (file)
index 0000000..0744db7
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _DWARF2_H
+#define _DWARF2_H 1
+
+
+#ifndef __ASSEMBLY__
+#warning "asm/dwarf2.h should be only included in pure assembly files"
+#endif
+
+/* 
+   Macros for dwarf2 CFI unwind table entries.
+   See "as.info" for details on these pseudo ops. Unfortunately 
+   they are only supported in very new binutils, so define them 
+   away for older version. 
+ */
+
+#ifdef CONFIG_UNWIND_INFO
+
+#define CFI_STARTPROC .cfi_startproc
+#define CFI_ENDPROC .cfi_endproc
+#define CFI_DEF_CFA .cfi_def_cfa
+#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
+#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
+#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
+#define CFI_OFFSET .cfi_offset
+#define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_REGISTER .cfi_register
+#define CFI_RESTORE .cfi_restore
+#define CFI_REMEMBER_STATE .cfi_remember_state
+#define CFI_RESTORE_STATE .cfi_restore_state
+#define CFI_UNDEFINED .cfi_undefined
+
+#else
+
+/* use assembler line comment character # to ignore the arguments. */
+#define CFI_STARTPROC  #
+#define CFI_ENDPROC    #
+#define CFI_DEF_CFA    #
+#define CFI_DEF_CFA_REGISTER   #
+#define CFI_DEF_CFA_OFFSET     #
+#define CFI_ADJUST_CFA_OFFSET  #
+#define CFI_OFFSET     #
+#define CFI_REL_OFFSET #
+#define CFI_REGISTER   #
+#define CFI_RESTORE    #
+#define CFI_REMEMBER_STATE     #
+#define CFI_RESTORE_STATE      #
+#define CFI_UNDEFINED  #
+
+#endif
+
+#endif
diff --git a/kitten/include/arch-x86_64/e820.h b/kitten/include/arch-x86_64/e820.h
new file mode 100644 (file)
index 0000000..0842c98
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * structures and definitions for the int 15, ax=e820 memory map
+ * scheme.
+ *
+ * In a nutshell, setup.S populates a scratch table in the
+ * empty_zero_block that contains a list of usable address/size
+ * duples.  setup.c, this information is transferred into the e820map,
+ * and in init.c/numa.c, that new information is used to mark pages
+ * reserved or not.
+ */
+#ifndef _ARCH_E820_H
+#define _ARCH_E820_H
+
+#include <lwk/init.h>
+
+#define E820MAP        0x2d0           /* our map */
+#define E820MAX        128             /* number of entries in E820MAP */
+#define E820NR 0x1e8           /* # entries in E820MAP */
+
+#define E820_RAM       1
+#define E820_RESERVED  2
+#define E820_ACPI      3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS       4
+
+#define HIGH_MEMORY    (1024*1024)
+
+#define LOWMEMSIZE()   (0x9f000)
+
+#ifndef __ASSEMBLY__
+struct e820entry {
+       u64 addr;       /* start of memory segment */
+       u64 size;       /* size of memory segment */
+       u32 type;       /* type of memory segment */
+} __attribute__((packed));
+
+struct e820map {
+       int nr_map;
+       struct e820entry map[E820MAX];
+};
+
+extern unsigned long find_e820_area(unsigned long start, unsigned long end, 
+                                   unsigned size);
+extern void add_memory_region(unsigned long start, unsigned long size, 
+                             int type);
+extern void setup_memory_region(void);
+extern void contig_e820_setup(void); 
+extern unsigned long e820_end_of_ram(void);
+extern void e820_reserve_resources(void);
+extern void e820_print_map(char *who);
+extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
+extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);
+
+extern void e820_bootmem_free(unsigned long start,unsigned long end);
+extern void e820_setup_gap(void);
+extern unsigned long e820_hole_size(unsigned long start_pfn,
+                                   unsigned long end_pfn);
+
+extern void __init parse_memopt(char *p, char **end);
+extern void __init parse_memmapopt(char *p, char **end);
+
+extern struct e820map e820;
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ARCH_E820_H */
diff --git a/kitten/include/arch-x86_64/elf.h b/kitten/include/arch-x86_64/elf.h
new file mode 100644 (file)
index 0000000..7db2bbb
--- /dev/null
@@ -0,0 +1,168 @@
+#ifndef __ASM_X86_64_ELF_H
+#define __ASM_X86_64_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <arch/ptrace.h>
+#include <arch/user.h>
+
+/* x86-64 relocation types */
+#define R_X86_64_NONE          0       /* No reloc */
+#define R_X86_64_64            1       /* Direct 64 bit  */
+#define R_X86_64_PC32          2       /* PC relative 32 bit signed */
+#define R_X86_64_GOT32         3       /* 32 bit GOT entry */
+#define R_X86_64_PLT32         4       /* 32 bit PLT address */
+#define R_X86_64_COPY          5       /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT      6       /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT     7       /* Create PLT entry */
+#define R_X86_64_RELATIVE      8       /* Adjust by program base */
+#define R_X86_64_GOTPCREL      9       /* 32 bit signed pc relative
+                                          offset to GOT */
+#define R_X86_64_32            10      /* Direct 32 bit zero extended */
+#define R_X86_64_32S           11      /* Direct 32 bit sign extended */
+#define R_X86_64_16            12      /* Direct 16 bit zero extended */
+#define R_X86_64_PC16          13      /* 16 bit sign extended pc relative */
+#define R_X86_64_8             14      /* Direct 8 bit sign extended  */
+#define R_X86_64_PC8           15      /* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM           16
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_i387_struct elf_fpregset_t;
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2LSB
+#define ELF_ARCH       EM_X86_64
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.
+
+   For the moment, we have only optimizations for the Intel generations,
+   but that could change... */
+
+/* I'm not sure if we can use '-' here */
+#define ELF_PLATFORM  ("x86_64")
+
+#define ELF_EXEC_PAGESIZE      4096
+
+#ifdef __KERNEL__
+#include <arch/processor.h>
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+       ((x)->e_machine == EM_X86_64)
+
+
+/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx
+   contains a pointer to a function which might be registered using `atexit'.
+   This provides a mean for the dynamic linker to call DT_FINI functions for
+   shared libraries that have been loaded before the code runs.
+
+   A value of 0 tells we have no such handler. 
+
+   We might as well make sure everything else is cleared too (except for %esp),
+   just to make things more deterministic.
+ */
+#define ELF_PLAT_INIT(_r, load_addr)   do { \
+       struct task_struct *cur = current; \
+       (_r)->rbx = 0; (_r)->rcx = 0; (_r)->rdx = 0; \
+       (_r)->rsi = 0; (_r)->rdi = 0; (_r)->rbp = 0; \
+       (_r)->rax = 0;                          \
+       (_r)->r8 = 0;                           \
+       (_r)->r9 = 0;                           \
+       (_r)->r10 = 0;                          \
+       (_r)->r11 = 0;                          \
+       (_r)->r12 = 0;                          \
+       (_r)->r13 = 0;                          \
+       (_r)->r14 = 0;                          \
+       (_r)->r15 = 0;                          \
+        cur->thread.fs = 0; cur->thread.gs = 0; \
+       cur->thread.fsindex = 0; cur->thread.gsindex = 0; \
+        cur->thread.ds = 0; cur->thread.es = 0;  \
+       clear_thread_flag(TIF_IA32); \
+} while (0)
+
+#define USE_ELF_CORE_DUMP
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.  */
+
+#define ELF_ET_DYN_BASE         (2 * TASK_SIZE / 3)
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+   now struct_user_regs, they are different). Assumes current is the process
+   getting dumped. */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)  do { \
+       unsigned v;                                             \
+       (pr_reg)[0] = (regs)->r15;                              \
+       (pr_reg)[1] = (regs)->r14;                              \
+       (pr_reg)[2] = (regs)->r13;                              \
+       (pr_reg)[3] = (regs)->r12;                              \
+       (pr_reg)[4] = (regs)->rbp;                              \
+       (pr_reg)[5] = (regs)->rbx;                              \
+       (pr_reg)[6] = (regs)->r11;                              \
+       (pr_reg)[7] = (regs)->r10;                              \
+       (pr_reg)[8] = (regs)->r9;                               \
+       (pr_reg)[9] = (regs)->r8;                               \
+       (pr_reg)[10] = (regs)->rax;                             \
+       (pr_reg)[11] = (regs)->rcx;                             \
+       (pr_reg)[12] = (regs)->rdx;                             \
+       (pr_reg)[13] = (regs)->rsi;                             \
+       (pr_reg)[14] = (regs)->rdi;                             \
+       (pr_reg)[15] = (regs)->orig_rax;                        \
+       (pr_reg)[16] = (regs)->rip;                     \
+       (pr_reg)[17] = (regs)->cs;                      \
+       (pr_reg)[18] = (regs)->eflags;                  \
+       (pr_reg)[19] = (regs)->rsp;                     \
+       (pr_reg)[20] = (regs)->ss;                      \
+       (pr_reg)[21] = current->thread.fs;                      \
+       (pr_reg)[22] = current->thread.gs;                      \
+       asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v;       \
+       asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v;       \
+       asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v;       \
+       asm("movl %%gs,%0" : "=r" (v)); (pr_reg)[26] = v;       \
+} while(0);
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this CPU supports.  This could be done in user space,
+   but it's not easy, and we've already done it here.  */
+
+#define ELF_HWCAP(cpu) (cpu_info[cpu].arch.x86_capability[0])
+
+extern void set_personality_64bit(void);
+#define SET_PERSONALITY(ex, ibcs2) set_personality_64bit()
+/*
+ * An executable for which elf_read_implies_exec() returns TRUE will
+ * have the READ_IMPLIES_EXEC personality flag set automatically.
+ */
+#define elf_read_implies_exec(ex, executable_stack)    (executable_stack != EXSTACK_DISABLE_X)
+
+struct task_struct;
+
+extern int dump_task_regs (struct task_struct *, elf_gregset_t *);
+extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+
+/* 1GB for 64bit, 8MB for 32bit */
+#define STACK_RND_MASK (test_thread_flag(TIF_IA32) ? 0x7ff : 0x3fffff)
+
+#endif
+
+#endif
diff --git a/kitten/include/arch-x86_64/errno.h b/kitten/include/arch-x86_64/errno.h
new file mode 100644 (file)
index 0000000..1a992b6
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _X86_64_ERRNO_H
+#define _X86_64_ERRNO_H
+
+#include <arch-generic/errno.h>
+
+#endif
diff --git a/kitten/include/arch-x86_64/extable.h b/kitten/include/arch-x86_64/extable.h
new file mode 100644 (file)
index 0000000..79f88b1
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _ASM_X86_64_EXTABLE_H
+#define _ASM_X86_64_EXTABLE_H
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * The nice thing about this mechanism is that the fixup code is completely
+ * out of line with the main instruction path.  This means when everything
+ * is well, we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+struct exception_table_entry
+{
+        unsigned long insn;    /* Instruction addr that is allowed to fault */
+       unsigned long fixup;    /* Fixup handler address */
+};
+
+#define ARCH_HAS_SEARCH_EXTABLE
+
+#endif
diff --git a/kitten/include/arch-x86_64/fixmap.h b/kitten/include/arch-x86_64/fixmap.h
new file mode 100644 (file)
index 0000000..04b6b63
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Ingo Molnar
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#include <lwk/kernel.h>
+#include <arch/apicdef.h>
+#include <arch/page.h>
+#include <arch/vsyscall.h>
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process.
+ *
+ * These 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * higher than 1). Use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+
+enum fixed_addresses {
+       VSYSCALL_LAST_PAGE,
+       VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
+       FIX_APIC_BASE,  /* local (CPU) APIC) */
+       FIX_IO_APIC_BASE_0,
+       FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
+       __end_of_fixed_addresses
+};
+
+extern void __set_fixmap(enum fixed_addresses fixmap_index,
+                         unsigned long phys_addr, pgprot_t prot);
+
+#define set_fixmap(idx, phys) \
+               __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+               __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+
+#define FIXADDR_TOP    (VSYSCALL_END-PAGE_SIZE)
+#define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
+
+/* Only covers 32bit vsyscalls currently. Need another set for 64bit. */
+#define FIXADDR_USER_START     ((unsigned long)VSYSCALL32_VSYSCALL)
+#define FIXADDR_USER_END       (FIXADDR_USER_START + PAGE_SIZE)
+
+#define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without translation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+       /*
+        * this branch gets completely eliminated after inlining,
+        * except when someone tries to use fixaddr indices in an
+        * illegal way. (such as mixing up address types or using
+        * out-of-range indices).
+        *
+        * If it doesn't get removed, the linker will complain
+        * loudly with a reasonably clear error message..
+        */
+       if (idx >= __end_of_fixed_addresses)
+               __this_fixmap_does_not_exist();
+
+       return __fix_to_virt(idx);
+}
+
+#endif
diff --git a/kitten/include/arch-x86_64/i387.h b/kitten/include/arch-x86_64/i387.h
new file mode 100644 (file)
index 0000000..c927364
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * include/asm-x86_64/i387.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * General FPU state handling cleanups
+ *     Gareth Hughes <gareth@valinux.com>, May 2000
+ * x86-64 work by Andi Kleen 2002
+ */
+
+#ifndef _X86_64_I387_H
+#define _X86_64_I387_H
+
+#include <lwk/task.h>
+#include <lwk/errno.h>
+#include <arch/processor.h>
+#include <arch/sigcontext.h>
+#include <arch/user.h>
+#include <arch/uaccess.h>
+
+extern void fpu_init(void);
+extern unsigned int mxcsr_feature_mask;
+extern void mxcsr_feature_mask_init(void);
+
+/* Ignore delayed exceptions from user space */
+static inline void tolerant_fwait(void)
+{
+       asm volatile("1: fwait\n"
+                    "2:\n"
+                    "   .section __ex_table,\"a\"\n"
+                    "  .align 8\n"
+                    "  .quad 1b,2b\n"
+                    "  .previous\n");
+}
+
+#define clear_fpu(tsk) do { \
+       if (tsk->arch.status & TS_USEDFPU) {                    \
+               tolerant_fwait();                               \
+               tsk->arch.status &= ~TS_USEDFPU;                \
+               stts();                                         \
+       }                                                       \
+} while (0)
+
+/*
+ * ptrace request handers...
+ */
+extern int get_fpregs(struct user_i387_struct __user *buf,
+                     struct task_struct *tsk);
+extern int set_fpregs(struct task_struct *tsk,
+                     struct user_i387_struct __user *buf);
+
+/*
+ * i387 state interaction
+ */
+#define get_fpu_mxcsr(t) ((t)->arch.i387.fxsave.mxcsr)
+#define get_fpu_cwd(t) ((t)->arch.i387.fxsave.cwd)
+#define get_fpu_fxsr_twd(t) ((t)->arch.i387.fxsave.twd)
+#define get_fpu_swd(t) ((t)->arch.i387.fxsave.swd)
+#define set_fpu_cwd(t,val) ((t)->arch.i387.fxsave.cwd = (val))
+#define set_fpu_swd(t,val) ((t)->arch.i387.fxsave.swd = (val))
+#define set_fpu_fxsr_twd(t,val) ((t)->arch.i387.fxsave.twd = (val))
+
+#define X87_FSW_ES (1 << 7)    /* Exception Summary */
+
+/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
+   is pending. Clear the x87 state here by setting it to fixed
+   values. The kernel data segment can be sometimes 0 and sometimes
+   new user value. Both should be ok.
+   Use the PDA as safe address because it should be already in L1. */
+static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
+{
+       if (unlikely(fx->swd & X87_FSW_ES))
+                asm volatile("fnclex");
+
+       /*
+        * Unconditional fix for AMD CPUs that don't save/restore FDP/FIP/FOP.
+        * TODO: some CPUs may not need this, possibly use Linux
+        *       alternative_input() mechanism.
+        */
+       asm volatile ("emms");          /* clear stack tags */
+       asm volatile ("fildl %gs:0");   /* load to clear state */
+}
+
+static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) 
+{ 
+       int err;
+
+       asm volatile("1:  rex64/fxsave (%[fx])\n\t"
+                    "2:\n"
+                    ".section .fixup,\"ax\"\n"
+                    "3:  movl $-1,%[err]\n"
+                    "    jmp  2b\n"
+                    ".previous\n"
+                    ".section __ex_table,\"a\"\n"
+                    "   .align 8\n"
+                    "   .quad  1b,3b\n"
+                    ".previous"
+                    : [err] "=r" (err), "=m" (*fx)
+#if 0 /* See comment in __fxsave_clear() below. */
+                    : [fx] "r" (fx), "0" (0));
+#else
+                    : [fx] "cdaSDb" (fx), "0" (0));
+#endif
+       if (unlikely(err) && __clear_user(fx, sizeof(struct i387_fxsave_struct)))
+               err = -EFAULT;
+       /* No need to clear here because the caller clears USED_MATH */
+       return err;
+} 
+
+static inline void __fxsave_clear(struct task_struct *tsk)
+{
+       /* Using "rex64; fxsave %0" is broken because, if the memory operand
+          uses any extended registers for addressing, a second REX prefix
+          will be generated (to the assembler, rex64 followed by semicolon
+          is a separate instruction), and hence the 64-bitness is lost. */
+#if 0
+       /* Using "fxsaveq %0" would be the ideal choice, but is only supported
+          starting with gas 2.16. */
+       __asm__ __volatile__("fxsaveq %0"
+                            : "=m" (tsk->arch.thread.i387.fxsave));
+#elif 0
+       /* Using, as a workaround, the properly prefixed form below isn't
+          accepted by any binutils version so far released, complaining that
+          the same type of prefix is used twice if an extended register is
+          needed for addressing (fix submitted to mainline 2005-11-21). */
+       __asm__ __volatile__("rex64/fxsave %0"
+                            : "=m" (tsk->arch.thread.i387.fxsave));
+#else
+       /* This, however, we can work around by forcing the compiler to select
+          an addressing mode that doesn't require extended registers. */
+       __asm__ __volatile__("rex64/fxsave %P2(%1)"
+                            : "=m" (tsk->arch.thread.i387.fxsave)
+                            : "cdaSDb" (tsk),
+                               "i" (offsetof(__typeof__(*tsk),
+                                             arch.thread.i387.fxsave)));
+#endif
+       clear_fpu_state(&tsk->arch.thread.i387.fxsave);
+}
+
+static inline void kernel_fpu_begin(void)
+{
+       if (current->arch.flags & TF_USED_FPU) {
+               __fxsave_clear(current);
+               return;
+       }
+       clts();
+}
+
+static inline void kernel_fpu_end(void)
+{
+       stts();
+}
+
+static inline void
+fpu_save_state(struct task_struct *task)
+{
+       __asm__ __volatile__("fxsaveq %0"
+                            : "=m" (task->arch.thread.i387.fxsave));
+       clear_fpu_state(&task->arch.thread.i387.fxsave);
+}
+
+static inline void
+fpu_restore_state(struct task_struct *task)
+{
+       __asm__ __volatile__("fxrstorq %0"
+                            ::"m" (task->arch.thread.i387.fxsave));
+}
+
+#endif /* _X86_64_I387_H */
diff --git a/kitten/include/arch-x86_64/idt_vectors.h b/kitten/include/arch-x86_64/idt_vectors.h
new file mode 100644 (file)
index 0000000..d64806e
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef _ARCH_X86_64_IDT_VECTORS_H
+#define _ARCH_X86_64_IDT_VECTORS_H
+
+/*
+ * Based on linux/include/asm-x86_64/hw_irq.h
+ * Original file header:
+ *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *     moved some of the old arch/i386/kernel/irq.h to here. VY
+ *     IRQ/IPI changes taken from work by Thomas Radke
+ *     <tomsoft@informatik.tu-chemnitz.de>
+ *     hacked by Andi Kleen for x86-64.
+ */
+
+/**
+ * This file defines symbolic names for interrupt vectors installed in the
+ * Interrupt Descriptor Table (IDT). The IDT contains entries for 256 interrupt
+ * vectors.  Vectors [0,31] are used for specific purposes defined by the x86_64
+ * architecture.  Vectors [32,255] are available for external interrupts. The
+ * LWK uses a number of interrupt vectors for its own internal purposes, e.g.,
+ * inter-processor interrupts for TLB invalidations.
+ */
+
+/*
+ * [0,31] Standard x86_64 architecture vectors
+ */
+#define DIVIDE_ERROR_VECTOR                    0
+#define DEBUG_VECTOR                           1
+#define NMI_VECTOR                             2
+#define INT3_VECTOR                            3
+#define OVERFLOW_VECTOR                                4
+#define BOUNDS_VECTOR                          5
+#define INVALID_OP_VECTOR                      6
+#define DEVICE_NOT_AVAILABLE_VECTOR            7
+#define DOUBLE_FAULT_VECTOR                    8
+#define COPROC_SEGMENT_OVERRUN_VECTOR          9
+#define INVALID_TSS_VECTOR                     10
+#define SEGMENT_NOT_PRESENT_VECTOR             11
+#define STACK_SEGMENT_VECTOR                   12
+#define GENERAL_PROTECTION_VECTOR              13
+#define PAGE_FAULT_VECTOR                      14
+#define SPURIOUS_INTERRUPT_BUG_VECTOR          15
+#define COPROCESSOR_ERROR_VECTOR               16
+#define ALIGNMENT_CHECK_VECTOR                 17
+#define MACHINE_CHECK_VECTOR                   18
+#define SIMD_COPROCESSOR_ERROR_VECTOR          19
+/*
+ * [20,31] Reserved by x86_64 architecture for future use
+ * [32,47] Free for use by devices
+ * [48,63] Standard ISA IRQs
+ */
+#define IRQ0_VECTOR                            48
+#define IRQ1_VECTOR                            49
+#define IRQ2_VECTOR                            50
+#define IRQ3_VECTOR                            51
+#define IRQ4_VECTOR                            52
+#define IRQ5_VECTOR                            53
+#define IRQ6_VECTOR                            54
+#define IRQ7_VECTOR                            55
+#define IRQ8_VECTOR                            56
+#define IRQ9_VECTOR                            57
+#define IRQ10_VECTOR                           58
+#define IRQ11_VECTOR                           59
+#define IRQ12_VECTOR                           60
+#define IRQ13_VECTOR                           61
+#define IRQ14_VECTOR                           62
+#define IRQ15_VECTOR                           63
+/*
+ * [64,238]  Free for use by devices
+ * [239,255] Used by LWK for various internal purposes
+ */
+#define APIC_TIMER_VECTOR                      239
+#define INVALIDATE_TLB_0_VECTOR                        240
+#define INVALIDATE_TLB_1_VECTOR                        241
+#define INVALIDATE_TLB_2_VECTOR                        242
+#define INVALIDATE_TLB_3_VECTOR                        243
+#define INVALIDATE_TLB_4_VECTOR                        244
+#define INVALIDATE_TLB_5_VECTOR                        245
+#define INVALIDATE_TLB_6_VECTOR                        246
+#define INVALIDATE_TLB_7_VECTOR                        247
+/* 248 is available */
+#define APIC_PERF_COUNTER_VECTOR               249
+#define APIC_THERMAL_VECTOR                    250
+/* 251 is available */
+#define XCALL_FUNCTION_VECTOR                  252
+#define XCALL_RESCHEDULE_VECTOR                        253
+#define APIC_ERROR_VECTOR                      254
+#define APIC_SPURIOUS_VECTOR                   255
+
+/**
+ * Meta-defines describing the interrupt vector space defined above.
+ */
+#define NUM_IDT_ENTRIES                                256
+#define FIRST_EXTERNAL_VECTOR                  32
+#define FIRST_SYSTEM_VECTOR                    239
+#define INVALIDATE_TLB_VECTOR_START            240
+#define INVALIDATE_TLB_VECTOR_END              247
+#define NUM_INVALIDATE_TLB_VECTORS             8
+
+#endif
diff --git a/kitten/include/arch-x86_64/io.h b/kitten/include/arch-x86_64/io.h
new file mode 100644 (file)
index 0000000..ebf42d8
--- /dev/null
@@ -0,0 +1,308 @@
+#ifndef _ARCH_IO_H
+#define _ARCH_IO_H
+
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ * On the other hand, I'd like to be sure of a non-existent port:
+ * I feel a bit unsafe about using 0x80 (should be safe, though)
+ *
+ *             Linus
+ */
+
+ /*
+  *  Bit simplified and optimized by Jan Hubicka
+  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
+  *
+  *  isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
+  *  isa_read[wl] and isa_write[wl] fixed
+  *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+  */
+
+#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+
+#ifdef REALLY_SLOW_IO
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
+#else
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+#endif
+
+/*
+ * Talk about misusing macros..
+ */
+#define __OUT1(s,x) \
+static inline void out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+
+#define __IN1(s) \
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+
+#define __INS(s) \
+static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+#define IO_SPACE_LIMIT 0xffff
+
+#if defined(__KERNEL__) && __x86_64__
+
+// #include <linux/vmalloc.h>
+
+#ifndef __i386__
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are pretty trivial
+ */
+static inline unsigned long virt_to_phys(volatile void * address)
+{
+       return __pa(address);
+}
+
+static inline void * phys_to_virt(unsigned long address)
+{
+       return __va(address);
+}
+#endif
+
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)    ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
+
+#include <arch-generic/iomap.h>
+
+extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+static inline void __iomem * ioremap (unsigned long offset, unsigned long size)
+{
+       return __ioremap(offset, size, 0);
+}
+
+extern void *early_ioremap(unsigned long addr, unsigned long size);
+extern void early_iounmap(void *addr, unsigned long size);
+
+/*
+ * This one maps high address device memory and turns off caching for that area.
+ * it's useful if some control registers are in such an area and write combining
+ * or read caching is not desirable:
+ */
+extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
+extern void iounmap(volatile void __iomem *addr);
+
+/*
+ * ISA I/O bus memory addresses are 1:1 with the physical address.
+ */
+#define isa_virt_to_bus virt_to_phys
+#define isa_page_to_bus page_to_phys
+#define isa_bus_to_virt phys_to_virt
+
+/*
+ * However PCI ones are not necessarily 1:1 and therefore these interfaces
+ * are forbidden in portable PCI drivers.
+ *
+ * Allow them on x86 for legacy drivers, though.
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+
+static inline __u8 __readb(const volatile void __iomem *addr)
+{
+       return *(__force volatile __u8 *)addr;
+}
+static inline __u16 __readw(const volatile void __iomem *addr)
+{
+       return *(__force volatile __u16 *)addr;
+}
+static __always_inline __u32 __readl(const volatile void __iomem *addr)
+{
+       return *(__force volatile __u32 *)addr;
+}
+static inline __u64 __readq(const volatile void __iomem *addr)
+{
+       return *(__force volatile __u64 *)addr;
+}
+#define readb(x) __readb(x)
+#define readw(x) __readw(x)
+#define readl(x) __readl(x)
+#define readq(x) __readq(x)
+#define readb_relaxed(a) readb(a)
+#define readw_relaxed(a) readw(a)
+#define readl_relaxed(a) readl(a)
+#define readq_relaxed(a) readq(a)
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+#define __raw_readq readq
+
+#define mmiowb()
+
+static inline void __writel(__u32 b, volatile void __iomem *addr)
+{
+       *(__force volatile __u32 *)addr = b;
+}
+static inline void __writeq(__u64 b, volatile void __iomem *addr)
+{
+       *(__force volatile __u64 *)addr = b;
+}
+static inline void __writeb(__u8 b, volatile void __iomem *addr)
+{
+       *(__force volatile __u8 *)addr = b;
+}
+static inline void __writew(__u16 b, volatile void __iomem *addr)
+{
+       *(__force volatile __u16 *)addr = b;
+}
+#define writeq(val,addr) __writeq((val),(addr))
+#define writel(val,addr) __writel((val),(addr))
+#define writew(val,addr) __writew((val),(addr))
+#define writeb(val,addr) __writeb((val),(addr))
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+#define __raw_writeq writeq
+
+void __memcpy_fromio(void*,unsigned long,unsigned);
+void __memcpy_toio(unsigned long,const void*,unsigned);
+
+static inline void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len)
+{
+       __memcpy_fromio(to,(unsigned long)from,len);
+}
+static inline void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len)
+{
+       __memcpy_toio((unsigned long)to,from,len);
+}
+
+void memset_io(volatile void __iomem *a, int b, size_t c);
+
+/*
+ * ISA space is 'always mapped' on a typical x86 system, no need to
+ * explicitly ioremap() it. The fact that the ISA IO space is mapped
+ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
+ * are physical addresses. The following constant pointer can be
+ * used as the IO-area pointer (it can be iounmapped as well, so the
+ * analogy with PCI is quite large):
+ */
+#define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
+
+/*
+ * Again, x86-64 does not require mem IO specific function.
+ */
+
+#define eth_io_copy_and_sum(a,b,c,d)           eth_copy_and_sum((a),(void *)(b),(c),(d))
+
+/**
+ *     check_signature         -       find BIOS signatures
+ *     @io_addr: mmio address to check 
+ *     @signature:  signature block
+ *     @length: length of signature
+ *
+ *     Perform a signature comparison with the mmio address io_addr. This
+ *     address should have been obtained by ioremap.
+ *     Returns 1 on a match.
+ */
+static inline int check_signature(void __iomem *io_addr,
+       const unsigned char *signature, int length)
+{
+       int retval = 0;
+       do {
+               if (readb(io_addr) != *signature)
+                       goto out;
+               io_addr++;
+               signature++;
+               length--;
+       } while (length);
+       retval = 1;
+out:
+       return retval;
+}
+
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
+#define flush_write_buffers() 
+
+extern int iommu_bio_merge;
+#define BIO_VMERGE_BOUNDARY iommu_bio_merge
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)   __va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)  p
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/kitten/include/arch-x86_64/io_apic.h b/kitten/include/arch-x86_64/io_apic.h
new file mode 100644 (file)
index 0000000..f88d25e
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef __ASM_IO_APIC_H
+#define __ASM_IO_APIC_H
+
+#include <lwk/spinlock.h>
+#include <arch/types.h>
+#include <arch/mpspec.h>
+
+/*
+ * Intel IO-APIC support for SMP and UP systems.
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
+ */
+
+static inline int use_pci_vector(void) {return 1;}
+static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+static inline void end_edge_ioapic_vector (unsigned int vector) { }
+#define startup_level_ioapic   startup_level_ioapic_vector
+#define shutdown_level_ioapic  mask_IO_APIC_vector
+#define enable_level_ioapic    unmask_IO_APIC_vector
+#define disable_level_ioapic   mask_IO_APIC_vector
+#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
+#define end_level_ioapic       end_level_ioapic_vector
+#define set_ioapic_affinity    set_ioapic_affinity_vector
+
+#define startup_edge_ioapic    startup_edge_ioapic_vector
+#define shutdown_edge_ioapic   disable_edge_ioapic_vector
+#define enable_edge_ioapic     unmask_IO_APIC_vector
+#define disable_edge_ioapic    disable_edge_ioapic_vector
+#define ack_edge_ioapic        ack_edge_ioapic_vector
+#define end_edge_ioapic        end_edge_ioapic_vector
+
+#define APIC_MISMATCH_DEBUG
+
+#define IO_APIC_BASE(idx) \
+               ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
+               + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
+
+/*
+ * The structure of the IO-APIC:
+ */
+union IO_APIC_reg_00 {
+       u32     raw;
+       struct {
+               u32     __reserved_2    : 14,
+                       LTS             :  1,
+                       delivery_type   :  1,
+                       __reserved_1    :  8,
+                       ID              :  8;
+       } __attribute__ ((packed)) bits;
+};
+
+union IO_APIC_reg_01 {
+       u32     raw;
+       struct {
+               u32     version         :  8,
+               __reserved_2    :  7,
+               PRQ             :  1,
+               entries         :  8,
+               __reserved_1    :  8;
+       } __attribute__ ((packed)) bits;
+};
+
+union IO_APIC_reg_02 {
+       u32     raw;
+       struct {
+               u32     __reserved_2    : 24,
+               arbitration     :  4,
+               __reserved_1    :  4;
+       } __attribute__ ((packed)) bits;
+};
+
+union IO_APIC_reg_03 {
+       u32     raw;
+       struct {
+               u32     boot_DT         :  1,
+                       __reserved_1    : 31;
+       } __attribute__ ((packed)) bits;
+};
+
+/*
+ * # of IO-APICs and # of IRQ routing registers
+ */
+extern int nr_ioapics;
+extern int nr_ioapic_registers[MAX_IO_APICS];
+
+enum ioapic_trigger_modes {
+       ioapic_edge_sensitive  = 0,
+       ioapic_level_sensitive = 1
+};
+
+enum ioapic_pin_polarities {
+       ioapic_active_high = 0,
+       ioapic_active_low  = 1
+};
+
+enum ioapic_destination_modes {
+       ioapic_physical_dest = 0,
+       ioapic_logical_dest  = 1
+};
+
+enum ioapic_delivery_modes {
+       ioapic_fixed           = 0,
+       ioapic_lowest_priority = 1,
+       ioapic_SMI             = 2,
+       ioapic_NMI             = 4,
+       ioapic_INIT            = 5,
+       ioapic_ExtINT          = 7
+};
+
+struct IO_APIC_route_entry {
+       __u32   vector          :  8,
+               delivery_mode   :  3,   /* 000: FIXED
+                                        * 001: lowest prio
+                                        * 111: ExtINT
+                                        */
+               dest_mode       :  1,   /* 0: physical, 1: logical */
+               delivery_status :  1,
+               polarity        :  1,
+               irr             :  1,
+               trigger         :  1,   /* 0: edge, 1: level */
+               mask            :  1,   /* 0: enabled, 1: disabled */
+               __reserved_2    : 15;
+
+       __u32   __reserved_3    : 24,
+               dest            :  8;
+} __attribute__ ((packed));
+
+/*
+ * MP-BIOS irq configuration table structures:
+ */
+
+/* I/O APIC entries */
+extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+
+/* # of MP IRQ source entries */
+extern int mp_irq_entries;
+
+/* MP IRQ source entries */
+extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+/* non-0 if default (table-less) MP configuration */
+extern int mpc_default_type;
+
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+{
+       *IO_APIC_BASE(apic) = reg;
+       return *(IO_APIC_BASE(apic)+4);
+}
+
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+{
+       *IO_APIC_BASE(apic) = reg;
+       *(IO_APIC_BASE(apic)+4) = value;
+}
+
+/*
+ * Re-write a value: to be used for read-modify-write
+ * cycles where the read already set up the index register.
+ */
+static inline void io_apic_modify(unsigned int apic, unsigned int value)
+{
+       *(IO_APIC_BASE(apic)+4) = value;
+}
+
+/*
+ * Synchronize the IO-APIC and the CPU by doing
+ * a dummy read from the IO-APIC
+ */
+static inline void io_apic_sync(unsigned int apic)
+{
+       (void) *(IO_APIC_BASE(apic)+4);
+}
+
+/* 1 if "noapic" boot option passed */
+extern int skip_ioapic_setup;
+
+/*
+ * If we use the IO-APIC for IRQ routing, disable automatic
+ * assignment of PCI IRQ's.
+ */
+#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
+
+#ifdef CONFIG_ACPI
+extern int io_apic_get_version (int ioapic);
+extern int io_apic_get_redir_entries (int ioapic);
+extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
+extern int timer_uses_ioapic_pin_0;
+#endif
+
+extern int sis_apic_bug; /* dummy */ 
+
+extern int assign_irq_vector(int irq);
+
+void enable_NMI_through_LVT0 (void * dummy);
+
+extern spinlock_t i8259A_lock;
+
+extern unsigned int ioapic_num;
+extern unsigned int ioapic_id[MAX_IO_APICS];
+extern unsigned long ioapic_phys_addr[MAX_IO_APICS];
+
+extern void __init ioapic_map(void);
+extern void __init ioapic_init(void);
+extern void ioapic_dump(void);
+
+
+#endif
diff --git a/kitten/include/arch-x86_64/ldt.h b/kitten/include/arch-x86_64/ldt.h
new file mode 100644 (file)
index 0000000..9ef647b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ldt.h
+ *
+ * Definitions of structures used with the modify_ldt system call.
+ */
+#ifndef _LINUX_LDT_H
+#define _LINUX_LDT_H
+
+/* Maximum number of LDT entries supported. */
+#define LDT_ENTRIES    8192
+/* The size of each LDT entry. */
+#define LDT_ENTRY_SIZE 8
+
+#ifndef __ASSEMBLY__
+/* Note on 64bit base and limit is ignored and you cannot set
+   DS/ES/CS not to the default values if you still want to do syscalls. This
+   call is more for 32bit mode therefore. */
+struct user_desc {
+       unsigned int  entry_number;
+       unsigned int  base_addr;
+       unsigned int  limit;
+       unsigned int  seg_32bit:1;
+       unsigned int  contents:2;
+       unsigned int  read_exec_only:1;
+       unsigned int  limit_in_pages:1;
+       unsigned int  seg_not_present:1;
+       unsigned int  useable:1;
+       unsigned int  lm:1;
+};
+
+#define MODIFY_LDT_CONTENTS_DATA       0
+#define MODIFY_LDT_CONTENTS_STACK      1
+#define MODIFY_LDT_CONTENTS_CODE       2
+
+#endif /* !__ASSEMBLY__ */
+#endif
diff --git a/kitten/include/arch-x86_64/linkage.h b/kitten/include/arch-x86_64/linkage.h
new file mode 100644 (file)
index 0000000..aa5674f
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ARCH_LINKAGE_H
+#define _ARCH_LINKAGE_H
+
+/* Nothing to see here... */
+
+#endif
diff --git a/kitten/include/arch-x86_64/mman.h b/kitten/include/arch-x86_64/mman.h
new file mode 100644 (file)
index 0000000..a0e8407
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __X8664_MMAN_H__
+#define __X8664_MMAN_H__
+
+#include <arch-generic/mman.h>
+
+#define MAP_32BIT      0x40            /* only give out 32bit addresses */
+
+#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
+#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
+#define MAP_LOCKED     0x2000          /* pages are locked */
+#define MAP_NORESERVE  0x4000          /* don't check for reservations */
+#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
+#define MAP_NONBLOCK   0x10000         /* do not block on IO */
+
+#define MCL_CURRENT    1               /* lock all current mappings */
+#define MCL_FUTURE     2               /* lock all future mappings */
+
+#endif
diff --git a/kitten/include/arch-x86_64/mmu.h b/kitten/include/arch-x86_64/mmu.h
new file mode 100644 (file)
index 0000000..3c612f7
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _X86_64_MMU_H
+#define _X86_64_MMU_H
+
+#include <lwk/spinlock.h>
+// #include <asm/semaphore.h>
+
+/*
+ * The x86_64 doesn't have a mmu context, but
+ * we put the segment information here.
+ */
+typedef struct { 
+       void *ldt;
+       rwlock_t ldtlock; 
+       int size;
+//     struct semaphore sem; 
+} mm_context_t;
+
+#endif
diff --git a/kitten/include/arch-x86_64/mpspec.h b/kitten/include/arch-x86_64/mpspec.h
new file mode 100644 (file)
index 0000000..83cdf13
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef __ASM_MPSPEC_H
+#define __ASM_MPSPEC_H
+
+#include <lwk/kernel.h>
+
+/*
+ * Structure definitions for SMP machines following the
+ * Intel Multiprocessing Specification 1.1 and 1.4.
+ */
+
+/*
+ * This tag identifies where the SMP configuration
+ * information is. 
+ */
+#define SMP_MAGIC_IDENT        (('_'<<24)|('P'<<16)|('M'<<8)|'_')
+
+/*
+ * A maximum of 255 APICs with the current APIC ID architecture.
+ */
+#define MAX_APICS 255
+
+struct intel_mp_floating
+{
+       char mpf_signature[4];          /* "_MP_"                       */
+       unsigned int mpf_physptr;       /* Configuration table address  */
+       unsigned char mpf_length;       /* Our length (paragraphs)      */
+       unsigned char mpf_specification;/* Specification version        */
+       unsigned char mpf_checksum;     /* Checksum (makes sum 0)       */
+       unsigned char mpf_feature1;     /* Standard or configuration ?  */
+       unsigned char mpf_feature2;     /* Bit7 set for IMCR|PIC        */
+       unsigned char mpf_feature3;     /* Unused (0)                   */
+       unsigned char mpf_feature4;     /* Unused (0)                   */
+       unsigned char mpf_feature5;     /* Unused (0)                   */
+};
+sizecheck_struct(intel_mp_floating, 16);
+
+struct mp_config_table
+{
+       char mpc_signature[4];
+#define MPC_SIGNATURE "PCMP"
+       unsigned short mpc_length;      /* Size of table */
+       char  mpc_spec;                 /* 0x01 */
+       char  mpc_checksum;
+       char  mpc_oem[8];
+       char  mpc_productid[12];
+       unsigned int mpc_oemptr;        /* 0 if not present */
+       unsigned short mpc_oemsize;     /* 0 if not present */
+       unsigned short mpc_oemcount;
+       unsigned int mpc_lapic; /* APIC address */
+       unsigned int reserved;
+};
+
+/* Followed by entries */
+
+#define        MP_PROCESSOR    0
+#define        MP_BUS          1
+#define        MP_IOAPIC       2
+#define        MP_INTSRC       3
+#define        MP_LINTSRC      4
+
+struct mpc_config_processor
+{
+       unsigned char mpc_type;
+       unsigned char mpc_apicid;       /* Local APIC number */
+       unsigned char mpc_apicver;      /* Its versions */
+       unsigned char mpc_cpuflag;
+#define CPU_ENABLED            1       /* Processor is available */
+#define CPU_BOOTPROCESSOR      2       /* Processor is the BP */
+       unsigned int mpc_cpufeature;            
+#define CPU_STEPPING_MASK 0x0F
+#define CPU_MODEL_MASK 0xF0
+#define CPU_FAMILY_MASK        0xF00
+       unsigned int mpc_featureflag;   /* CPUID feature value */
+       unsigned int mpc_reserved[2];
+};
+
+struct mpc_config_bus
+{
+       unsigned char mpc_type;
+       unsigned char mpc_busid;
+       unsigned char mpc_bustype[6];
+};
+
+/* List of Bus Type string values, Intel MP Spec. */
+#define BUSTYPE_EISA   "EISA"
+#define BUSTYPE_ISA    "ISA"
+#define BUSTYPE_INTERN "INTERN"        /* Internal BUS */
+#define BUSTYPE_MCA    "MCA"
+#define BUSTYPE_VL     "VL"            /* Local bus */
+#define BUSTYPE_PCI    "PCI"
+#define BUSTYPE_PCMCIA "PCMCIA"
+#define BUSTYPE_CBUS   "CBUS"
+#define BUSTYPE_CBUSII "CBUSII"
+#define BUSTYPE_FUTURE "FUTURE"
+#define BUSTYPE_MBI    "MBI"
+#define BUSTYPE_MBII   "MBII"
+#define BUSTYPE_MPI    "MPI"
+#define BUSTYPE_MPSA   "MPSA"
+#define BUSTYPE_NUBUS  "NUBUS"
+#define BUSTYPE_TC     "TC"
+#define BUSTYPE_VME    "VME"
+#define BUSTYPE_XPRESS "XPRESS"
+
+struct mpc_config_ioapic
+{
+       unsigned char mpc_type;
+       unsigned char mpc_apicid;
+       unsigned char mpc_apicver;
+       unsigned char mpc_flags;
+#define MPC_APIC_USABLE                0x01
+       unsigned int mpc_apicaddr;
+};
+
+struct mpc_config_intsrc
+{
+       unsigned char mpc_type;
+       unsigned char mpc_irqtype;
+       unsigned short mpc_irqflag;
+       unsigned char mpc_srcbus;
+       unsigned char mpc_srcbusirq;
+       unsigned char mpc_dstapic;
+       unsigned char mpc_dstirq;
+};
+
+enum mp_irq_source_types {
+       mp_INT = 0,
+       mp_NMI = 1,
+       mp_SMI = 2,
+       mp_ExtINT = 3
+};
+
+#define MP_IRQDIR_DEFAULT      0
+#define MP_IRQDIR_HIGH         1
+#define MP_IRQDIR_LOW          3
+
+
+struct mpc_config_lintsrc
+{
+       unsigned char mpc_type;
+       unsigned char mpc_irqtype;
+       unsigned short mpc_irqflag;
+       unsigned char mpc_srcbusid;
+       unsigned char mpc_srcbusirq;
+       unsigned char mpc_destapic;     
+#define MP_APIC_ALL    0xFF
+       unsigned char mpc_destapiclint;
+};
+
+/*
+ *     Default configurations
+ *
+ *     1       2 CPU ISA 82489DX
+ *     2       2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
+ *     3       2 CPU EISA 82489DX
+ *     4       2 CPU MCA 82489DX
+ *     5       2 CPU ISA+PCI
+ *     6       2 CPU EISA+PCI
+ *     7       2 CPU MCA+PCI
+ */
+
+#define MAX_MP_BUSSES 256
+/* Each PCI slot may be a combo card with its own bus.  4 IRQ pins per slot. */
+#define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4)
+enum mp_bustype {
+       MP_BUS_ISA = 1,
+       MP_BUS_EISA,
+       MP_BUS_PCI,
+       MP_BUS_MCA
+};
+extern unsigned char mp_bus_id_to_type [MAX_MP_BUSSES];
+extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
+
+extern unsigned int boot_cpu_physical_apicid;
+extern int smp_found_config;
+extern void find_mp_config(void);
+extern void get_mp_config(void);
+extern int nr_ioapics;
+extern unsigned char apic_version [MAX_APICS];
+extern int mp_irq_entries;
+extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern int mpc_default_type;
+extern unsigned long mp_lapic_addr;
+extern int pic_mode;
+
+#ifdef CONFIG_ACPI
+extern void mp_register_lapic (u8 id, u8 enabled);
+extern void mp_register_lapic_address (u64 address);
+
+#ifdef CONFIG_X86_IO_APIC
+extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
+extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
+extern void mp_config_acpi_legacy_irqs (void);
+extern int mp_register_gsi (u32 gsi, int triggering, int polarity);
+#endif /*CONFIG_X86_IO_APIC*/
+#endif
+
+extern int using_apic_timer;
+
+#define PHYSID_ARRAY_SIZE      BITS_TO_LONGS(MAX_APICS)
+
+struct physid_mask
+{
+       unsigned long mask[PHYSID_ARRAY_SIZE];
+};
+
+typedef struct physid_mask physid_mask_t;
+
+#define physid_set(physid, map)                        set_bit(physid, (map).mask)
+#define physid_clear(physid, map)              clear_bit(physid, (map).mask)
+#define physid_isset(physid, map)              test_bit(physid, (map).mask)
+#define physid_test_and_set(physid, map)       test_and_set_bit(physid, (map).mask)
+
+#define physids_and(dst, src1, src2)           bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
+#define physids_or(dst, src1, src2)            bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
+#define physids_clear(map)                     bitmap_zero((map).mask, MAX_APICS)
+#define physids_complement(dst, src)           bitmap_complement((dst).mask, (src).mask, MAX_APICS)
+#define physids_empty(map)                     bitmap_empty((map).mask, MAX_APICS)
+#define physids_equal(map1, map2)              bitmap_equal((map1).mask, (map2).mask, MAX_APICS)
+#define physids_weight(map)                    bitmap_weight((map).mask, MAX_APICS)
+#define physids_shift_right(d, s, n)           bitmap_shift_right((d).mask, (s).mask, n, MAX_APICS)
+#define physids_shift_left(d, s, n)            bitmap_shift_left((d).mask, (s).mask, n, MAX_APICS)
+#define physids_coerce(map)                    ((map).mask[0])
+
+#define physids_promote(physids)                                               \
+       ({                                                                      \
+               physid_mask_t __physid_mask = PHYSID_MASK_NONE;                 \
+               __physid_mask.mask[0] = physids;                                \
+               __physid_mask;                                                  \
+       })
+
+#define physid_mask_of_physid(physid)                                          \
+       ({                                                                      \
+               physid_mask_t __physid_mask = PHYSID_MASK_NONE;                 \
+               physid_set(physid, __physid_mask);                              \
+               __physid_mask;                                                  \
+       })
+
+#define PHYSID_MASK_ALL                { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} }
+#define PHYSID_MASK_NONE       { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} }
+
+extern physid_mask_t phys_cpu_present_map;
+
+#endif
+
diff --git a/kitten/include/arch-x86_64/msr.h b/kitten/include/arch-x86_64/msr.h
new file mode 100644 (file)
index 0000000..eb7f909
--- /dev/null
@@ -0,0 +1,403 @@
+#ifndef _X86_64_MSR_H
+#define _X86_64_MSR_H
+
+#ifndef __ASSEMBLY__
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+                           : "=a" (val1), "=d" (val2) \
+                           : "c" (msr))
+
+
+#define rdmsrl(msr,val) do { unsigned long a__,b__; \
+       __asm__ __volatile__("rdmsr" \
+                           : "=a" (a__), "=d" (b__) \
+                           : "c" (msr)); \
+       val = a__ | (b__<<32); \
+} while(0)
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+                         : /* no outputs */ \
+                         : "c" (msr), "a" (val1), "d" (val2))
+
+#define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) 
+
+/* wrmsr with exception handling */
+#define wrmsr_safe(msr,a,b) ({ int ret__;                      \
+       asm volatile("2: wrmsr ; xorl %0,%0\n"                  \
+                    "1:\n\t"                                   \
+                    ".section .fixup,\"ax\"\n\t"               \
+                    "3:  movl %4,%0 ; jmp 1b\n\t"              \
+                    ".previous\n\t"                            \
+                    ".section __ex_table,\"a\"\n"              \
+                    "   .align 8\n\t"                          \
+                    "   .quad  2b,3b\n\t"                      \
+                    ".previous"                                \
+                    : "=a" (ret__)                             \
+                    : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \
+       ret__; })
+
+#define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
+
+#define rdmsr_safe(msr,a,b) \
+       ({ int ret__;                                           \
+         asm volatile ("1:       rdmsr\n"                      \
+                      "2:\n"                                   \
+                      ".section .fixup,\"ax\"\n"               \
+                      "3:       movl %4,%0\n"                  \
+                      " jmp 2b\n"                              \
+                      ".previous\n"                            \
+                      ".section __ex_table,\"a\"\n"            \
+                      " .align 8\n"                            \
+                      " .quad 1b,3b\n"                         \
+                      ".previous":"=&bDS" (ret__), "=a"(*(a)), "=d"(*(b))\
+                      :"c"(msr), "i"(-EIO), "0"(0));           \
+         ret__; })             
+
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+     __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) do { \
+     unsigned int __a,__d; \
+     asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
+     (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
+} while(0)
+
+#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+                         : "=a" (low), "=d" (high) \
+                         : "c" (counter))
+
+static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx,
+                        unsigned int *ecx, unsigned int *edx)
+{
+       __asm__("cpuid"
+               : "=a" (*eax),
+                 "=b" (*ebx),
+                 "=c" (*ecx),
+                 "=d" (*edx)
+               : "0" (op));
+}
+
+/* Some CPUID calls want 'count' to be placed in ecx */
+static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
+               int *edx)
+{
+       __asm__("cpuid"
+               : "=a" (*eax),
+                 "=b" (*ebx),
+                 "=c" (*ecx),
+                 "=d" (*edx)
+               : "0" (op), "c" (count));
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline unsigned int cpuid_eax(unsigned int op)
+{
+       unsigned int eax;
+
+       __asm__("cpuid"
+               : "=a" (eax)
+               : "0" (op)
+               : "bx", "cx", "dx");
+       return eax;
+}
+static inline unsigned int cpuid_ebx(unsigned int op)
+{
+       unsigned int eax, ebx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=b" (ebx)
+               : "0" (op)
+               : "cx", "dx" );
+       return ebx;
+}
+static inline unsigned int cpuid_ecx(unsigned int op)
+{
+       unsigned int eax, ecx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=c" (ecx)
+               : "0" (op)
+               : "bx", "dx" );
+       return ecx;
+}
+static inline unsigned int cpuid_edx(unsigned int op)
+{
+       unsigned int eax, edx;
+
+       __asm__("cpuid"
+               : "=a" (eax), "=d" (edx)
+               : "0" (op)
+               : "bx", "cx");
+       return edx;
+}
+
+#define MSR_IA32_UCODE_WRITE           0x79
+#define MSR_IA32_UCODE_REV             0x8b
+
+
+#endif
+
+/* AMD/K8 specific MSRs */ 
+#define MSR_EFER 0xc0000080            /* extended feature register */
+#define MSR_STAR 0xc0000081            /* legacy mode SYSCALL target */
+#define MSR_LSTAR 0xc0000082           /* long mode SYSCALL target */
+#define MSR_CSTAR 0xc0000083           /* compatibility mode SYSCALL target */
+#define MSR_SYSCALL_MASK 0xc0000084    /* EFLAGS mask for syscall */
+#define MSR_FS_BASE 0xc0000100         /* 64bit GS base */
+#define MSR_GS_BASE 0xc0000101         /* 64bit FS base */
+#define MSR_KERNEL_GS_BASE  0xc0000102 /* SwapGS GS shadow (or USER_GS from kernel) */ 
+/* EFER bits: */ 
+#define _EFER_SCE 0  /* SYSCALL/SYSRET */
+#define _EFER_LME 8  /* Long mode enable */
+#define _EFER_LMA 10 /* Long mode active (read-only) */
+#define _EFER_NX 11  /* No execute enable */
+
+#define EFER_SCE (1<<_EFER_SCE)
+#define EFER_LME (1<<_EFER_LME)
+#define EFER_LMA (1<<_EFER_LMA)
+#define EFER_NX (1<<_EFER_NX)
+
+/* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_TSC           0x10
+#define MSR_IA32_PLATFORM_ID   0x17
+
+#define MSR_IA32_PERFCTR0      0xc1
+#define MSR_IA32_PERFCTR1      0xc2
+
+#define MSR_MTRRcap            0x0fe
+#define MSR_IA32_BBL_CR_CTL        0x119
+
+#define MSR_IA32_SYSENTER_CS   0x174
+#define MSR_IA32_SYSENTER_ESP  0x175
+#define MSR_IA32_SYSENTER_EIP  0x176
+
+#define MSR_IA32_MCG_CAP       0x179
+#define MSR_IA32_MCG_STATUS        0x17a
+#define MSR_IA32_MCG_CTL       0x17b
+
+#define MSR_IA32_EVNTSEL0      0x186
+#define MSR_IA32_EVNTSEL1      0x187
+
+#define MSR_IA32_DEBUGCTLMSR       0x1d9
+#define MSR_IA32_LASTBRANCHFROMIP  0x1db
+#define MSR_IA32_LASTBRANCHTOIP        0x1dc
+#define MSR_IA32_LASTINTFROMIP     0x1dd
+#define MSR_IA32_LASTINTTOIP       0x1de
+
+#define MSR_MTRRfix64K_00000   0x250
+#define MSR_MTRRfix16K_80000   0x258
+#define MSR_MTRRfix16K_A0000   0x259
+#define MSR_MTRRfix4K_C0000    0x268
+#define MSR_MTRRfix4K_C8000    0x269
+#define MSR_MTRRfix4K_D0000    0x26a
+#define MSR_MTRRfix4K_D8000    0x26b
+#define MSR_MTRRfix4K_E0000    0x26c
+#define MSR_MTRRfix4K_E8000    0x26d
+#define MSR_MTRRfix4K_F0000    0x26e
+#define MSR_MTRRfix4K_F8000    0x26f
+#define MSR_MTRRdefType                0x2ff
+
+#define MSR_IA32_MC0_CTL       0x400
+#define MSR_IA32_MC0_STATUS        0x401
+#define MSR_IA32_MC0_ADDR      0x402
+#define MSR_IA32_MC0_MISC      0x403
+
+#define MSR_P6_PERFCTR0                        0xc1
+#define MSR_P6_PERFCTR1                        0xc2
+#define MSR_P6_EVNTSEL0                        0x186
+#define MSR_P6_EVNTSEL1                        0x187
+
+/* K7/K8 MSRs. Not complete. See the architecture manual for a more complete list. */
+#define MSR_K7_EVNTSEL0            0xC0010000
+#define MSR_K7_PERFCTR0            0xC0010004
+#define MSR_K7_EVNTSEL1            0xC0010001
+#define MSR_K7_PERFCTR1            0xC0010005
+#define MSR_K7_EVNTSEL2            0xC0010002
+#define MSR_K7_PERFCTR2            0xC0010006
+#define MSR_K7_EVNTSEL3            0xC0010003
+#define MSR_K7_PERFCTR3            0xC0010007
+#define MSR_K8_TOP_MEM1                   0xC001001A
+#define MSR_K8_TOP_MEM2                   0xC001001D
+#define MSR_K8_SYSCFG             0xC0010010
+#define MSR_K8_HWCR               0xC0010015
+#define MSR_K8_FIDVID_STATUS      0xC0010042
+
+/* AMD K10 MSRs */
+#define MSR_K10_COFVID_STATUS          0xC0010071
+
+/* K6 MSRs */
+#define MSR_K6_EFER                    0xC0000080
+#define MSR_K6_STAR                    0xC0000081
+#define MSR_K6_WHCR                    0xC0000082
+#define MSR_K6_UWCCR                   0xC0000085
+#define MSR_K6_PSOR                    0xC0000087
+#define MSR_K6_PFIR                    0xC0000088
+
+/* Centaur-Hauls/IDT defined MSRs. */
+#define MSR_IDT_FCR1                   0x107
+#define MSR_IDT_FCR2                   0x108
+#define MSR_IDT_FCR3                   0x109
+#define MSR_IDT_FCR4                   0x10a
+
+#define MSR_IDT_MCR0                   0x110
+#define MSR_IDT_MCR1                   0x111
+#define MSR_IDT_MCR2                   0x112
+#define MSR_IDT_MCR3                   0x113
+#define MSR_IDT_MCR4                   0x114
+#define MSR_IDT_MCR5                   0x115
+#define MSR_IDT_MCR6                   0x116
+#define MSR_IDT_MCR7                   0x117
+#define MSR_IDT_MCR_CTRL               0x120
+
+/* VIA Cyrix defined MSRs*/
+#define MSR_VIA_FCR                    0x1107
+#define MSR_VIA_LONGHAUL               0x110a
+#define MSR_VIA_RNG                    0x110b
+#define MSR_VIA_BCR2                   0x1147
+
+/* Intel defined MSRs. */
+#define MSR_IA32_P5_MC_ADDR            0
+#define MSR_IA32_P5_MC_TYPE            1
+#define MSR_IA32_PLATFORM_ID           0x17
+#define MSR_IA32_EBL_CR_POWERON                0x2a
+
+#define MSR_IA32_APICBASE               0x1b
+#define MSR_IA32_APICBASE_BSP           (1<<8)
+#define MSR_IA32_APICBASE_ENABLE        (1<<11)
+#define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+
+/* P4/Xeon+ specific */
+#define MSR_IA32_MCG_EAX               0x180
+#define MSR_IA32_MCG_EBX               0x181
+#define MSR_IA32_MCG_ECX               0x182
+#define MSR_IA32_MCG_EDX               0x183
+#define MSR_IA32_MCG_ESI               0x184
+#define MSR_IA32_MCG_EDI               0x185
+#define MSR_IA32_MCG_EBP               0x186
+#define MSR_IA32_MCG_ESP               0x187
+#define MSR_IA32_MCG_EFLAGS            0x188
+#define MSR_IA32_MCG_EIP               0x189
+#define MSR_IA32_MCG_RESERVED          0x18A
+
+#define MSR_P6_EVNTSEL0                        0x186
+#define MSR_P6_EVNTSEL1                        0x187
+
+#define MSR_IA32_PERF_STATUS           0x198
+#define MSR_IA32_PERF_CTL              0x199
+
+#define MSR_IA32_THERM_CONTROL         0x19a
+#define MSR_IA32_THERM_INTERRUPT       0x19b
+#define MSR_IA32_THERM_STATUS          0x19c
+#define MSR_IA32_MISC_ENABLE           0x1a0
+
+#define MSR_IA32_DEBUGCTLMSR           0x1d9
+#define MSR_IA32_LASTBRANCHFROMIP      0x1db
+#define MSR_IA32_LASTBRANCHTOIP                0x1dc
+#define MSR_IA32_LASTINTFROMIP         0x1dd
+#define MSR_IA32_LASTINTTOIP           0x1de
+
+#define MSR_IA32_MC0_CTL               0x400
+#define MSR_IA32_MC0_STATUS            0x401
+#define MSR_IA32_MC0_ADDR              0x402
+#define MSR_IA32_MC0_MISC              0x403
+
+/* Pentium IV performance counter MSRs */
+#define MSR_P4_BPU_PERFCTR0            0x300
+#define MSR_P4_BPU_PERFCTR1            0x301
+#define MSR_P4_BPU_PERFCTR2            0x302
+#define MSR_P4_BPU_PERFCTR3            0x303
+#define MSR_P4_MS_PERFCTR0             0x304
+#define MSR_P4_MS_PERFCTR1             0x305
+#define MSR_P4_MS_PERFCTR2             0x306
+#define MSR_P4_MS_PERFCTR3             0x307
+#define MSR_P4_FLAME_PERFCTR0          0x308
+#define MSR_P4_FLAME_PERFCTR1          0x309
+#define MSR_P4_FLAME_PERFCTR2          0x30a
+#define MSR_P4_FLAME_PERFCTR3          0x30b
+#define MSR_P4_IQ_PERFCTR0             0x30c
+#define MSR_P4_IQ_PERFCTR1             0x30d
+#define MSR_P4_IQ_PERFCTR2             0x30e
+#define MSR_P4_IQ_PERFCTR3             0x30f
+#define MSR_P4_IQ_PERFCTR4             0x310
+#define MSR_P4_IQ_PERFCTR5             0x311
+#define MSR_P4_BPU_CCCR0               0x360
+#define MSR_P4_BPU_CCCR1               0x361
+#define MSR_P4_BPU_CCCR2               0x362
+#define MSR_P4_BPU_CCCR3               0x363
+#define MSR_P4_MS_CCCR0                0x364
+#define MSR_P4_MS_CCCR1                0x365
+#define MSR_P4_MS_CCCR2                0x366
+#define MSR_P4_MS_CCCR3                0x367
+#define MSR_P4_FLAME_CCCR0             0x368
+#define MSR_P4_FLAME_CCCR1             0x369
+#define MSR_P4_FLAME_CCCR2             0x36a
+#define MSR_P4_FLAME_CCCR3             0x36b
+#define MSR_P4_IQ_CCCR0                0x36c
+#define MSR_P4_IQ_CCCR1                0x36d
+#define MSR_P4_IQ_CCCR2                0x36e
+#define MSR_P4_IQ_CCCR3                0x36f
+#define MSR_P4_IQ_CCCR4                0x370
+#define MSR_P4_IQ_CCCR5                0x371
+#define MSR_P4_ALF_ESCR0               0x3ca
+#define MSR_P4_ALF_ESCR1               0x3cb
+#define MSR_P4_BPU_ESCR0               0x3b2
+#define MSR_P4_BPU_ESCR1               0x3b3
+#define MSR_P4_BSU_ESCR0               0x3a0
+#define MSR_P4_BSU_ESCR1               0x3a1
+#define MSR_P4_CRU_ESCR0               0x3b8
+#define MSR_P4_CRU_ESCR1               0x3b9
+#define MSR_P4_CRU_ESCR2               0x3cc
+#define MSR_P4_CRU_ESCR3               0x3cd
+#define MSR_P4_CRU_ESCR4               0x3e0
+#define MSR_P4_CRU_ESCR5               0x3e1
+#define MSR_P4_DAC_ESCR0               0x3a8
+#define MSR_P4_DAC_ESCR1               0x3a9
+#define MSR_P4_FIRM_ESCR0              0x3a4
+#define MSR_P4_FIRM_ESCR1              0x3a5
+#define MSR_P4_FLAME_ESCR0             0x3a6
+#define MSR_P4_FLAME_ESCR1             0x3a7
+#define MSR_P4_FSB_ESCR0               0x3a2
+#define MSR_P4_FSB_ESCR1               0x3a3
+#define MSR_P4_IQ_ESCR0                0x3ba
+#define MSR_P4_IQ_ESCR1                0x3bb
+#define MSR_P4_IS_ESCR0                0x3b4
+#define MSR_P4_IS_ESCR1                0x3b5
+#define MSR_P4_ITLB_ESCR0              0x3b6
+#define MSR_P4_ITLB_ESCR1              0x3b7
+#define MSR_P4_IX_ESCR0                0x3c8
+#define MSR_P4_IX_ESCR1                0x3c9
+#define MSR_P4_MOB_ESCR0               0x3aa
+#define MSR_P4_MOB_ESCR1               0x3ab
+#define MSR_P4_MS_ESCR0                0x3c0
+#define MSR_P4_MS_ESCR1                0x3c1
+#define MSR_P4_PMH_ESCR0               0x3ac
+#define MSR_P4_PMH_ESCR1               0x3ad
+#define MSR_P4_RAT_ESCR0               0x3bc
+#define MSR_P4_RAT_ESCR1               0x3bd
+#define MSR_P4_SAAT_ESCR0              0x3ae
+#define MSR_P4_SAAT_ESCR1              0x3af
+#define MSR_P4_SSU_ESCR0               0x3be
+#define MSR_P4_SSU_ESCR1               0x3bf    /* guess: not defined in manual */
+#define MSR_P4_TBPU_ESCR0              0x3c2
+#define MSR_P4_TBPU_ESCR1              0x3c3
+#define MSR_P4_TC_ESCR0                0x3c4
+#define MSR_P4_TC_ESCR1                0x3c5
+#define MSR_P4_U2L_ESCR0               0x3b0
+#define MSR_P4_U2L_ESCR1               0x3b1
+
+#endif
diff --git a/kitten/include/arch-x86_64/page.h b/kitten/include/arch-x86_64/page.h
new file mode 100644 (file)
index 0000000..eac69c5
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef _X86_64_PAGE_H
+#define _X86_64_PAGE_H
+
+#include <lwk/const.h>
+
+/**
+ * Define the base page size, 4096K on x86_64.
+ * PAGE_SHIFT defines the base page size.
+ */
+#define PAGE_SHIFT             12
+#define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_MASK              (~(PAGE_SIZE-1))
+#define PHYSICAL_PAGE_MASK     (~(PAGE_SIZE-1) & __PHYSICAL_MASK)
+
+/**
+ * The kernel is mapped into the virtual address space of every task:
+ *
+ *     [PAGE_OFFSET, TOP_OF_MEMORY)  Kernel-space virtual memory region
+ *     [0, PAGE_OFFSET]              User-space virtual memory region
+ */
+#define PAGE_OFFSET            _AC(0xffff810000000000, UL)
+
+/**
+ * The bootloader loads the LWK at address __PHYSICAL_START in physical memory.
+ * This must be aligned on a 2 MB page boundary... or else.
+ */
+#define __PHYSICAL_START       CONFIG_PHYSICAL_START
+#define __KERNEL_ALIGN         0x200000
+
+/**
+ * If you hit this error when compiling the LWK, change your config file so that
+ * CONFIG_PHYSICAL_START is aligned to a 2 MB boundary.
+ */
+#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0
+#error "CONFIG_PHYSICAL_START must be a multiple of 2MB"
+#endif
+
+/**
+ * The kernel page tables map the kernel image text and data starting at
+ * virtual address __START_KERNEL_map. The kernel text starts at
+ * __START_KERNEL.
+ */
+#define __START_KERNEL_map     _AC(0xffffffff80000000, UL)
+#define __START_KERNEL         (__START_KERNEL_map + __PHYSICAL_START)
+
+/* See Documentation/x86_64/mm.txt for a description of the memory map. */
+#define __PHYSICAL_MASK_SHIFT   46
+#define __PHYSICAL_MASK     ((_AC(1,UL) << __PHYSICAL_MASK_SHIFT) - 1)
+#define __VIRTUAL_MASK_SHIFT    48
+#define __VIRTUAL_MASK      ((_AC(1,UL) << __VIRTUAL_MASK_SHIFT) - 1)
+
+#define TASK_ORDER 1 
+#define TASK_SIZE  (PAGE_SIZE << TASK_ORDER)
+#define CURRENT_MASK (~(TASK_SIZE-1))
+
+#define EXCEPTION_STACK_ORDER 0
+#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
+
+#define DEBUG_STACK_ORDER EXCEPTION_STACK_ORDER
+#define DEBUG_STKSZ (PAGE_SIZE << DEBUG_STACK_ORDER)
+
+#define IRQSTACK_ORDER 2
+#define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER)
+
+#define STACKFAULT_STACK       1
+#define DOUBLEFAULT_STACK      2
+#define NMI_STACK              3
+#define DEBUG_STACK            4
+#define MCE_STACK              5
+#define N_EXCEPTION_STACKS     5       /* hw limit is 7 */
+
+/**
+ * Macros for converting between physical address and kernel virtual address.
+ * NOTE: These only work for kernel virtual addresses in the identity map.
+ */
+#ifndef __ASSEMBLY__
+extern unsigned long __phys_addr(unsigned long virt_addr);
+#endif
+#define __pa(x)                __phys_addr((unsigned long)(x))
+#define __pa_symbol(x) __phys_addr((unsigned long)(x))
+#define __va(x)                ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define __boot_va(x)   __va(x)
+#define __boot_pa(x)   __pa(x)
+
+#ifndef __ASSEMBLY__
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pud; } pud_t;
+typedef struct { unsigned long pgd; } pgd_t;
+#define PTE_MASK    PHYSICAL_PAGE_MASK
+
+
+extern pud_t level3_kernel_pgt[512];
+extern pud_t level3_physmem_pgt[512];
+extern pud_t level3_ident_pgt[512];
+extern pmd_t level2_kernel_pgt[512];
+extern pgd_t init_level4_pgt[];
+extern pgd_t boot_level4_pgt[];
+
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+extern unsigned long end_pfn;
+
+#endif
+
+#define PTRS_PER_PGD   512
+#define KERNEL_TEXT_SIZE (40*1024*1024)
+
+#define pte_val(x)  ((x).pte)
+#define pmd_val(x)  ((x).pmd)
+#define pud_val(x)  ((x).pud)
+#define pgd_val(x)  ((x).pgd)
+#define pgprot_val(x)   ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pud(x) ((pud_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+#define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT)
+
+#endif
diff --git a/kitten/include/arch-x86_64/page_table.h b/kitten/include/arch-x86_64/page_table.h
new file mode 100644 (file)
index 0000000..0751c9a
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef _ARCH_X86_64_PAGE_TABLE_H
+#define _ARCH_X86_64_PAGE_TABLE_H
+
+typedef struct {
+       uint64_t
+               present    :1,  /* Is there a physical page? */
+               write      :1,  /* Is the page writable? */
+               user       :1,  /* Is the page accessible to user-space? */
+               pwt        :1,  /* Is the page write-through cached? */
+               pcd        :1,  /* Is the page uncached? */
+               accessed   :1,  /* Has the page been read? */
+               dirty      :1,  /* Has the page been written to? */
+               pagesize   :1,  /* 0 == 4KB, 1 == (2 MB || 1 GB) */
+               global     :1,  /* Is the page mapped in all address spaces? */
+               os_bits_1  :3,  /* Available for us! */
+               base_paddr :40, /* Bits [51,12] of base address. */
+               os_bits_2  :11, /* Available for us! */
+               no_exec    :1;  /* Is the page executable? */
+} xpte_t;
+
+typedef struct {
+       uint64_t
+               present    :1,  /* Is there a physical page? */
+               write      :1,  /* Is the page writable? */
+               user       :1,  /* Is the page accessible to user-space? */
+               pwt        :1,  /* Is the page write-through cached? */
+               pcd        :1,  /* Is the page uncached? */
+               accessed   :1,  /* Has the page been read? */
+               dirty      :1,  /* Has the page been written to? */
+               pat        :1,  /* Page attribute table bit. */
+               global     :1,  /* Is the page mapped in all address spaces? */
+               os_bits_1  :3,  /* Available for us! */
+               base_paddr :40, /* Bits [51,12] of page's base physical addr. */
+               os_bits_2  :11, /* Available for us! */
+               no_exec    :1;  /* Is the page executable? */
+} xpte_4KB_t;
+
+typedef struct {
+       uint64_t
+               present    :1,  /* Is there a physical page? */
+               write      :1,  /* Is the page writable? */
+               user       :1,  /* Is the page accessible to user-space? */
+               pwt        :1,  /* Is the page write-through cached? */
+               pcd        :1,  /* Is the page uncached? */
+               accessed   :1,  /* Has the page been read? */
+               dirty      :1,  /* Has the page been written to? */
+               must_be_1  :1,  /* Must be 1 to indicate a 2 MB page. */
+               global     :1,  /* Is the page mapped in all address spaces? */
+               os_bits_1  :3,  /* Available for us! */
+               pat        :1,  /* Page attribute table bit. */
+               must_be_0  :8,  /* Reserved, must be zero. */
+               base_paddr :31, /* Bits [51,21] of page's base physical addr. */
+               os_bits_2  :11, /* Available for us! */
+               no_exec    :1;  /* Is the page executable? */
+} xpte_2MB_t;
+
+typedef struct {
+       uint64_t
+               present    :1,  /* Is there a physical page? */
+               write      :1,  /* Is the page writable? */
+               user       :1,  /* Is the page accessible to user-space? */
+               pwt        :1,  /* Is the page write-through cached? */
+               pcd        :1,  /* Is the page uncached? */
+               accessed   :1,  /* Has the page been read? */
+               dirty      :1,  /* Has the page been written to? */
+               must_be_1  :1,  /* Must be 1 to indicate a 1GB page. */
+               global     :1,  /* Is the page mapped in all address spaces? */
+               os_bits_1  :3,  /* Available for us! */
+               pat        :1,  /* Page attribute table bit. */
+               must_be_0  :17, /* Reserved, must be zero. */
+               base_paddr :22, /* Bits [51,30] of page's base physical addr. */
+               os_bits_2  :11, /* Available for us! */
+               no_exec    :1;  /* Is the page executable? */
+} xpte_1GB_t;
+
+#endif
diff --git a/kitten/include/arch-x86_64/param.h b/kitten/include/arch-x86_64/param.h
new file mode 100644 (file)
index 0000000..58a3d76
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ASMx86_64_PARAM_H
+#define _ASMx86_64_PARAM_H
+
+#ifdef __KERNEL__
+# define USER_HZ       100             /* .. some user interfaces are in "ticks */
+#define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
+#endif
+
+#define EXEC_PAGESIZE  4096
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#endif
diff --git a/kitten/include/arch-x86_64/pda.h b/kitten/include/arch-x86_64/pda.h
new file mode 100644 (file)
index 0000000..73f5f55
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef _X86_64_PDA_H
+#define _X86_64_PDA_H
+
+#ifndef __ASSEMBLY__
+#include <lwk/stddef.h>
+#include <lwk/types.h>
+#include <lwk/cache.h>
+#include <arch/page.h>
+
+/* Per processor datastructure. %gs points to it while the kernel runs */ 
+struct x8664_pda {
+       struct task_struct *pcurrent;   /* Current process */
+       unsigned long data_offset;      /* Per cpu data offset from linker address */
+       unsigned long kernelstack;  /* top of kernel stack for current */ 
+       unsigned long oldrsp;       /* user rsp for system call */
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+       unsigned long debugstack;   /* #DB/#BP stack. */
+#endif
+        int irqcount;              /* Irq nesting counter. Starts with -1 */   
+       int cpunumber;              /* Logical CPU number */
+       char *irqstackptr;      /* top of irqstack */
+       int nodenumber;             /* number of current node */
+       unsigned int __softirq_pending;
+       unsigned int __nmi_count;       /* number of NMI on this CPUs */
+       int mmu_state;     
+       struct aspace *active_aspace;
+       unsigned apic_timer_irqs;
+} ____cacheline_aligned_in_smp;
+
+extern struct x8664_pda *_cpu_pda[];
+extern struct x8664_pda boot_cpu_pda[];
+
+void pda_init(unsigned int cpu, struct task_struct *task);
+
+#define cpu_pda(i) (_cpu_pda[i])
+
+/* 
+ * There is no fast way to get the base address of the PDA, all the accesses
+ * have to mention %fs/%gs.  So it needs to be done this Torvaldian way.
+ */ 
+#define sizeof_field(type,field)  (sizeof(((type *)0)->field))
+#define typeof_field(type,field)  typeof(((type *)0)->field)
+
+extern void __bad_pda_field(void);
+
+#define pda_offset(field) offsetof(struct x8664_pda, field)
+
+#define pda_to_op(op,field,val) do { \
+       typedef typeof_field(struct x8664_pda, field) T__; \
+       switch (sizeof_field(struct x8664_pda, field)) {                \
+case 2: \
+asm volatile(op "w %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
+case 4: \
+asm volatile(op "l %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
+case 8: \
+asm volatile(op "q %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
+       default: __bad_pda_field();                                     \
+       } \
+       } while (0)
+
+/* 
+ * AK: PDA read accesses should be neither volatile nor have an memory clobber.
+ * Unfortunately removing them causes all hell to break lose currently.
+ */
+#define pda_from_op(op,field) ({ \
+       typeof_field(struct x8664_pda, field) ret__; \
+       switch (sizeof_field(struct x8664_pda, field)) {                \
+case 2: \
+asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
+case 4: \
+asm volatile(op "l %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
+case 8: \
+asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
+       default: __bad_pda_field();                                     \
+       } \
+       ret__; })
+
+
+#define read_pda(field) pda_from_op("mov",field)
+#define write_pda(field,val) pda_to_op("mov",field,val)
+#define add_pda(field,val) pda_to_op("add",field,val)
+#define sub_pda(field,val) pda_to_op("sub",field,val)
+#define or_pda(field,val) pda_to_op("or",field,val)
+
+#endif
+
+#define PDA_STACKOFFSET (5*8)
+
+#endif
diff --git a/kitten/include/arch-x86_64/percpu.h b/kitten/include/arch-x86_64/percpu.h
new file mode 100644 (file)
index 0000000..56de2d6
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _X86_64_PERCPU_H
+#define _X86_64_PERCPU_H
+#include <lwk/compiler.h>
+
+/* Same as asm-generic/percpu.h, except that we store the per cpu offset
+   in the PDA. Longer term the PDA and every per cpu variable
+   should be just put into a single section and referenced directly
+   from %gs */
+
+#include <arch/pda.h>
+
+#define __per_cpu_offset(cpu) (cpu_pda(cpu)->data_offset)
+#define __my_cpu_offset() read_pda(data_offset)
+
+/* Separate out the type, so (int[3], foo) works. */
+#define DEFINE_PER_CPU(type, name) \
+    __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+
+/* var is in discarded region: offset to particular copy we want */
+#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
+#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+
+#endif /* _X86_64_PERCPU_H */
diff --git a/kitten/include/arch-x86_64/pgtable.h b/kitten/include/arch-x86_64/pgtable.h
new file mode 100644 (file)
index 0000000..ec03f44
--- /dev/null
@@ -0,0 +1,445 @@
+#ifndef _X86_64_PGTABLE_H
+#define _X86_64_PGTABLE_H
+
+#include <lwk/const.h>
+#ifndef __ASSEMBLY__
+
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the x86-64 page table tree.
+ */
+#include <lwk/spinlock.h>
+#include <arch/fixmap.h>
+#include <arch/processor.h>
+#include <arch/bitops.h>
+#include <arch/pda.h>
+
+extern pud_t level3_kernel_pgt[512];
+extern pud_t level3_ident_pgt[512];
+extern pmd_t level2_kernel_pgt[512];
+extern pgd_t init_level4_pgt[];
+extern unsigned long __supported_pte_mask;
+
+#define swapper_pg_dir init_level4_pgt
+
+extern void paging_init(void);
+extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * PGDIR_SHIFT determines what a top-level page table entry can map
+ */
+#define PGDIR_SHIFT    39
+#define PTRS_PER_PGD   512
+
+/*
+ * 3rd level page
+ */
+#define PUD_SHIFT      30
+#define PTRS_PER_PUD   512
+
+/*
+ * PMD_SHIFT determines the size of the area a middle-level
+ * page table can map
+ */
+#define PMD_SHIFT      21
+#define PTRS_PER_PMD   512
+
+/*
+ * entries per page directory level
+ */
+#define PTRS_PER_PTE   512
+
+#ifndef __ASSEMBLY__
+
+#define pte_ERROR(e) \
+       printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
+#define pmd_ERROR(e) \
+       printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), pmd_val(e))
+#define pud_ERROR(e) \
+       printk("%s:%d: bad pud %p(%016lx).\n", __FILE__, __LINE__, &(e), pud_val(e))
+#define pgd_ERROR(e) \
+       printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
+
+#define pgd_none(x)    (!pgd_val(x))
+#define pud_none(x)    (!pud_val(x))
+
+static inline void set_pte(pte_t *dst, pte_t val)
+{
+       pte_val(*dst) = pte_val(val);
+} 
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+static inline void set_pmd(pmd_t *dst, pmd_t val)
+{
+        pmd_val(*dst) = pmd_val(val); 
+} 
+
+static inline void set_pud(pud_t *dst, pud_t val)
+{
+       pud_val(*dst) = pud_val(val);
+}
+
+static inline void pud_clear (pud_t *pud)
+{
+       set_pud(pud, __pud(0));
+}
+
+static inline void set_pgd(pgd_t *dst, pgd_t val)
+{
+       pgd_val(*dst) = pgd_val(val); 
+} 
+
+static inline void pgd_clear (pgd_t * pgd)
+{
+       set_pgd(pgd, __pgd(0));
+}
+
+#define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte, 0))
+
+struct mm_struct;
+
+static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
+{
+       pte_t pte;
+       if (full) {
+               pte = *ptep;
+               *ptep = __pte(0);
+       } else {
+               pte = ptep_get_and_clear(mm, addr, ptep);
+       }
+       return pte;
+}
+
+#define pte_same(a, b)         ((a).pte == (b).pte)
+
+#define pte_pgprot(a)  (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK))
+
+#endif /* !__ASSEMBLY__ */
+
+#define PMD_SIZE       (_AC(1,UL) << PMD_SHIFT)
+#define PMD_MASK       (~(PMD_SIZE-1))
+#define PUD_SIZE       (_AC(1,UL) << PUD_SHIFT)
+#define PUD_MASK       (~(PUD_SIZE-1))
+#define PGDIR_SIZE     (_AC(1,UL) << PGDIR_SHIFT)
+#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+
+#define USER_PTRS_PER_PGD      ((TASK_SIZE-1)/PGDIR_SIZE+1)
+#define FIRST_USER_ADDRESS     0
+
+#define MAXMEM          _AC(0x3fffffffffff, UL)
+#define VMALLOC_START    _AC(0xffffc20000000000, UL)
+#define VMALLOC_END      _AC(0xffffe1ffffffffff, UL)
+#define MODULES_VADDR    _AC(0xffffffff88000000, UL)
+#define MODULES_END      _AC(0xfffffffffff00000, UL)
+#define MODULES_LEN   (MODULES_END - MODULES_VADDR)
+
+#define _PAGE_BIT_PRESENT      0
+#define _PAGE_BIT_RW           1
+#define _PAGE_BIT_USER         2
+#define _PAGE_BIT_PWT          3
+#define _PAGE_BIT_PCD          4
+#define _PAGE_BIT_ACCESSED     5
+#define _PAGE_BIT_DIRTY                6
+#define _PAGE_BIT_PSE          7       /* 4 MB (or 2MB) page */
+#define _PAGE_BIT_GLOBAL       8       /* Global TLB entry PPro+ */
+#define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
+
+#define _PAGE_PRESENT  0x001
+#define _PAGE_RW       0x002
+#define _PAGE_USER     0x004
+#define _PAGE_PWT      0x008
+#define _PAGE_PCD      0x010
+#define _PAGE_ACCESSED 0x020
+#define _PAGE_DIRTY    0x040
+#define _PAGE_PSE      0x080   /* 2MB page */
+#define _PAGE_FILE     0x040   /* nonlinear file mapping, saved PTE; unset:swap */
+#define _PAGE_GLOBAL   0x100   /* Global TLB entry */
+
+#define _PAGE_PROTNONE 0x080   /* If not present */
+#define _PAGE_NX        (_AC(1,UL)<<_PAGE_BIT_NX)
+
+#define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE      __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_COPY PAGE_COPY_NOEXEC
+#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define __PAGE_KERNEL \
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+#define __PAGE_KERNEL_EXEC \
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_NOCACHE \
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX)
+#define __PAGE_KERNEL_RO \
+       (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+#define __PAGE_KERNEL_VSYSCALL \
+       (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_VSYSCALL_NOCACHE \
+       (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PCD)
+#define __PAGE_KERNEL_LARGE \
+       (__PAGE_KERNEL | _PAGE_PSE)
+#define __PAGE_KERNEL_LARGE_EXEC \
+       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
+
+#define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
+
+#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
+#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC)
+#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
+#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
+#define PAGE_KERNEL_VSYSCALL32 __pgprot(__PAGE_KERNEL_VSYSCALL)
+#define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
+#define PAGE_KERNEL_LARGE MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
+#define PAGE_KERNEL_VSYSCALL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL_NOCACHE)
+
+/*         xwr */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY_EXEC
+#define __P101 PAGE_READONLY_EXEC
+#define __P110 PAGE_COPY_EXEC
+#define __P111 PAGE_COPY_EXEC
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY_EXEC
+#define __S101 PAGE_READONLY_EXEC
+#define __S110 PAGE_SHARED_EXEC
+#define __S111 PAGE_SHARED_EXEC
+
+#ifndef __ASSEMBLY__
+
+static inline unsigned long pgd_bad(pgd_t pgd)
+{
+       return pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
+}
+
+static inline unsigned long pud_bad(pud_t pud)
+{
+       return pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
+}
+
+static inline unsigned long pmd_bad(pmd_t pmd)
+{
+       return pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
+}
+
+#define pte_none(x)    (!pte_val(x))
+#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+#define pte_clear(mm,addr,xp)  do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
+
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))        /* FIXME: is this
+                                                  right? */
+#define pte_page(x)    pfn_to_page(pte_pfn(x))
+#define pte_pfn(x)  ((pte_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
+
+static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
+{
+       pte_t pte;
+       pte_val(pte) = (page_nr << PAGE_SHIFT);
+       pte_val(pte) |= pgprot_val(pgprot);
+       pte_val(pte) &= __supported_pte_mask;
+       return pte;
+}
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
+static inline int pte_user(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_read(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_exec(pte_t pte)          { return !(pte_val(pte) & _PAGE_NX); }
+static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_huge(pte_t pte)          { return pte_val(pte) & _PAGE_PSE; }
+
+static inline pte_t pte_rdprotect(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
+static inline pte_t pte_exprotect(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
+static inline pte_t pte_mkclean(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
+static inline pte_t pte_mkold(pte_t pte)       { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
+static inline pte_t pte_wrprotect(pte_t pte)   { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; }
+static inline pte_t pte_mkread(pte_t pte)      { set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
+static inline pte_t pte_mkexec(pte_t pte)      { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_NX)); return pte; }
+static inline pte_t pte_mkdirty(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
+static inline pte_t pte_mkyoung(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
+static inline pte_t pte_mkwrite(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
+static inline pte_t pte_mkhuge(pte_t pte)      { set_pte(&pte, __pte(pte_val(pte) | _PAGE_PSE)); return pte; }
+static inline pte_t pte_clrhuge(pte_t pte)     { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_PSE)); return pte; }
+
+struct vm_area_struct;
+
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+       if (!pte_dirty(*ptep))
+               return 0;
+       return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte);
+}
+
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+       if (!pte_young(*ptep))
+               return 0;
+       return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte);
+}
+
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       clear_bit(_PAGE_BIT_RW, &ptep->pte);
+}
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT))
+
+static inline int pmd_large(pmd_t pte) { 
+       return (pmd_val(pte) & __LARGE_PTE) == __LARGE_PTE; 
+}      
+
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+/*
+ * Level 4 access.
+ */
+#define pgd_page_vaddr(pgd) ((unsigned long) __va((unsigned long)pgd_val(pgd) & PTE_MASK))
+#define pgd_page(pgd)          (pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
+#define pgd_offset_k(address) (init_level4_pgt + pgd_index(address))
+#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT)
+#define mk_kernel_pgd(address) ((pgd_t){ (address) | _KERNPG_TABLE })
+
+/* PUD - Level3 access */
+/* to find an entry in a page-table-directory. */
+#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK))
+#define pud_page(pud)          (pfn_to_page(pud_val(pud) >> PAGE_SHIFT))
+#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
+#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address))
+#define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
+
+/* PMD  - Level 2 access */
+#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
+#define pmd_page(pmd)          (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+
+#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+#define pmd_offset(dir, address) ((pmd_t *) pud_page_vaddr(*(dir)) + \
+                       pmd_index(address))
+#define pmd_none(x)    (!pmd_val(x))
+#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
+#define pmd_clear(xp)  do { set_pmd(xp, __pmd(0)); } while (0)
+#define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
+#define pmd_pfn(x)  ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
+
+#define pte_to_pgoff(pte) ((pte_val(pte) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
+#define pgoff_to_pte(off) ((pte_t) { ((off) << PAGE_SHIFT) | _PAGE_FILE })
+#define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT
+
+/* PTE - Level 1 access. */
+
+/* page, protection -> pte */
+#define mk_pte(page, pgprot)   pfn_pte(page_to_pfn(page), (pgprot))
+#define mk_pte_huge(entry) (pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE)
+/* Change flags of a PTE */
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ 
+       pte_val(pte) &= _PAGE_CHG_MASK;
+       pte_val(pte) |= pgprot_val(newprot);
+       pte_val(pte) &= __supported_pte_mask;
+       return pte; 
+}
+
+#define pte_index(address) \
+               (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + \
+                       pte_index(address))
+
+/* x86-64 always has all page tables mapped. */
+#define pte_offset_map(dir,address) pte_offset_kernel(dir,address)
+#define pte_offset_map_nested(dir,address) pte_offset_kernel(dir,address)
+#define pte_unmap(pte) /* NOP */
+#define pte_unmap_nested(pte) /* NOP */ 
+
+#define update_mmu_cache(vma,address,pte) do { } while (0)
+
+/* We only update the dirty/accessed state if we set
+ * the dirty bit by hand in the kernel, since the hardware
+ * will do the accessed bit for us, and we don't want to
+ * race with other CPU's that might be updating the dirty
+ * bit at the same time. */
+#define  __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+({                                                                       \
+       int __changed = !pte_same(*(__ptep), __entry);                    \
+       if (__changed && __dirty) {                                       \
+               set_pte(__ptep, __entry);                                 \
+               flush_tlb_page(__vma, __address);                         \
+       }                                                                 \
+       __changed;                                                        \
+})
+
+/* Encode and de-code a swap entry */
+#define __swp_type(x)                  (((x).val >> 1) & 0x3f)
+#define __swp_offset(x)                        ((x).val >> 8)
+#define __swp_entry(type, offset)      ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define __pte_to_swp_entry(pte)                ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)          ((pte_t) { (x).val })
+
+extern spinlock_t pgd_lock;
+extern struct list_head pgd_list;
+
+extern int kern_addr_valid(unsigned long addr); 
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
+               remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+#define HAVE_ARCH_UNMAPPED_AREA
+
+#define pgtable_cache_init()   do { } while (0)
+#define check_pgt_cache()      do { } while (0)
+
+#define PAGE_AGP    PAGE_KERNEL_NOCACHE
+#define HAVE_PAGE_AGP 1
+
+/* fs/proc/kcore.c */
+#define        kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK)
+#define        kc_offset_to_vaddr(o) \
+   (((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o))
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+#define __HAVE_ARCH_PTE_SAME
+#include <arch-generic/pgtable.h>
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _X86_64_PGTABLE_H */
diff --git a/kitten/include/arch-x86_64/posix_types.h b/kitten/include/arch-x86_64/posix_types.h
new file mode 100644 (file)
index 0000000..d39fade
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef _X86_64_POSIX_TYPES_H
+#define _X86_64_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned long  __kernel_ino_t;
+typedef unsigned int   __kernel_mode_t;
+typedef unsigned long  __kernel_nlink_t;
+typedef long           __kernel_off_t;
+typedef int            __kernel_pid_t;
+typedef int            __kernel_ipc_pid_t;
+typedef unsigned int   __kernel_uid_t;
+typedef unsigned int   __kernel_gid_t;
+typedef unsigned long  __kernel_size_t;
+typedef long           __kernel_ssize_t;
+typedef long           __kernel_ptrdiff_t;
+typedef unsigned long  __kernel_uintptr_t;
+typedef long           __kernel_time_t;
+typedef long           __kernel_suseconds_t;
+typedef long           __kernel_clock_t;
+typedef int            __kernel_timer_t;
+typedef int            __kernel_clockid_t;
+typedef int            __kernel_daddr_t;
+typedef char *         __kernel_caddr_t;
+typedef long long      __kernel_loff_t;
+
+typedef struct {
+       int     val[2];
+} __kernel_fsid_t;
+
+#ifdef __KERNEL__
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+       unsigned long _tmp = fd / __NFDBITS;
+       unsigned long _rem = fd % __NFDBITS;
+       fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+       unsigned long _tmp = fd / __NFDBITS;
+       unsigned long _rem = fd % __NFDBITS;
+       fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p)
+{
+       unsigned long _tmp = fd / __NFDBITS;
+       unsigned long _rem = fd % __NFDBITS;
+       return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant cases (8 or 32 longs,
+ * for 256 and 1024-bit fd_sets respectively)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *p)
+{
+       unsigned long *tmp = p->fds_bits;
+       int i;
+
+       if (__builtin_constant_p(__FDSET_LONGS)) {
+               switch (__FDSET_LONGS) {
+                       case 32:
+                         tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+                         tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+                         tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+                         tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+                         tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0;
+                         tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0;
+                         tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0;
+                         tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0;
+                         return;
+                       case 16:
+                         tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+                         tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+                         tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+                         tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+                         return;
+                       case 8:
+                         tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+                         tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+                         return;
+                       case 4:
+                         tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+                         return;
+               }
+       }
+       i = __FDSET_LONGS;
+       while (i) {
+               i--;
+               *tmp = 0;
+               tmp++;
+       }
+}
+
+#endif /* defined(__KERNEL__) */
+
+#endif
diff --git a/kitten/include/arch-x86_64/prctl.h b/kitten/include/arch-x86_64/prctl.h
new file mode 100644 (file)
index 0000000..52952ad
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef X86_64_PRCTL_H
+#define X86_64_PRCTL_H 1
+
+#define ARCH_SET_GS 0x1001
+#define ARCH_SET_FS 0x1002
+#define ARCH_GET_FS 0x1003
+#define ARCH_GET_GS 0x1004
+
+
+#endif
diff --git a/kitten/include/arch-x86_64/processor.h b/kitten/include/arch-x86_64/processor.h
new file mode 100644 (file)
index 0000000..e75dec0
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * include/asm-x86_64/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+#ifndef _X86_64_PROCESSOR_H
+#define _X86_64_PROCESSOR_H
+
+#include <arch/segment.h>
+#include <arch/page.h>
+#include <arch/types.h>
+#include <arch/sigcontext.h>
+#include <arch/cpufeature.h>
+/* #include <linux/threads.h> */
+#include <arch/msr.h>
+#include <arch/current.h>
+#include <arch/system.h>
+/* #include <arch/mmsegment.h> */
+#include <arch/percpu.h>
+/* #include <lwk/personality.h> */
+#include <lwk/cpumask.h>
+#include <lwk/cache.h>
+
+#define TF_MASK                0x00000100
+#define IF_MASK                0x00000200
+#define IOPL_MASK      0x00003000
+#define NT_MASK                0x00004000
+#define VM_MASK                0x00020000
+#define AC_MASK                0x00040000
+#define VIF_MASK       0x00080000      /* virtual interrupt flag */
+#define VIP_MASK       0x00100000      /* virtual interrupt pending */
+#define ID_MASK                0x00200000
+
+#define desc_empty(desc) \
+               (!((desc)->a | (desc)->b))
+
+#define desc_equal(desc1, desc2) \
+               (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ void *pc; asm volatile("leaq 1f(%%rip),%0\n1:":"=r"(pc)); pc; })
+
+#define X86_VENDOR_INTEL 0
+#define X86_VENDOR_CYRIX 1
+#define X86_VENDOR_AMD 2
+#define X86_VENDOR_UMC 3
+#define X86_VENDOR_NEXGEN 4
+#define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_RISE 6
+#define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_NUM 8
+#define X86_VENDOR_UNKNOWN 0xff
+
+extern char ignore_irq13;
+
+extern void identify_cpu(void);
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF  0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF  0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF  0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF  0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF  0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF  0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF  0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF  0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF  0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL        0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT  0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF  0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM  0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC  0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID  0x00200000 /* CPUID detection flag */
+
+/*
+ * Intel CPU features in CR4
+ */
+#define X86_CR4_VME            0x0001  /* enable vm86 extensions */
+#define X86_CR4_PVI            0x0002  /* virtual interrupts flag enable */
+#define X86_CR4_TSD            0x0004  /* disable time stamp at ipl 3 */
+#define X86_CR4_DE             0x0008  /* enable debugging extensions */
+#define X86_CR4_PSE            0x0010  /* enable page size extensions */
+#define X86_CR4_PAE            0x0020  /* enable physical address extensions */
+#define X86_CR4_MCE            0x0040  /* Machine check enable */
+#define X86_CR4_PGE            0x0080  /* enable global pages */
+#define X86_CR4_PCE            0x0100  /* enable performance counters at ipl 3 */
+#define X86_CR4_OSFXSR         0x0200  /* enable fast FPU save and restore */
+#define X86_CR4_OSXMMEXCPT     0x0400  /* enable unmasked SSE exceptions */
+
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+extern unsigned long mmu_cr4_features;
+
+static inline void set_in_cr4 (unsigned long mask)
+{
+       mmu_cr4_features |= mask;
+       __asm__("movq %%cr4,%%rax\n\t"
+               "orq %0,%%rax\n\t"
+               "movq %%rax,%%cr4\n"
+               : : "irg" (mask)
+               :"ax");
+}
+
+static inline void clear_in_cr4 (unsigned long mask)
+{
+       mmu_cr4_features &= ~mask;
+       __asm__("movq %%cr4,%%rax\n\t"
+               "andq %0,%%rax\n\t"
+               "movq %%rax,%%cr4\n"
+               : : "irg" (~mask)
+               :"ax");
+}
+
+
+/*
+ * Size of io_bitmap.
+ */
+#define IO_BITMAP_BITS  65536
+#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8)
+#define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long))
+#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
+#define INVALID_IO_BITMAP_OFFSET 0x8000
+
+struct i387_fxsave_struct {
+       u16     cwd;
+       u16     swd;
+       u16     twd;
+       u16     fop;
+       u64     rip;
+       u64     rdp; 
+       u32     mxcsr;
+       u32     mxcsr_mask;
+       u32     st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
+       u32     xmm_space[64];  /* 16*16 bytes for each XMM-reg = 256 bytes */
+       u32     padding[24];
+} __attribute__ ((aligned (16)));
+
+union i387_union {
+       struct i387_fxsave_struct       fxsave;
+};
+
+struct tss_struct {
+       u32 reserved1;
+       u64 rsp0;       
+       u64 rsp1;
+       u64 rsp2;
+       u64 reserved2;
+       u64 ist[7];
+       u32 reserved3;
+       u32 reserved4;
+       u16 reserved5;
+       u16 io_bitmap_base;
+       /*
+        * The extra 1 is there because the CPU will access an
+        * additional byte beyond the end of the IO permission
+        * bitmap. The extra byte must be all 1 bits, and must
+        * be within the limit. Thus we have:
+        *
+        * 128 bytes, the bitmap itself, for ports 0..0x3ff
+        * 8 bytes, for an extra "long" of ~0UL
+        */
+       unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
+} __attribute__((packed)) ____cacheline_aligned;
+
+DECLARE_PER_CPU(struct tss_struct,tss);
+
+#ifdef CONFIG_X86_VSMP
+#define ARCH_MIN_TASKALIGN     (1 << INTERNODE_CACHE_SHIFT)
+#define ARCH_MIN_MMSTRUCT_ALIGN        (1 << INTERNODE_CACHE_SHIFT)
+#else
+#define ARCH_MIN_TASKALIGN     16
+#define ARCH_MIN_MMSTRUCT_ALIGN        0
+#endif
+
+struct thread_struct {
+       unsigned long   rsp0;
+       unsigned long   rsp;
+       unsigned long   userrsp;        /* Copy from PDA */ 
+       unsigned long   fs;
+       unsigned long   gs;
+       unsigned short  es, ds, fsindex, gsindex;       
+/* Hardware debugging registers */
+       unsigned long   debugreg0;  
+       unsigned long   debugreg1;  
+       unsigned long   debugreg2;  
+       unsigned long   debugreg3;  
+       unsigned long   debugreg6;  
+       unsigned long   debugreg7;  
+/* fault info */
+       unsigned long   cr2, trap_no, error_code;
+/* floating point info */
+       union i387_union        i387  __attribute__((aligned(16)));
+/* IO permissions. the bitmap could be moved into the GDT, that would make
+   switch faster for a limited number of ioperm using tasks. -AK */
+       int             ioperm;
+       unsigned long   *io_bitmap_ptr;
+       unsigned io_bitmap_max;
+/* cached TLS descriptors. */
+       u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
+} __attribute__((aligned(16)));
+
+#define BOOTSTRAP_THREAD  { \
+       .rsp0 = (unsigned long)&bootstrap_stack + sizeof(bootstrap_stack) \
+}
+
+#define BOOTSTRAP_TSS  { \
+       .rsp0 = (unsigned long)&bootstrap_stack + sizeof(bootstrap_stack) \
+}
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+
+#define start_thread(regs,new_rip,new_rsp) do { \
+       asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0));      \
+       load_gs_index(0);                                                       \
+       (regs)->rip = (new_rip);                                                 \
+       (regs)->rsp = (new_rsp);                                                 \
+       write_pda(oldrsp, (new_rsp));                                            \
+       (regs)->cs = __USER_CS;                                                  \
+       (regs)->ss = __USER_DS;                                                  \
+       (regs)->eflags = 0x200;                                                  \
+       set_fs(USER_DS);                                                         \
+} while(0) 
+
+#define get_debugreg(var, register)                            \
+               __asm__("movq %%db" #register ", %0"            \
+                       :"=r" (var))
+#define set_debugreg(value, register)                  \
+               __asm__("movq %0,%%db" #register                \
+                       : /* no output */                       \
+                       :"r" (value))
+
+struct mm_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
+/* Prepare to copy thread state - unlazy all lazy status */
+extern void prepare_to_copy(struct task_struct *tsk);
+
+/*
+ * create a kernel thread without removing it from tasklists
+ */
+extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/*
+ * Return saved PC of a blocked thread.
+ * What is this good for? it will be always the scheduler or ret_from_fork.
+ */
+#define thread_saved_pc(t) (*(unsigned long *)((t)->thread.rsp - 8))
+
+extern unsigned long get_wchan(struct task_struct *p);
+#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.rsp0 - 1)
+#define KSTK_EIP(tsk) (task_pt_regs(tsk)->rip)
+#define KSTK_ESP(tsk) -1 /* sorry. doesn't work for syscall. */
+
+
+struct microcode_header {
+       unsigned int hdrver;
+       unsigned int rev;
+       unsigned int date;
+       unsigned int sig;
+       unsigned int cksum;
+       unsigned int ldrver;
+       unsigned int pf;
+       unsigned int datasize;
+       unsigned int totalsize;
+       unsigned int reserved[3];
+};
+
+struct microcode {
+       struct microcode_header hdr;
+       unsigned int bits[0];
+};
+
+typedef struct microcode microcode_t;
+typedef struct microcode_header microcode_header_t;
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+       unsigned int sig;
+       unsigned int pf;
+       unsigned int cksum;
+};
+
+struct extended_sigtable {
+       unsigned int count;
+       unsigned int cksum;
+       unsigned int reserved[3];
+       struct extended_signature sigs[0];
+};
+
+
+#define ASM_NOP1 K8_NOP1
+#define ASM_NOP2 K8_NOP2
+#define ASM_NOP3 K8_NOP3
+#define ASM_NOP4 K8_NOP4
+#define ASM_NOP5 K8_NOP5
+#define ASM_NOP6 K8_NOP6
+#define ASM_NOP7 K8_NOP7
+#define ASM_NOP8 K8_NOP8
+
+/* Opteron nops */
+#define K8_NOP1 ".byte 0x90\n"
+#define K8_NOP2        ".byte 0x66,0x90\n" 
+#define K8_NOP3        ".byte 0x66,0x66,0x90\n" 
+#define K8_NOP4        ".byte 0x66,0x66,0x66,0x90\n" 
+#define K8_NOP5        K8_NOP3 K8_NOP2 
+#define K8_NOP6        K8_NOP3 K8_NOP3
+#define K8_NOP7        K8_NOP4 K8_NOP3
+#define K8_NOP8        K8_NOP4 K8_NOP4
+
+#define ASM_NOP_MAX 8
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void rep_nop(void)
+{
+       __asm__ __volatile__("rep;nop": : :"memory");
+}
+
+/* Stop speculative execution */
+static inline void sync_core(void)
+{ 
+       int tmp;
+       asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
+} 
+
+#define cpu_has_fpu 1
+
+#define ARCH_HAS_PREFETCH
+static inline void prefetch(void *x) 
+{ 
+       asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
+} 
+
+#define ARCH_HAS_PREFETCHW 1
+static inline void prefetchw(void *x) 
+{ 
+       asm volatile("prefetchtw %0" :: "m" (*(unsigned long *)x));
+} 
+
+#define ARCH_HAS_SPINLOCK_PREFETCH 1
+
+#define spin_lock_prefetch(x)  prefetchw(x)
+
+#define cpu_relax()   rep_nop()
+
+static inline void serialize_cpu(void)
+{
+       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+}
+
+static inline void __monitor(const void *eax, unsigned long ecx,
+               unsigned long edx)
+{
+       /* "monitor %eax,%ecx,%edx;" */
+       asm volatile(
+               ".byte 0x0f,0x01,0xc8;"
+               : :"a" (eax), "c" (ecx), "d"(edx));
+}
+
+static inline void __mwait(unsigned long eax, unsigned long ecx)
+{
+       /* "mwait %eax,%ecx;" */
+       asm volatile(
+               ".byte 0x0f,0x01,0xc9;"
+               : :"a" (eax), "c" (ecx));
+}
+
+#define stack_current() \
+({                                                             \
+       struct thread_info *ti;                                 \
+       asm("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK));  \
+       ti->task;                                       \
+})
+
+#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
+
+extern unsigned long boot_option_idle_override;
+/* Boot loader type from the setup header */
+extern int bootloader_type;
+
+#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
+
+#endif /* _X86_64_PROCESSOR_H */
diff --git a/kitten/include/arch-x86_64/proto.h b/kitten/include/arch-x86_64/proto.h
new file mode 100644 (file)
index 0000000..95cd178
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _X86_64_PROTO_H
+#define _X86_64_PROTO_H
+
+/* misc architecture specific prototypes */
+
+extern void early_idt_handler(void);
+
+extern char boot_exception_stacks[];
+
+extern unsigned long table_start, table_end;
+
+void init_kernel_pgtables(unsigned long start, unsigned long end);
+
+extern unsigned long end_pfn_map;
+
+extern void init_resources(void);
+
+extern unsigned long ebda_addr, ebda_size;
+
+extern int unhandled_signal(struct task_struct *tsk, int sig);
+
+extern void asm_syscall(void);
+extern void asm_syscall_ignore(void);
+
+extern unsigned long __phys_addr(unsigned long virt_addr);
+
+void __init interrupts_init(void);
+
+extern paddr_t initrd_start, initrd_end;
+
+#endif
diff --git a/kitten/include/arch-x86_64/ptrace.h b/kitten/include/arch-x86_64/ptrace.h
new file mode 100644 (file)
index 0000000..19f91d9
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef _X86_64_PTRACE_H
+#define _X86_64_PTRACE_H
+
+#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS) 
+#define R15 0
+#define R14 8
+#define R13 16
+#define R12 24
+#define RBP 32
+#define RBX 40
+/* arguments: interrupts/non tracing syscalls only save upto here*/
+#define R11 48
+#define R10 56 
+#define R9 64
+#define R8 72
+#define RAX 80
+#define RCX 88
+#define RDX 96
+#define RSI 104
+#define RDI 112
+#define ORIG_RAX 120       /* = ERROR_CODE */ 
+#define ERROR_CODE 120
+/* end of arguments */         
+/* cpu exception frame or undefined in case of fast syscall. */
+#define RIP 128
+#define CS 136
+#define EFLAGS 144
+#define RSP 152
+#define SS 160
+#define ARGOFFSET R11
+#endif /* __ASSEMBLY__ */
+
+/* top of stack page */ 
+#define FRAME_SIZE 168
+
+#define PTRACE_OLDSETOPTIONS         21
+
+#ifndef __ASSEMBLY__ 
+
+struct pt_regs {
+       unsigned long r15;
+       unsigned long r14;
+       unsigned long r13;
+       unsigned long r12;
+       unsigned long rbp;
+       unsigned long rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+       unsigned long r11;
+       unsigned long r10;      
+       unsigned long r9;
+       unsigned long r8;
+       unsigned long rax;
+       unsigned long rcx;
+       unsigned long rdx;
+       unsigned long rsi;
+       unsigned long rdi;
+       unsigned long orig_rax;
+/* end of arguments */         
+/* cpu exception frame or undefined */
+       unsigned long rip;
+       unsigned long cs;
+       unsigned long eflags; 
+       unsigned long rsp; 
+       unsigned long ss;
+/* top of stack page */ 
+};
+
+#endif
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+#define PTRACE_GETFPXREGS         18
+#define PTRACE_SETFPXREGS         19
+
+/* only useful for access 32bit programs */
+#define PTRACE_GET_THREAD_AREA    25
+#define PTRACE_SET_THREAD_AREA    26
+
+#define PTRACE_ARCH_PRCTL        30    /* arch_prctl for child */
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__) 
+#define user_mode(regs) (!!((regs)->cs & 3))
+#define user_mode_vm(regs) user_mode(regs)
+#define instruction_pointer(regs) ((regs)->rip)
+extern unsigned long profile_pc(struct pt_regs *regs);
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+
+struct task_struct;
+
+extern unsigned long
+convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs);
+
+enum {
+        EF_CF   = 0x00000001,
+        EF_PF   = 0x00000004,
+        EF_AF   = 0x00000010,
+        EF_ZF   = 0x00000040,
+        EF_SF   = 0x00000080,
+        EF_TF   = 0x00000100,
+        EF_IE   = 0x00000200,
+        EF_DF   = 0x00000400,
+        EF_OF   = 0x00000800,
+        EF_IOPL = 0x00003000,
+        EF_IOPL_RING0 = 0x00000000,
+        EF_IOPL_RING1 = 0x00001000,
+        EF_IOPL_RING2 = 0x00002000,
+        EF_NT   = 0x00004000,   /* nested task */
+        EF_RF   = 0x00010000,   /* resume */
+        EF_VM   = 0x00020000,   /* virtual mode */
+        EF_AC   = 0x00040000,   /* alignment */
+        EF_VIF  = 0x00080000,   /* virtual interrupt */
+        EF_VIP  = 0x00100000,   /* virtual interrupt pending */
+        EF_ID   = 0x00200000,   /* id */
+};
+
+/* TODO: remove this */
+typedef void (*idtvec_handler_t)(struct pt_regs *regs, unsigned int vector);
+void set_idtvec_handler(unsigned int vector, idtvec_handler_t handler);
+
+#endif
+
+#endif
diff --git a/kitten/include/arch-x86_64/rwlock.h b/kitten/include/arch-x86_64/rwlock.h
new file mode 100644 (file)
index 0000000..60036f3
--- /dev/null
@@ -0,0 +1,86 @@
+/* include/arch-x86_64/rwlock.h
+ *
+ *     Helpers used by both rw spinlocks and rw semaphores.
+ *
+ *     Based in part on code from semaphore.h and
+ *     spinlock.h Copyright 1996 Linus Torvalds.
+ *
+ *     Copyright 1999 Red Hat, Inc.
+ *     Copyright 2001,2002 SuSE labs 
+ *
+ *     Written by Benjamin LaHaise.
+ *
+ *     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 _ARCH_X86_64_RWLOCK_H
+#define _ARCH_X86_64_RWLOCK_H
+
+#include <lwk/stringify.h>
+
+#define RW_LOCK_BIAS            0x01000000
+#define RW_LOCK_BIAS_STR       "0x01000000"
+
+#define __build_read_lock_ptr(rw, helper)   \
+       asm volatile("lock ; subl $1,(%0)\n\t" \
+                    "js 2f\n" \
+                    "1:\n" \
+                   LOCK_SECTION_START("") \
+                    "2:\tcall " helper "\n\t" \
+                    "jmp 1b\n" \
+                   LOCK_SECTION_END \
+                    ::"a" (rw) : "memory")
+
+#define __build_read_lock_const(rw, helper)   \
+       asm volatile("lock ; subl $1,%0\n\t" \
+                    "js 2f\n" \
+                    "1:\n" \
+                   LOCK_SECTION_START("") \
+                    "2:\tpushq %%rax\n\t" \
+                    "leaq %0,%%rax\n\t" \
+                    "call " helper "\n\t" \
+                    "popq %%rax\n\t" \
+                    "jmp 1b\n" \
+                   LOCK_SECTION_END \
+                    :"=m" (*((volatile int *)rw))::"memory")
+
+#define __build_read_lock(rw, helper)  do { \
+                                               if (__builtin_constant_p(rw)) \
+                                                       __build_read_lock_const(rw, helper); \
+                                               else \
+                                                       __build_read_lock_ptr(rw, helper); \
+                                       } while (0)
+
+#define __build_write_lock_ptr(rw, helper) \
+       asm volatile("lock ; subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+                    "jnz 2f\n" \
+                    "1:\n" \
+                    LOCK_SECTION_START("") \
+                    "2:\tcall " helper "\n\t" \
+                    "jmp 1b\n" \
+                    LOCK_SECTION_END \
+                    ::"a" (rw) : "memory")
+
+#define __build_write_lock_const(rw, helper) \
+       asm volatile("lock ; subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+                    "jnz 2f\n" \
+                    "1:\n" \
+                   LOCK_SECTION_START("") \
+                    "2:\tpushq %%rax\n\t" \
+                    "leaq %0,%%rax\n\t" \
+                    "call " helper "\n\t" \
+                    "popq %%rax\n\t" \
+                    "jmp 1b\n" \
+                   LOCK_SECTION_END \
+                    :"=m" (*((volatile long *)rw))::"memory")
+
+#define __build_write_lock(rw, helper) do { \
+                                               if (__builtin_constant_p(rw)) \
+                                                       __build_write_lock_const(rw, helper); \
+                                               else \
+                                                       __build_write_lock_ptr(rw, helper); \
+                                       } while (0)
+
+#endif
diff --git a/kitten/include/arch-x86_64/sections.h b/kitten/include/arch-x86_64/sections.h
new file mode 100644 (file)
index 0000000..47fc1bc
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _X86_64_SECTIONS_H
+#define _X86_64_SECTIONS_H
+
+/* nothing to see, move along */
+#include <arch-generic/sections.h>
+
+#endif
diff --git a/kitten/include/arch-x86_64/segment.h b/kitten/include/arch-x86_64/segment.h
new file mode 100644 (file)
index 0000000..b08353e
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _ARCH_SEGMENT_H
+#define _ARCH_SEGMENT_H
+
+#include <arch/cache.h>
+
+#define __KERNEL_CS    0x10
+#define __KERNEL_DS    0x18
+
+#define __KERNEL32_CS   0x08
+
+/* 
+ * we cannot use the same code segment descriptor for user and kernel
+ * -- not even in the long flat mode, because of different DPL /kkeil 
+ * The segment offset needs to contain a RPL. Grr. -AK
+ * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets) 
+ */
+
+#define __USER32_CS   0x23   /* 4*8+3 */ 
+#define __USER_DS     0x2b   /* 5*8+3 */ 
+#define __USER_CS     0x33   /* 6*8+3 */ 
+#define __USER32_DS    __USER_DS 
+
+#define GDT_ENTRY_TSS 8        /* needs two entries */
+#define GDT_ENTRY_LDT 10 /* needs two entries */
+#define GDT_ENTRY_TLS_MIN 12
+#define GDT_ENTRY_TLS_MAX 14
+
+#define GDT_ENTRY_TLS_ENTRIES 3
+
+#define GDT_ENTRY_PER_CPU 15   /* Abused to load per CPU data from limit */
+#define __PER_CPU_SEG  (GDT_ENTRY_PER_CPU * 8 + 3)
+
+/* TLS indexes for 64bit - hardcoded in arch_prctl */
+#define FS_TLS 0       
+#define GS_TLS 1       
+
+#define GS_TLS_SEL ((GDT_ENTRY_TLS_MIN+GS_TLS)*8 + 3)
+#define FS_TLS_SEL ((GDT_ENTRY_TLS_MIN+FS_TLS)*8 + 3)
+
+#define IDT_ENTRIES 256
+#define GDT_ENTRIES 16
+#define GDT_SIZE (GDT_ENTRIES * 8)
+#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8) 
+
+#endif
diff --git a/kitten/include/arch-x86_64/show.h b/kitten/include/arch-x86_64/show.h
new file mode 100644 (file)
index 0000000..c883382
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_X86_64_SHOW_H
+#define _ASM_X86_64_SHOW_H
+
+#include <lwk/ptrace.h>
+
+extern void printk_address(unsigned long address);
+extern void show_registers(struct pt_regs *regs);
+
+#endif
diff --git a/kitten/include/arch-x86_64/sigcontext.h b/kitten/include/arch-x86_64/sigcontext.h
new file mode 100644 (file)
index 0000000..4a55012
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _X86_64_SIGCONTEXT_H
+#define _X86_64_SIGCONTEXT_H
+
+#include <arch/types.h>
+#include <lwk/compiler.h>
+
+/* FXSAVE frame */
+/* Note: reserved1/2 may someday contain valuable data. Always save/restore
+   them when you change signal frames. */
+struct _fpstate {
+       __u16   cwd;
+       __u16   swd;
+       __u16   twd;    /* Note this is not the same as the 32bit/x87/FSAVE twd */
+       __u16   fop;
+       __u64   rip;
+       __u64   rdp; 
+       __u32   mxcsr;
+       __u32   mxcsr_mask;
+       __u32   st_space[32];   /* 8*16 bytes for each FP-reg */
+       __u32   xmm_space[64];  /* 16*16 bytes for each XMM-reg  */
+       __u32   reserved2[24];
+};
+
+struct sigcontext { 
+       unsigned long r8;
+       unsigned long r9;
+       unsigned long r10;
+       unsigned long r11;
+       unsigned long r12;
+       unsigned long r13;
+       unsigned long r14;
+       unsigned long r15;
+       unsigned long rdi;
+       unsigned long rsi;
+       unsigned long rbp;
+       unsigned long rbx;
+       unsigned long rdx;
+       unsigned long rax;
+       unsigned long rcx;
+       unsigned long rsp;
+       unsigned long rip;
+       unsigned long eflags;           /* RFLAGS */
+       unsigned short cs;
+       unsigned short gs;
+       unsigned short fs;
+       unsigned short __pad0; 
+       unsigned long err;
+       unsigned long trapno;
+       unsigned long oldmask;
+       unsigned long cr2;
+       struct _fpstate __user *fpstate;        /* zero when no FPU context */
+       unsigned long reserved1[8];
+};
+
+#endif
diff --git a/kitten/include/arch-x86_64/siginfo.h b/kitten/include/arch-x86_64/siginfo.h
new file mode 100644 (file)
index 0000000..d5329fe
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _X8664_SIGINFO_H
+#define _X8664_SIGINFO_H
+
+#define __ARCH_SI_PREAMBLE_SIZE        (4 * sizeof(int))
+
+#include <arch-generic/siginfo.h>
+
+#endif
diff --git a/kitten/include/arch-x86_64/signal.h b/kitten/include/arch-x86_64/signal.h
new file mode 100644 (file)
index 0000000..a46a806
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef _ASM_X86_64_SIGNAL_H
+#define _ASM_X86_64_SIGNAL_H
+
+#ifndef __ASSEMBLY__
+#include <lwk/types.h>
+#include <lwk/time.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifdef __KERNEL__
+#include <lwk/linkage.h>
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+#define _NSIG          64
+#define _NSIG_BPW      64
+#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t;            /* at least 32 bits */
+
+typedef struct {
+       unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG           32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+#endif
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/*
+#define SIGLOST                29
+*/
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#define SIGRTMAX       _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP   0x00000001
+#define SA_NOCLDWAIT   0x00000002
+#define SA_SIGINFO     0x00000004
+#define SA_ONSTACK     0x08000000
+#define SA_RESTART     0x10000000
+#define SA_NODEFER     0x40000000
+#define SA_RESETHAND   0x80000000
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+
+#define SA_RESTORER    0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK     1
+#define SS_DISABLE     2
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
+#include <arch-generic/signal.h>
+
+#ifndef __ASSEMBLY__
+
+struct sigaction {
+       __sighandler_t sa_handler;
+       unsigned long sa_flags;
+       __sigrestore_t sa_restorer;
+       sigset_t sa_mask;               /* mask last for extensibility */
+};
+
+struct k_sigaction {
+       struct sigaction sa;
+};
+
+typedef struct sigaltstack {
+       void __user *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+#include <arch/sigcontext.h>
+
+#undef __HAVE_ARCH_SIG_BITOPS
+#endif
+
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/kitten/include/arch-x86_64/smp.h b/kitten/include/arch-x86_64/smp.h
new file mode 100644 (file)
index 0000000..c127ed6
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef _ASM_SMP_H
+#define _ASM_SMP_H
+
+/*
+ * We need the APIC definitions automatically as part of 'smp.h'
+ */
+#ifndef __ASSEMBLY__
+/* #include <linux/threads.h>s */
+#include <lwk/cpumask.h>
+#include <lwk/bitops.h>
+extern int disable_apic;
+#endif
+
+#ifndef __ASSEMBLY__
+#include <arch/fixmap.h>
+//#include <asm/mpspec.h>
+//#include <asm/io_apic.h>
+#include <arch/apic.h>
+//#include <asm/thread_info.h>
+#include <arch/pda.h>
+
+struct pt_regs;
+
+extern cpumask_t cpu_present_mask;
+extern cpumask_t cpu_possible_map;
+extern cpumask_t cpu_online_map;
+extern cpumask_t cpu_callout_map;
+extern cpumask_t cpu_initialized;
+
+/*
+ * Private routines/data
+ */
+extern void smp_alloc_memory(void);
+extern volatile unsigned long smp_invalidate_needed;
+extern int pic_mode;
+extern void lock_ipi_call_lock(void);
+extern void unlock_ipi_call_lock(void);
+extern int smp_num_siblings;
+extern void smp_send_reschedule(int cpu);
+void smp_stop_cpu(void);
+extern int smp_call_function_single(int cpuid, void (*func) (void *info),
+                               void *info, int retry, int wait);
+
+extern cpumask_t cpu_sibling_map[NR_CPUS];
+extern cpumask_t cpu_core_map[NR_CPUS];
+extern uint16_t phys_proc_id[NR_CPUS];
+extern uint16_t cpu_core_id[NR_CPUS];
+extern uint16_t cpu_llc_id[NR_CPUS];
+
+#define SMP_TRAMPOLINE_BASE 0x6000
+
+/*
+ * On x86 all CPUs are mapped 1:1 to the APIC space.
+ * This simplifies scheduling and IPI sending and
+ * compresses data structures.
+ */
+
+static inline int num_booting_cpus(void)
+{
+       return cpus_weight(cpu_callout_map);
+}
+
+#define raw_smp_processor_id() read_pda(cpunumber)
+
+static inline int hard_smp_processor_id(void)
+{
+       /* we don't want to mark this access volatile - bad code generation */
+       return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
+}
+
+extern int safe_smp_processor_id(void);
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+extern void prefill_possible_map(void);
+extern unsigned num_processors;
+extern unsigned disabled_cpus;
+
+#endif /* !ASSEMBLY */
+
+#define NO_PROC_ID             0xFF            /* No processor magic marker */
+
+
+#ifndef ASSEMBLY
+/*
+ * Some lowlevel functions might want to know about
+ * the real APIC ID <-> CPU # mapping.
+ */
+extern u8 x86_cpu_to_apicid[NR_CPUS];  /* physical ID */
+extern u8 x86_cpu_to_log_apicid[NR_CPUS];
+extern u8 bios_cpu_apicid[];
+
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+{
+       return cpus_addr(cpumask)[0];
+}
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+       if (mps_cpu < NR_CPUS)
+               return (int)bios_cpu_apicid[mps_cpu];
+       else
+               return BAD_APICID;
+}
+
+#endif /* !ASSEMBLY */
+
+#include <lwk/task.h>
+#define stack_smp_processor_id() \
+({                                                                     \
+       struct task_struct *task;                                               \
+       __asm__("andq %%rsp,%0; ":"=r" (task) : "0" (CURRENT_MASK));    \
+       task->arch.cpu;                                                 \
+})
+
+#ifndef __ASSEMBLY__
+static __inline int logical_smp_processor_id(void)
+{
+       /* we don't want to mark this access volatile - bad code generation */
+       return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
+}
+#endif
+
+#define cpu_physical_id(cpu)           x86_cpu_to_apicid[cpu]
+
+#endif
+
diff --git a/kitten/include/arch-x86_64/spinlock.h b/kitten/include/arch-x86_64/spinlock.h
new file mode 100644 (file)
index 0000000..b3f1256
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef _X86_64_SPINLOCK_H
+#define _X86_64_SPINLOCK_H
+
+#include <arch/atomic.h>
+#include <arch/rwlock.h>
+#include <arch/page.h>
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ *
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ *
+ * (the type definitions are in arch/spinlock_types.h)
+ */
+
+#define __raw_spin_is_locked(x) \
+               (*(volatile signed int *)(&(x)->slock) <= 0)
+
+#define __raw_spin_lock_string \
+       "\n1:\t" \
+       "lock ; decl %0\n\t" \
+       "js 2f\n" \
+       LOCK_SECTION_START("") \
+       "2:\t" \
+       "rep;nop\n\t" \
+       "cmpl $0,%0\n\t" \
+       "jle 2b\n\t" \
+       "jmp 1b\n" \
+       LOCK_SECTION_END
+
+#define __raw_spin_unlock_string \
+       "movl $1,%0" \
+               :"=m" (lock->slock) : : "memory"
+
+static inline void __raw_spin_lock(raw_spinlock_t *lock)
+{
+       __asm__ __volatile__(
+               __raw_spin_lock_string
+               :"=m" (lock->slock) : : "memory");
+}
+
+#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+
+static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+{
+       int oldval;
+
+       __asm__ __volatile__(
+               "xchgl %0,%1"
+               :"=q" (oldval), "=m" (lock->slock)
+               :"0" (0) : "memory");
+
+       return oldval > 0;
+}
+
+static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+{
+       __asm__ __volatile__(
+               __raw_spin_unlock_string
+       );
+}
+
+#define __raw_spin_unlock_wait(lock) \
+       do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ *
+ * On x86, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+ *
+ * The inline assembly is non-obvious. Think about it.
+ *
+ * Changed to use the same technique as rw semaphores.  See
+ * semaphore.h for details.  -ben
+ *
+ * the helpers are in arch/i386/kernel/semaphore.c
+ */
+
+#define __raw_read_can_lock(x)         ((int)(x)->lock > 0)
+#define __raw_write_can_lock(x)                ((x)->lock == RW_LOCK_BIAS)
+
+static inline void __raw_read_lock(raw_rwlock_t *rw)
+{
+       __build_read_lock(rw, "__read_lock_failed");
+}
+
+static inline void __raw_write_lock(raw_rwlock_t *rw)
+{
+       __build_write_lock(rw, "__write_lock_failed");
+}
+
+static inline int __raw_read_trylock(raw_rwlock_t *lock)
+{
+       atomic_t *count = (atomic_t *)lock;
+       atomic_dec(count);
+       if (atomic_read(count) >= 0)
+               return 1;
+       atomic_inc(count);
+       return 0;
+}
+
+static inline int __raw_write_trylock(raw_rwlock_t *lock)
+{
+       atomic_t *count = (atomic_t *)lock;
+       if (atomic_sub_and_test(RW_LOCK_BIAS, count))
+               return 1;
+       atomic_add(RW_LOCK_BIAS, count);
+       return 0;
+}
+
+static inline void __raw_read_unlock(raw_rwlock_t *rw)
+{
+       asm volatile("lock ; incl %0" :"=m" (rw->lock) : : "memory");
+}
+
+static inline void __raw_write_unlock(raw_rwlock_t *rw)
+{
+       asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0"
+                               : "=m" (rw->lock) : : "memory");
+}
+
+#endif /* _X86_64_SPINLOCK_H */
diff --git a/kitten/include/arch-x86_64/spinlock_types.h b/kitten/include/arch-x86_64/spinlock_types.h
new file mode 100644 (file)
index 0000000..ad5079e
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _X86_64_SPINLOCK_TYPES_H
+#define _X86_64_SPINLOCK_TYPES_H
+
+#ifndef _LWK_SPINLOCK_TYPES_H
+# error "please don't include this file directly"
+#endif
+
+typedef struct {
+       volatile unsigned int slock;
+} raw_spinlock_t;
+
+#define __RAW_SPIN_LOCK_UNLOCKED       { 1 }
+
+typedef struct {
+       volatile unsigned int lock;
+} raw_rwlock_t;
+
+#define __RAW_RW_LOCK_UNLOCKED         { RW_LOCK_BIAS }
+
+#endif
diff --git a/kitten/include/arch-x86_64/stat.h b/kitten/include/arch-x86_64/stat.h
new file mode 100644 (file)
index 0000000..059bcf1
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _X86_64_STAT_H
+#define _X86_64_STAT_H
+
+#define STAT_HAVE_NSEC 1
+
+struct stat {
+       unsigned long   st_dev;
+       unsigned long   st_ino;
+       unsigned long   st_nlink;
+
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    __pad0;
+       unsigned long   st_rdev;
+       long            st_size;
+       long            st_blksize;
+       long            st_blocks;      /* Number 512-byte blocks allocated. */
+
+       unsigned long   st_atime;
+       unsigned long   st_atime_nsec; 
+       unsigned long   st_mtime;
+       unsigned long   st_mtime_nsec;
+       unsigned long   st_ctime;
+       unsigned long   st_ctime_nsec;
+       long            __unused[3];
+};
+
+#endif
diff --git a/kitten/include/arch-x86_64/string.h b/kitten/include/arch-x86_64/string.h
new file mode 100644 (file)
index 0000000..ee6bf27
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _X86_64_STRING_H_
+#define _X86_64_STRING_H_
+
+#ifdef __KERNEL__
+
+/* Written 2002 by Andi Kleen */ 
+
+/* Only used for special circumstances. Stolen from i386/string.h */ 
+static inline void * __inline_memcpy(void * to, const void * from, size_t n)
+{
+unsigned long d0, d1, d2;
+__asm__ __volatile__(
+       "rep ; movsl\n\t"
+       "testb $2,%b4\n\t"
+       "je 1f\n\t"
+       "movsw\n"
+       "1:\ttestb $1,%b4\n\t"
+       "je 2f\n\t"
+       "movsb\n"
+       "2:"
+       : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+       :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+       : "memory");
+return (to);
+}
+
+/* Even with __builtin_ the compiler may decide to use the out of line
+   function. */
+
+#define __HAVE_ARCH_MEMCPY 1
+extern void *__memcpy(void *to, const void *from, size_t len); 
+#define memcpy(dst,src,len) \
+       ({ size_t __len = (len);                                \
+          void *__ret;                                         \
+          if (__builtin_constant_p(len) && __len >= 64)        \
+                __ret = __memcpy((dst),(src),__len);           \
+          else                                                 \
+                __ret = __builtin_memcpy((dst),(src),__len);   \
+          __ret; }) 
+
+
+#define __HAVE_ARCH_MEMSET
+void *memset(void *s, int c, size_t n);
+
+#define __HAVE_ARCH_MEMMOVE
+void * memmove(void * dest,const void *src,size_t count);
+
+int memcmp(const void * cs,const void * ct,size_t count);
+size_t strlen(const char * s);
+char *strcpy(char * dest,const char *src);
+char *strcat(char * dest, const char * src);
+int strcmp(const char * cs,const char * ct);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/kitten/include/arch-x86_64/system.h b/kitten/include/arch-x86_64/system.h
new file mode 100644 (file)
index 0000000..98f7ee2
--- /dev/null
@@ -0,0 +1,278 @@
+#ifndef __ASM_SYSTEM_H
+#define __ASM_SYSTEM_H
+
+#include <lwk/kernel.h>
+#include <arch/segment.h>
+
+#ifdef __KERNEL__
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define __SAVE(reg,offset) "movq %%" #reg ",(14-" #offset ")*8(%%rsp)\n\t"
+#define __RESTORE(reg,offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t"
+
+/* frame pointer must be last for get_wchan */
+#define SAVE_CONTEXT    "pushq %%rbp ; movq %%rsi,%%rbp\n\t"
+#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\n\t"
+
+#define __EXTRA_CLOBBER  \
+       ,"rcx","rbx","rdx","r8","r9","r10","r11","r12","r13","r14","r15"
+
+#define switch_to(prev,next,last) \
+       asm volatile(SAVE_CONTEXT                                                   \
+                    "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */       \
+                    "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */    \
+                    "call __switch_to\n\t"                                       \
+                    ".globl thread_return\n"                                   \
+                    "thread_return:\n\t"                                           \
+                    "movq %%gs:%P[pda_pcurrent],%%rsi\n\t"                       \
+                    "movq %P[thread_info](%%rsi),%%r8\n\t"                       \
+                    "lock ; btr  %[tif_fork],%P[ti_flags](%%r8)\n\t"     \
+                    "movq %%rax,%%rdi\n\t"                                       \
+                    "jc   ret_from_fork\n\t"                                     \
+                    RESTORE_CONTEXT                                                \
+                    : "=a" (last)                                                \
+                    : [next] "S" (next), [prev] "D" (prev),                      \
+                      [threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \
+                      [ti_flags] "i" (offsetof(struct thread_info, flags)),\
+                      [tif_fork] "i" (TIF_FORK),                         \
+                      [thread_info] "i" (offsetof(struct task_struct, thread_info)), \
+                      [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent))   \
+                    : "memory", "cc" __EXTRA_CLOBBER)
+    
+extern void load_gs_index(unsigned); 
+
+/*
+ * Load a segment. Fall back on loading the zero
+ * segment if something goes wrong..
+ */
+#define loadsegment(seg,value) \
+       asm volatile("\n"                       \
+               "1:\t"                          \
+               "movl %k0,%%" #seg "\n"         \
+               "2:\n"                          \
+               ".section .fixup,\"ax\"\n"      \
+               "3:\t"                          \
+               "movl %1,%%" #seg "\n\t"        \
+               "jmp 2b\n"                      \
+               ".previous\n"                   \
+               ".section __ex_table,\"a\"\n\t" \
+               ".align 8\n\t"                  \
+               ".quad 1b,3b\n"                 \
+               ".previous"                     \
+               : :"r" (value), "r" (0))
+
+/*
+ * Clear and set 'TS' bit respectively
+ */
+#define clts() __asm__ __volatile__ ("clts")
+
+static inline unsigned long read_cr0(void)
+{ 
+       unsigned long cr0;
+       asm volatile("movq %%cr0,%0" : "=r" (cr0));
+       return cr0;
+} 
+
+static inline void write_cr0(unsigned long val) 
+{ 
+       asm volatile("movq %0,%%cr0" :: "r" (val));
+} 
+
+static inline unsigned long read_cr3(void)
+{ 
+       unsigned long cr3;
+       asm("movq %%cr3,%0" : "=r" (cr3));
+       return cr3;
+} 
+
+static inline unsigned long read_cr4(void)
+{ 
+       unsigned long cr4;
+       asm("movq %%cr4,%0" : "=r" (cr4));
+       return cr4;
+} 
+
+static inline void write_cr4(unsigned long val)
+{ 
+       asm volatile("movq %0,%%cr4" :: "r" (val));
+} 
+
+#define stts() write_cr0(8 | read_cr0())
+
+#define wbinvd() \
+       __asm__ __volatile__ ("wbinvd": : :"memory");
+
+static inline unsigned long read_eflags(void)
+{ 
+       unsigned long eflags;
+
+       __asm__ __volatile__(
+               "# __raw_save_flags\n\t"
+               "pushf ; pop %0"
+               : "=g" (eflags)
+               : /* no input */
+               : "memory"
+       );
+
+       return eflags;
+} 
+
+/*
+ * On SMP systems, when the scheduler does migration-cost autodetection,
+ * it needs a way to flush as much of the CPU's caches as possible.
+ */
+static inline void sched_cacheflush(void)
+{
+       wbinvd();
+}
+
+#endif /* __KERNEL__ */
+
+#define nop() __asm__ __volatile__ ("nop")
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+#define tas(ptr) (xchg((ptr),1))
+
+#define __xg(x) ((volatile long *)(x))
+
+static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
+{
+       *ptr = val;
+}
+
+#define _set_64bit set_64bit
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ *       but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+       switch (size) {
+               case 1:
+                       __asm__ __volatile__("xchgb %b0,%1"
+                               :"=q" (x)
+                               :"m" (*__xg(ptr)), "0" (x)
+                               :"memory");
+                       break;
+               case 2:
+                       __asm__ __volatile__("xchgw %w0,%1"
+                               :"=r" (x)
+                               :"m" (*__xg(ptr)), "0" (x)
+                               :"memory");
+                       break;
+               case 4:
+                       __asm__ __volatile__("xchgl %k0,%1"
+                               :"=r" (x)
+                               :"m" (*__xg(ptr)), "0" (x)
+                               :"memory");
+                       break;
+               case 8:
+                       __asm__ __volatile__("xchgq %0,%1"
+                               :"=r" (x)
+                               :"m" (*__xg(ptr)), "0" (x)
+                               :"memory");
+                       break;
+       }
+       return x;
+}
+
+/*
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+                                     unsigned long new, int size)
+{
+       unsigned long prev;
+       switch (size) {
+       case 1:
+               __asm__ __volatile__("lock ; cmpxchgb %b1,%2"
+                                    : "=a"(prev)
+                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "memory");
+               return prev;
+       case 2:
+               __asm__ __volatile__("lock ; cmpxchgw %w1,%2"
+                                    : "=a"(prev)
+                                    : "r"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "memory");
+               return prev;
+       case 4:
+               __asm__ __volatile__("lock ; cmpxchgl %k1,%2"
+                                    : "=a"(prev)
+                                    : "r"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "memory");
+               return prev;
+       case 8:
+               __asm__ __volatile__("lock ; cmpxchgq %1,%2"
+                                    : "=a"(prev)
+                                    : "r"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "memory");
+               return prev;
+       }
+       return old;
+}
+
+#define cmpxchg(ptr,o,n)\
+       ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+                                       (unsigned long)(n),sizeof(*(ptr))))
+
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#define smp_read_barrier_depends()     do {} while(0)
+    
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ */
+#define mb()   asm volatile("mfence":::"memory")
+#define rmb()  asm volatile("lfence":::"memory")
+#define wmb()  asm volatile("sfence" ::: "memory")
+#define read_barrier_depends() do {} while(0)
+#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
+
+/* interrupt control.. */
+#define local_save_flags(x)    do { warn_if_not_ulong(x); __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0)
+#define local_irq_restore(x)   __asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc")
+
+#define local_irq_disable()    __asm__ __volatile__("cli": : :"memory")
+#define local_irq_enable()     __asm__ __volatile__("sti": : :"memory")
+
+#define irqs_disabled()                        \
+({                                     \
+       unsigned long flags;            \
+       local_save_flags(flags);        \
+       !(flags & (1<<9));              \
+})
+
+#define irqs_enabled() !irqs_disabled()
+
+/* For spinlocks etc */
+#define local_irq_save(x)      do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
+
+/* used in the idle loop; sti takes one instruction cycle to complete */
+#define safe_halt()            __asm__ __volatile__("sti; hlt": : :"memory")
+/* used when interrupts are already enabled or to shutdown the processor */
+#define halt()                 __asm__ __volatile__("hlt": : :"memory")
+
+void cpu_idle_wait(void);
+
+extern unsigned long arch_align_stack(unsigned long sp);
+extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
+
+#endif
diff --git a/kitten/include/arch-x86_64/task.h b/kitten/include/arch-x86_64/task.h
new file mode 100644 (file)
index 0000000..361c682
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _ARCH_TASK_H
+#define _ARCH_TASK_H
+
+/**
+ * Bits in the arch_task.flags field.
+ */
+#define _TF_NEW_TASK_BIT  0
+#define _TF_USED_FPU_BIT  1
+
+/**
+ * Masks for the bits in the arch_task.flags field.
+ */
+#define TF_NEW_TASK   (1 << _TF_NEW_TASK_BIT)
+#define TF_USED_FPU   (1 << _TF_USED_FPU_BIT)
+
+#ifndef __ASSEMBLY__
+
+#include <arch/pda.h>
+#include <arch/page_table.h>
+
+struct arch_mm {
+       xpte_t  *page_table_root;
+};
+
+/**
+ * Architecture-specific task information.
+ */
+struct arch_task {
+       uint32_t                flags;          /* arch-dependent task flags */
+       unsigned long           addr_limit;     /* task's virtual memory space is from [0,addr_limit) */
+       struct thread_struct    thread;
+};
+
+#endif
+#endif
diff --git a/kitten/include/arch-x86_64/time.h b/kitten/include/arch-x86_64/time.h
new file mode 100644 (file)
index 0000000..d0afd58
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ARCH_x86_64_TIME_H
+#define _ARCH_x86_64_TIME_H
+
+#include <arch/tsc.h>
+
+#endif
diff --git a/kitten/include/arch-x86_64/tlbflush.h b/kitten/include/arch-x86_64/tlbflush.h
new file mode 100644 (file)
index 0000000..e3a78bc
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef _X86_64_TLBFLUSH_H
+#define _X86_64_TLBFLUSH_H
+
+//#include <linux/mm.h>
+#include <arch/processor.h>
+
+#define __flush_tlb()                                                  \
+       do {                                                            \
+               unsigned long tmpreg;                                   \
+                                                                       \
+               __asm__ __volatile__(                                   \
+                       "movq %%cr3, %0;  # flush TLB \n"               \
+                       "movq %0, %%cr3;              \n"               \
+                       : "=r" (tmpreg)                                 \
+                       :: "memory");                                   \
+       } while (0)
+
+/*
+ * Global pages have to be flushed a bit differently. Not a real
+ * performance problem because this does not happen often.
+ */
+#define __flush_tlb_global()                                           \
+       do {                                                            \
+               unsigned long tmpreg, cr4, cr4_orig;                    \
+                                                                       \
+               __asm__ __volatile__(                                   \
+                       "movq %%cr4, %2;  # turn off PGE     \n"        \
+                       "movq %2, %1;                        \n"        \
+                       "andq %3, %1;                        \n"        \
+                       "movq %1, %%cr4;                     \n"        \
+                       "movq %%cr3, %0;  # flush TLB        \n"        \
+                       "movq %0, %%cr3;                     \n"        \
+                       "movq %2, %%cr4;  # turn PGE back on \n"        \
+                       : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \
+                       : "i" (~X86_CR4_PGE)                            \
+                       : "memory");                                    \
+       } while (0)
+
+extern unsigned long pgkern_mask;
+
+#define __flush_tlb_all() __flush_tlb_global()
+
+#define __flush_tlb_one(addr) \
+       __asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+
+#if 0
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ *
+ * x86-64 can only flush individual pages or full VMs. For a range flush
+ * we always do the full VM. Might be worth trying if for a small
+ * range a few INVLPGs in a row are a win.
+ */
+
+#ifndef CONFIG_SMP
+
+#define flush_tlb() __flush_tlb()
+#define flush_tlb_all() __flush_tlb_all()
+#define local_flush_tlb() __flush_tlb()
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       if (mm == current->active_mm)
+               __flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+       unsigned long addr)
+{
+       if (vma->vm_mm == current->active_mm)
+               __flush_tlb_one(addr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+       unsigned long start, unsigned long end)
+{
+       if (vma->vm_mm == current->active_mm)
+               __flush_tlb();
+}
+
+#else
+
+#include <asm/smp.h>
+
+#define local_flush_tlb() \
+       __flush_tlb()
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+
+#define flush_tlb()    flush_tlb_current_task()
+
+static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
+{
+       flush_tlb_mm(vma->vm_mm);
+}
+
+#define TLBSTATE_OK    1
+#define TLBSTATE_LAZY  2
+
+/* Roughly an IPI every 20MB with 4k pages for freeing page table
+   ranges. Cost is about 42k of memory for each CPU. */
+#define ARCH_FREE_PTE_NR 5350  
+
+#endif
+
+#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+                                     unsigned long start, unsigned long end)
+{
+       /* x86_64 does not keep any page table caches in a software TLB.
+          The CPUs do in their hardware TLBs, but they are handled
+          by the normal TLB flushing algorithms. */
+}
+
+#endif
+
+#endif /* _X86_64_TLBFLUSH_H */
diff --git a/kitten/include/arch-x86_64/tsc.h b/kitten/include/arch-x86_64/tsc.h
new file mode 100644 (file)
index 0000000..4d5a53d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-i386/tsc.h
+ *
+ * i386 TSC related functions
+ */
+#ifndef _ARCH_x86_64_TSC_H
+#define _ARCH_x86_64_TSC_H
+
+#include <lwk/types.h>
+#include <arch/processor.h>
+
+typedef uint64_t cycles_t;
+
+/**
+ * Returns the current value of the CPU's cycle counter.
+ *
+ * NOTE: This is not serializing. It doesn't necessarily wait for previous
+ *       instructions to complete before reading the cycle counter. Also,
+ *       subsequent instructions could potentially begin execution before
+ *       the cycle counter is read.
+ */
+static __always_inline cycles_t
+get_cycles(void)
+{
+       cycles_t ret = 0;
+       rdtscll(ret);
+       return ret;
+}
+
+/**
+ * This is a synchronizing version of get_cycles(). It ensures that all
+ * previous instructions have completed before reading the cycle counter.
+ */
+static __always_inline cycles_t
+get_cycles_sync(void)
+{
+       sync_core();
+       return get_cycles();
+}
+
+#endif
diff --git a/kitten/include/arch-x86_64/types.h b/kitten/include/arch-x86_64/types.h
new file mode 100644 (file)
index 0000000..2d4491a
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _X86_64_TYPES_H
+#define _X86_64_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+typedef __signed__ long long __s64;
+typedef unsigned long long  __u64;
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+#define BITS_PER_LONG 64
+
+#ifndef __ASSEMBLY__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+typedef u64 dma64_addr_t;
+typedef u64 dma_addr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/kitten/include/arch-x86_64/uaccess.h b/kitten/include/arch-x86_64/uaccess.h
new file mode 100644 (file)
index 0000000..2c97699
--- /dev/null
@@ -0,0 +1,349 @@
+#ifndef _X86_64_UACCESS_H
+#define _X86_64_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <lwk/compiler.h>
+#include <lwk/errno.h>
+#include <lwk/prefetch.h>
+#include <lwk/task.h>
+#include <arch/page.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS      0xFFFFFFFFFFFFFFFFUL
+#define USER_DS                PAGE_OFFSET
+
+#define get_ds()       (KERNEL_DS)
+#define get_fs()       (current->arch.addr_limit)
+#define set_fs(x)      (current->arch.addr_limit = (x))
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
+
+#define __addr_ok(addr) (!((unsigned long)(addr) & (current->arch.addr_limit)))
+
+/*
+ * Uhhuh, this needs 65-bit arithmetic. We have a carry..
+ */
+#define __range_not_ok(addr,size) ({ \
+       unsigned long flag,sum; \
+       __chk_user_ptr(addr); \
+       asm("# range_ok\n\r" \
+               "addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0"  \
+               :"=&r" (flag), "=r" (sum) \
+               :"1" (addr),"g" ((long)(size)),"g" (current->arch.addr_limit)); \
+       flag; })
+
+#define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ *
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the ugliness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ */
+
+#define __get_user_x(size,ret,x,ptr) \
+       asm volatile("call __get_user_" #size \
+               :"=a" (ret),"=d" (x) \
+               :"c" (ptr) \
+               :"r8")
+
+/* Careful: we have to cast the result to the type of the pointer for sign reasons */
+#define get_user(x,ptr)                                                        \
+({     unsigned long __val_gu;                                         \
+       int __ret_gu;                                                   \
+       __chk_user_ptr(ptr);                                            \
+       switch(sizeof (*(ptr))) {                                       \
+       case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;          \
+       case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;          \
+       case 4:  __get_user_x(4,__ret_gu,__val_gu,ptr); break;          \
+       case 8:  __get_user_x(8,__ret_gu,__val_gu,ptr); break;          \
+       default: __get_user_bad(); break;                               \
+       }                                                               \
+       (x) = (typeof(*(ptr)))__val_gu;                         \
+       __ret_gu;                                                       \
+})
+
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
+extern void __put_user_8(void);
+extern void __put_user_bad(void);
+
+#define __put_user_x(size,ret,x,ptr)                                   \
+       asm volatile("call __put_user_" #size                   \
+               :"=a" (ret)                                             \
+               :"c" (ptr),"d" (x)                                      \
+               :"r8")
+
+#define put_user(x,ptr)                                                        \
+  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user_unaligned __get_user
+#define __put_user_unaligned __put_user
+
+#define __put_user_nocheck(x,ptr,size)                 \
+({                                                     \
+       int __pu_err;                                   \
+       __put_user_size((x),(ptr),(size),__pu_err);     \
+       __pu_err;                                       \
+})
+
+
+#define __put_user_check(x,ptr,size)                   \
+({                                                     \
+       int __pu_err;                                   \
+       typeof(*(ptr)) __user *__pu_addr = (ptr);       \
+       switch (size) {                                 \
+       case 1: __put_user_x(1,__pu_err,x,__pu_addr); break;    \
+       case 2: __put_user_x(2,__pu_err,x,__pu_addr); break;    \
+       case 4: __put_user_x(4,__pu_err,x,__pu_addr); break;    \
+       case 8: __put_user_x(8,__pu_err,x,__pu_addr); break;    \
+       default: __put_user_bad();                      \
+       }                                               \
+       __pu_err;                                       \
+})
+
+#define __put_user_size(x,ptr,size,retval)                             \
+do {                                                                   \
+       retval = 0;                                                     \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+         case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\
+         case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\
+         case 4: __put_user_asm(x,ptr,retval,"l","k","ir",-EFAULT); break;\
+         case 8: __put_user_asm(x,ptr,retval,"q","","Zr",-EFAULT); break;\
+         default: __put_user_bad();                                    \
+       }                                                               \
+} while (0)
+
+/* FIXME: this hack is definitely wrong -AK */
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct __user *)(x))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno)       \
+       asm volatile(                                   \
+               "1:     mov"itype" %"rtype"1,%2\n"              \
+               "2:\n"                                          \
+               ".section .fixup,\"ax\"\n"                      \
+               "3:     mov %3,%0\n"                            \
+               "       jmp 2b\n"                               \
+               ".previous\n"                                   \
+               ".section __ex_table,\"a\"\n"                   \
+               "       .align 8\n"                             \
+               "       .quad 1b,3b\n"                          \
+               ".previous"                                     \
+               : "=r"(err)                                     \
+               : ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size)                         \
+({                                                             \
+       int __gu_err;                                           \
+       unsigned long __gu_val;                                 \
+       __get_user_size(__gu_val,(ptr),(size),__gu_err);        \
+       (x) = (typeof(*(ptr)))__gu_val;                 \
+       __gu_err;                                               \
+})
+
+extern int __get_user_1(void);
+extern int __get_user_2(void);
+extern int __get_user_4(void);
+extern int __get_user_8(void);
+extern int __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)                             \
+do {                                                                   \
+       retval = 0;                                                     \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+         case 1: __get_user_asm(x,ptr,retval,"b","b","=q",-EFAULT); break;\
+         case 2: __get_user_asm(x,ptr,retval,"w","w","=r",-EFAULT); break;\
+         case 4: __get_user_asm(x,ptr,retval,"l","k","=r",-EFAULT); break;\
+         case 8: __get_user_asm(x,ptr,retval,"q","","=r",-EFAULT); break;\
+         default: (x) = __get_user_bad();                              \
+       }                                                               \
+} while (0)
+
+#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno)       \
+       asm volatile(                                   \
+               "1:     mov"itype" %2,%"rtype"1\n"              \
+               "2:\n"                                          \
+               ".section .fixup,\"ax\"\n"                      \
+               "3:     mov %3,%0\n"                            \
+               "       xor"itype" %"rtype"1,%"rtype"1\n"       \
+               "       jmp 2b\n"                               \
+               ".previous\n"                                   \
+               ".section __ex_table,\"a\"\n"                   \
+               "       .align 8\n"                             \
+               "       .quad 1b,3b\n"                          \
+               ".previous"                                     \
+               : "=r"(err), ltype (x)                          \
+               : "m"(__m(addr)), "i"(errno), "0"(err))
+
+/*
+ * Copy To/From Userspace
+ */
+
+/* Handles exceptions in both to and from, but doesn't do access_ok */
+__must_check unsigned long
+copy_user_generic(void *to, const void *from, unsigned len);
+
+__must_check unsigned long
+copy_to_user(void __user *to, const void *from, unsigned len);
+__must_check unsigned long
+copy_from_user(void *to, const void __user *from, unsigned len);
+__must_check unsigned long
+copy_in_user(void __user *to, const void __user *from, unsigned len);
+
+static __always_inline __must_check
+int __copy_from_user(void *dst, const void __user *src, unsigned size)
+{ 
+       int ret = 0;
+       if (!__builtin_constant_p(size))
+               return copy_user_generic(dst,(__force void *)src,size);
+       switch (size) { 
+       case 1:__get_user_asm(*(u8*)dst,(u8 __user *)src,ret,"b","b","=q",1); 
+               return ret;
+       case 2:__get_user_asm(*(u16*)dst,(u16 __user *)src,ret,"w","w","=r",2);
+               return ret;
+       case 4:__get_user_asm(*(u32*)dst,(u32 __user *)src,ret,"l","k","=r",4);
+               return ret;
+       case 8:__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",8);
+               return ret; 
+       case 10:
+               __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
+               if (unlikely(ret)) return ret;
+               __get_user_asm(*(u16*)(8+(char*)dst),(u16 __user *)(8+(char __user *)src),ret,"w","w","=r",2);
+               return ret; 
+       case 16:
+               __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
+               if (unlikely(ret)) return ret;
+               __get_user_asm(*(u64*)(8+(char*)dst),(u64 __user *)(8+(char __user *)src),ret,"q","","=r",8);
+               return ret; 
+       default:
+               return copy_user_generic(dst,(__force void *)src,size); 
+       }
+}      
+
+static __always_inline __must_check
+int __copy_to_user(void __user *dst, const void *src, unsigned size)
+{ 
+       int ret = 0;
+       if (!__builtin_constant_p(size))
+               return copy_user_generic((__force void *)dst,src,size);
+       switch (size) { 
+       case 1:__put_user_asm(*(u8*)src,(u8 __user *)dst,ret,"b","b","iq",1); 
+               return ret;
+       case 2:__put_user_asm(*(u16*)src,(u16 __user *)dst,ret,"w","w","ir",2);
+               return ret;
+       case 4:__put_user_asm(*(u32*)src,(u32 __user *)dst,ret,"l","k","ir",4);
+               return ret;
+       case 8:__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",8);
+               return ret; 
+       case 10:
+               __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",10);
+               if (unlikely(ret)) return ret;
+               asm("":::"memory");
+               __put_user_asm(4[(u16*)src],4+(u16 __user *)dst,ret,"w","w","ir",2);
+               return ret; 
+       case 16:
+               __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",16);
+               if (unlikely(ret)) return ret;
+               asm("":::"memory");
+               __put_user_asm(1[(u64*)src],1+(u64 __user *)dst,ret,"q","","ir",8);
+               return ret; 
+       default:
+               return copy_user_generic((__force void *)dst,src,size); 
+       }
+}      
+
+static __always_inline __must_check
+int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
+{ 
+       int ret = 0;
+       if (!__builtin_constant_p(size))
+               return copy_user_generic((__force void *)dst,(__force void *)src,size);
+       switch (size) { 
+       case 1: { 
+               u8 tmp;
+               __get_user_asm(tmp,(u8 __user *)src,ret,"b","b","=q",1); 
+               if (likely(!ret))
+                       __put_user_asm(tmp,(u8 __user *)dst,ret,"b","b","iq",1); 
+               return ret;
+       }
+       case 2: { 
+               u16 tmp;
+               __get_user_asm(tmp,(u16 __user *)src,ret,"w","w","=r",2); 
+               if (likely(!ret))
+                       __put_user_asm(tmp,(u16 __user *)dst,ret,"w","w","ir",2); 
+               return ret;
+       }
+
+       case 4: { 
+               u32 tmp;
+               __get_user_asm(tmp,(u32 __user *)src,ret,"l","k","=r",4); 
+               if (likely(!ret))
+                       __put_user_asm(tmp,(u32 __user *)dst,ret,"l","k","ir",4); 
+               return ret;
+       }
+       case 8: { 
+               u64 tmp;
+               __get_user_asm(tmp,(u64 __user *)src,ret,"q","","=r",8); 
+               if (likely(!ret))
+                       __put_user_asm(tmp,(u64 __user *)dst,ret,"q","","ir",8); 
+               return ret;
+       }
+       default:
+               return copy_user_generic((__force void *)dst,(__force void *)src,size); 
+       }
+}      
+
+__must_check long 
+strncpy_from_user(char *dst, const char __user *src, long count);
+__must_check long 
+__strncpy_from_user(char *dst, const char __user *src, long count);
+__must_check long strnlen_user(const char __user *str, long n);
+__must_check long __strnlen_user(const char __user *str, long n);
+__must_check long strlen_user(const char __user *str);
+__must_check unsigned long clear_user(void __user *mem, unsigned long len);
+__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
+
+__must_check long __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size);
+
+static __must_check __always_inline int
+__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
+{
+       return copy_user_generic((__force void *)dst, src, size);
+}
+
+#endif /* _X86_64_UACCESS_H */
diff --git a/kitten/include/arch-x86_64/unistd.h b/kitten/include/arch-x86_64/unistd.h
new file mode 100644 (file)
index 0000000..9dc19bd
--- /dev/null
@@ -0,0 +1,682 @@
+#ifndef _ARCH_X86_64_UNISTD_H
+#define _ARCH_X86_64_UNISTD_H
+
+/**
+ * This file contains the system call numbers.
+ *
+ * NOTE: holes are not allowed.
+ */
+
+#ifndef __SYSCALL
+#define __SYSCALL(a,b) 
+#endif
+
+#define __NR_read                                0
+__SYSCALL(__NR_read, syscall_not_implemented)
+#define __NR_write                               1
+__SYSCALL(__NR_write, sys_write)
+#define __NR_open                                2
+__SYSCALL(__NR_open, syscall_not_implemented)
+#define __NR_close                               3
+__SYSCALL(__NR_close, syscall_not_implemented)
+#define __NR_stat                                4
+__SYSCALL(__NR_stat, syscall_not_implemented)
+#define __NR_fstat                               5
+__SYSCALL(__NR_fstat, sys_fstat)
+#define __NR_lstat                               6
+__SYSCALL(__NR_lstat, syscall_not_implemented)
+#define __NR_poll                                7
+__SYSCALL(__NR_poll, syscall_not_implemented)
+
+#define __NR_lseek                               8
+__SYSCALL(__NR_lseek, syscall_not_implemented)
+#define __NR_mmap                                9
+__SYSCALL(__NR_mmap, sys_mmap)
+#define __NR_mprotect                           10
+__SYSCALL(__NR_mprotect, syscall_not_implemented)
+#define __NR_munmap                             11
+__SYSCALL(__NR_munmap, syscall_not_implemented)
+#define __NR_brk                                12
+__SYSCALL(__NR_brk, sys_brk)
+#define __NR_rt_sigaction                       13
+__SYSCALL(__NR_rt_sigaction, syscall_not_implemented)
+#define __NR_rt_sigprocmask                     14
+__SYSCALL(__NR_rt_sigprocmask, syscall_not_implemented)
+#define __NR_rt_sigreturn                       15
+__SYSCALL(__NR_rt_sigreturn, syscall_not_implemented)
+
+#define __NR_ioctl                              16
+__SYSCALL(__NR_ioctl, syscall_not_implemented)
+#define __NR_pread64                            17
+__SYSCALL(__NR_pread64, syscall_not_implemented)
+#define __NR_pwrite64                           18
+__SYSCALL(__NR_pwrite64, syscall_not_implemented)
+#define __NR_readv                              19
+__SYSCALL(__NR_readv, syscall_not_implemented)
+#define __NR_writev                             20
+__SYSCALL(__NR_writev, syscall_not_implemented)
+#define __NR_access                             21
+__SYSCALL(__NR_access, syscall_not_implemented)
+#define __NR_pipe                               22
+__SYSCALL(__NR_pipe, syscall_not_implemented)
+#define __NR_select                             23
+__SYSCALL(__NR_select, syscall_not_implemented)
+
+#define __NR_sched_yield                        24
+__SYSCALL(__NR_sched_yield, sys_sched_yield)
+#define __NR_mremap                             25
+__SYSCALL(__NR_mremap, syscall_not_implemented)
+#define __NR_msync                              26
+__SYSCALL(__NR_msync, syscall_not_implemented)
+#define __NR_mincore                            27
+__SYSCALL(__NR_mincore, syscall_not_implemented)
+#define __NR_madvise                            28
+__SYSCALL(__NR_madvise, syscall_not_implemented)
+#define __NR_shmget                             29
+__SYSCALL(__NR_shmget, syscall_not_implemented)
+#define __NR_shmat                              30
+__SYSCALL(__NR_shmat, syscall_not_implemented)
+#define __NR_shmctl                             31
+__SYSCALL(__NR_shmctl, syscall_not_implemented)
+
+#define __NR_dup                                32
+__SYSCALL(__NR_dup, syscall_not_implemented)
+#define __NR_dup2                               33
+__SYSCALL(__NR_dup2, syscall_not_implemented)
+#define __NR_pause                              34
+__SYSCALL(__NR_pause, syscall_not_implemented)
+#define __NR_nanosleep                          35
+__SYSCALL(__NR_nanosleep, sys_nanosleep)
+#define __NR_getitimer                          36
+__SYSCALL(__NR_getitimer, syscall_not_implemented)
+#define __NR_alarm                              37
+__SYSCALL(__NR_alarm, syscall_not_implemented)
+#define __NR_setitimer                          38
+__SYSCALL(__NR_setitimer, syscall_not_implemented)
+#define __NR_getpid                             39
+__SYSCALL(__NR_getpid, syscall_not_implemented)
+
+#define __NR_sendfile                           40
+__SYSCALL(__NR_sendfile, syscall_not_implemented)
+#define __NR_socket                             41
+__SYSCALL(__NR_socket, syscall_not_implemented)
+#define __NR_connect                            42
+__SYSCALL(__NR_connect, syscall_not_implemented)
+#define __NR_accept                             43
+__SYSCALL(__NR_accept, syscall_not_implemented)
+#define __NR_sendto                             44
+__SYSCALL(__NR_sendto, syscall_not_implemented)
+#define __NR_recvfrom                           45
+__SYSCALL(__NR_recvfrom, syscall_not_implemented)
+#define __NR_sendmsg                            46
+__SYSCALL(__NR_sendmsg, syscall_not_implemented)
+#define __NR_recvmsg                            47
+__SYSCALL(__NR_recvmsg, syscall_not_implemented)
+
+#define __NR_shutdown                           48
+__SYSCALL(__NR_shutdown, syscall_not_implemented)
+#define __NR_bind                               49
+__SYSCALL(__NR_bind, syscall_not_implemented)
+#define __NR_listen                             50
+__SYSCALL(__NR_listen, syscall_not_implemented)
+#define __NR_getsockname                        51
+__SYSCALL(__NR_getsockname, syscall_not_implemented)
+#define __NR_getpeername                        52
+__SYSCALL(__NR_getpeername, syscall_not_implemented)
+#define __NR_socketpair                         53
+__SYSCALL(__NR_socketpair, syscall_not_implemented)
+#define __NR_setsockopt                         54
+__SYSCALL(__NR_setsockopt, syscall_not_implemented)
+#define __NR_getsockopt                         55
+__SYSCALL(__NR_getsockopt, syscall_not_implemented)
+
+#define __NR_clone                              56
+__SYSCALL(__NR_clone, syscall_not_implemented)
+#define __NR_fork                               57
+__SYSCALL(__NR_fork, syscall_not_implemented)
+#define __NR_vfork                              58
+__SYSCALL(__NR_vfork, syscall_not_implemented)
+#define __NR_execve                             59
+__SYSCALL(__NR_execve, syscall_not_implemented)
+#define __NR_exit                               60
+__SYSCALL(__NR_exit, sys_task_exit)
+#define __NR_wait4                              61
+__SYSCALL(__NR_wait4, syscall_not_implemented)
+#define __NR_kill                               62
+__SYSCALL(__NR_kill, syscall_not_implemented)
+#define __NR_uname                              63
+__SYSCALL(__NR_uname, sys_uname)
+
+#define __NR_semget                             64
+__SYSCALL(__NR_semget, syscall_not_implemented)
+#define __NR_semop                              65
+__SYSCALL(__NR_semop, syscall_not_implemented)
+#define __NR_semctl                             66
+__SYSCALL(__NR_semctl, syscall_not_implemented)
+#define __NR_shmdt                              67
+__SYSCALL(__NR_shmdt, syscall_not_implemented)
+#define __NR_msgget                             68
+__SYSCALL(__NR_msgget, syscall_not_implemented)
+#define __NR_msgsnd                             69
+__SYSCALL(__NR_msgsnd, syscall_not_implemented)
+#define __NR_msgrcv                             70
+__SYSCALL(__NR_msgrcv, syscall_not_implemented)
+#define __NR_msgctl                             71
+__SYSCALL(__NR_msgctl, syscall_not_implemented)
+
+#define __NR_fcntl                              72
+__SYSCALL(__NR_fcntl, syscall_not_implemented)
+#define __NR_flock                              73
+__SYSCALL(__NR_flock, syscall_not_implemented)
+#define __NR_fsync                              74
+__SYSCALL(__NR_fsync, syscall_not_implemented)
+#define __NR_fdatasync                          75
+__SYSCALL(__NR_fdatasync, syscall_not_implemented)
+#define __NR_truncate                           76
+__SYSCALL(__NR_truncate, syscall_not_implemented)
+#define __NR_ftruncate                          77
+__SYSCALL(__NR_ftruncate, syscall_not_implemented)
+#define __NR_getdents                           78
+__SYSCALL(__NR_getdents, syscall_not_implemented)
+#define __NR_getcwd                             79
+__SYSCALL(__NR_getcwd, syscall_not_implemented)
+
+#define __NR_chdir                              80
+__SYSCALL(__NR_chdir, syscall_not_implemented)
+#define __NR_fchdir                             81
+__SYSCALL(__NR_fchdir, syscall_not_implemented)
+#define __NR_rename                             82
+__SYSCALL(__NR_rename, syscall_not_implemented)
+#define __NR_mkdir                              83
+__SYSCALL(__NR_mkdir, syscall_not_implemented)
+#define __NR_rmdir                              84
+__SYSCALL(__NR_rmdir, syscall_not_implemented)
+#define __NR_creat                              85
+__SYSCALL(__NR_creat, syscall_not_implemented)
+#define __NR_link                               86
+__SYSCALL(__NR_link, syscall_not_implemented)
+#define __NR_unlink                             87
+__SYSCALL(__NR_unlink, syscall_not_implemented)
+
+#define __NR_symlink                            88
+__SYSCALL(__NR_symlink, syscall_not_implemented)
+#define __NR_readlink                           89
+__SYSCALL(__NR_readlink, syscall_not_implemented)
+#define __NR_chmod                              90
+__SYSCALL(__NR_chmod, syscall_not_implemented)
+#define __NR_fchmod                             91
+__SYSCALL(__NR_fchmod, syscall_not_implemented)
+#define __NR_chown                              92
+__SYSCALL(__NR_chown, syscall_not_implemented)
+#define __NR_fchown                             93
+__SYSCALL(__NR_fchown, syscall_not_implemented)
+#define __NR_lchown                             94
+__SYSCALL(__NR_lchown, syscall_not_implemented)
+#define __NR_umask                              95
+__SYSCALL(__NR_umask, syscall_not_implemented)
+
+#define __NR_gettimeofday                       96
+__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+#define __NR_getrlimit                          97
+__SYSCALL(__NR_getrlimit, syscall_not_implemented)
+#define __NR_getrusage                          98
+__SYSCALL(__NR_getrusage, syscall_not_implemented)
+#define __NR_sysinfo                            99
+__SYSCALL(__NR_sysinfo, syscall_not_implemented)
+#define __NR_times                             100
+__SYSCALL(__NR_times, syscall_not_implemented)
+#define __NR_ptrace                            101
+__SYSCALL(__NR_ptrace, syscall_not_implemented)
+#define __NR_getuid                            102
+__SYSCALL(__NR_getuid, sys_getuid)
+#define __NR_syslog                            103
+__SYSCALL(__NR_syslog, syscall_not_implemented)
+
+/* at the very end the stuff that never runs during the benchmarks */
+#define __NR_getgid                            104
+__SYSCALL(__NR_getgid, sys_getgid)
+#define __NR_setuid                            105
+__SYSCALL(__NR_setuid, syscall_not_implemented)
+#define __NR_setgid                            106
+__SYSCALL(__NR_setgid, syscall_not_implemented)
+#define __NR_geteuid                           107
+__SYSCALL(__NR_geteuid, sys_getuid)
+#define __NR_getegid                           108
+__SYSCALL(__NR_getegid, sys_getgid)
+#define __NR_setpgid                           109
+__SYSCALL(__NR_setpgid, syscall_not_implemented)
+#define __NR_getppid                           110
+__SYSCALL(__NR_getppid, syscall_not_implemented)
+#define __NR_getpgrp                           111
+__SYSCALL(__NR_getpgrp, syscall_not_implemented)
+
+#define __NR_setsid                            112
+__SYSCALL(__NR_setsid, syscall_not_implemented)
+#define __NR_setreuid                          113
+__SYSCALL(__NR_setreuid, syscall_not_implemented)
+#define __NR_setregid                          114
+__SYSCALL(__NR_setregid, syscall_not_implemented)
+#define __NR_getgroups                         115
+__SYSCALL(__NR_getgroups, syscall_not_implemented)
+#define __NR_setgroups                         116
+__SYSCALL(__NR_setgroups, syscall_not_implemented)
+#define __NR_setresuid                         117
+__SYSCALL(__NR_setresuid, syscall_not_implemented)
+#define __NR_getresuid                         118
+__SYSCALL(__NR_getresuid, syscall_not_implemented)
+#define __NR_setresgid                         119
+__SYSCALL(__NR_setresgid, syscall_not_implemented)
+
+#define __NR_getresgid                         120
+__SYSCALL(__NR_getresgid, syscall_not_implemented)
+#define __NR_getpgid                           121
+__SYSCALL(__NR_getpgid, syscall_not_implemented)
+#define __NR_setfsuid                          122
+__SYSCALL(__NR_setfsuid, syscall_not_implemented)
+#define __NR_setfsgid                          123
+__SYSCALL(__NR_setfsgid, syscall_not_implemented)
+#define __NR_getsid                            124
+__SYSCALL(__NR_getsid, syscall_not_implemented)
+#define __NR_capget                            125
+__SYSCALL(__NR_capget, syscall_not_implemented)
+#define __NR_capset                            126
+__SYSCALL(__NR_capset, syscall_not_implemented)
+
+#define __NR_rt_sigpending                     127
+__SYSCALL(__NR_rt_sigpending, syscall_not_implemented)
+#define __NR_rt_sigtimedwait                   128
+__SYSCALL(__NR_rt_sigtimedwait, syscall_not_implemented)
+#define __NR_rt_sigqueueinfo                   129
+__SYSCALL(__NR_rt_sigqueueinfo, syscall_not_implemented)
+#define __NR_rt_sigsuspend                     130
+__SYSCALL(__NR_rt_sigsuspend, syscall_not_implemented)
+#define __NR_sigaltstack                       131
+__SYSCALL(__NR_sigaltstack, syscall_not_implemented)
+#define __NR_utime                             132
+__SYSCALL(__NR_utime, syscall_not_implemented)
+#define __NR_mknod                             133
+__SYSCALL(__NR_mknod, syscall_not_implemented)
+
+/* Only needed for a.out */
+#define __NR_uselib                            134
+__SYSCALL(__NR_uselib, syscall_not_implemented)
+#define __NR_personality                       135
+__SYSCALL(__NR_personality, syscall_not_implemented)
+
+#define __NR_ustat                             136
+__SYSCALL(__NR_ustat, syscall_not_implemented)
+#define __NR_statfs                            137
+__SYSCALL(__NR_statfs, syscall_not_implemented)
+#define __NR_fstatfs                           138
+__SYSCALL(__NR_fstatfs, syscall_not_implemented)
+#define __NR_sysfs                             139
+__SYSCALL(__NR_sysfs, syscall_not_implemented)
+
+#define __NR_getpriority                       140
+__SYSCALL(__NR_getpriority, syscall_not_implemented)
+#define __NR_setpriority                       141
+__SYSCALL(__NR_setpriority, syscall_not_implemented)
+#define __NR_sched_setparam                    142
+__SYSCALL(__NR_sched_setparam, syscall_not_implemented)
+#define __NR_sched_getparam                    143
+__SYSCALL(__NR_sched_getparam, syscall_not_implemented)
+#define __NR_sched_setscheduler                144
+__SYSCALL(__NR_sched_setscheduler, syscall_not_implemented)
+#define __NR_sched_getscheduler                145
+__SYSCALL(__NR_sched_getscheduler, syscall_not_implemented)
+#define __NR_sched_get_priority_max            146
+__SYSCALL(__NR_sched_get_priority_max, syscall_not_implemented)
+#define __NR_sched_get_priority_min            147
+__SYSCALL(__NR_sched_get_priority_min, syscall_not_implemented)
+#define __NR_sched_rr_get_interval             148
+__SYSCALL(__NR_sched_rr_get_interval, syscall_not_implemented)
+
+#define __NR_mlock                             149
+__SYSCALL(__NR_mlock, syscall_not_implemented)
+#define __NR_munlock                           150
+__SYSCALL(__NR_munlock, syscall_not_implemented)
+#define __NR_mlockall                          151
+__SYSCALL(__NR_mlockall, syscall_not_implemented)
+#define __NR_munlockall                        152
+__SYSCALL(__NR_munlockall, syscall_not_implemented)
+
+#define __NR_vhangup                           153
+__SYSCALL(__NR_vhangup, syscall_not_implemented)
+
+#define __NR_modify_ldt                        154
+__SYSCALL(__NR_modify_ldt, syscall_not_implemented)
+
+#define __NR_pivot_root                        155
+__SYSCALL(__NR_pivot_root, syscall_not_implemented)
+
+#define __NR__sysctl                           156
+__SYSCALL(__NR__sysctl, syscall_not_implemented)
+
+#define __NR_prctl                             157
+__SYSCALL(__NR_prctl, syscall_not_implemented)
+#define __NR_arch_prctl                        158
+__SYSCALL(__NR_arch_prctl, sys_arch_prctl)
+
+#define __NR_adjtimex                          159
+__SYSCALL(__NR_adjtimex, syscall_not_implemented)
+
+#define __NR_setrlimit                         160
+__SYSCALL(__NR_setrlimit, syscall_not_implemented)
+
+#define __NR_chroot                            161
+__SYSCALL(__NR_chroot, syscall_not_implemented)
+
+#define __NR_sync                              162
+__SYSCALL(__NR_sync, syscall_not_implemented)
+
+#define __NR_acct                              163
+__SYSCALL(__NR_acct, syscall_not_implemented)
+
+#define __NR_settimeofday                      164
+__SYSCALL(__NR_settimeofday, sys_settimeofday)
+
+#define __NR_mount                             165
+__SYSCALL(__NR_mount, syscall_not_implemented)
+#define __NR_umount2                           166
+__SYSCALL(__NR_umount2, syscall_not_implemented)
+
+#define __NR_swapon                            167
+__SYSCALL(__NR_swapon, syscall_not_implemented)
+#define __NR_swapoff                           168
+__SYSCALL(__NR_swapoff, syscall_not_implemented)
+
+#define __NR_reboot                            169
+__SYSCALL(__NR_reboot, syscall_not_implemented)
+
+#define __NR_sethostname                       170
+__SYSCALL(__NR_sethostname, syscall_not_implemented)
+#define __NR_setdomainname                     171
+__SYSCALL(__NR_setdomainname, syscall_not_implemented)
+
+#define __NR_iopl                              172
+__SYSCALL(__NR_iopl, syscall_not_implemented)
+#define __NR_ioperm                            173
+__SYSCALL(__NR_ioperm, syscall_not_implemented)
+
+#define __NR_create_module                     174
+__SYSCALL(__NR_create_module, syscall_not_implemented)
+#define __NR_init_module                       175
+__SYSCALL(__NR_init_module, syscall_not_implemented)
+#define __NR_delete_module                     176
+__SYSCALL(__NR_delete_module, syscall_not_implemented)
+#define __NR_get_kernel_syms                   177
+__SYSCALL(__NR_get_kernel_syms, syscall_not_implemented)
+#define __NR_query_module                      178
+__SYSCALL(__NR_query_module, syscall_not_implemented)
+
+#define __NR_quotactl                          179
+__SYSCALL(__NR_quotactl, syscall_not_implemented)
+
+#define __NR_nfsservctl                        180
+__SYSCALL(__NR_nfsservctl, syscall_not_implemented)
+
+#define __NR_getpmsg                           181     /* reserved for LiS/STREAMS */
+__SYSCALL(__NR_getpmsg, syscall_not_implemented)
+#define __NR_putpmsg                           182     /* reserved for LiS/STREAMS */
+__SYSCALL(__NR_putpmsg, syscall_not_implemented)
+
+#define __NR_afs_syscall                       183     /* reserved for AFS */ 
+__SYSCALL(__NR_afs_syscall, syscall_not_implemented)
+
+#define __NR_tuxcall                   184 /* reserved for tux */
+__SYSCALL(__NR_tuxcall, syscall_not_implemented)
+
+#define __NR_security                  185
+__SYSCALL(__NR_security, syscall_not_implemented)
+
+#define __NR_gettid            186
+__SYSCALL(__NR_gettid, syscall_not_implemented)
+
+#define __NR_readahead         187
+__SYSCALL(__NR_readahead, syscall_not_implemented)
+#define __NR_setxattr          188
+__SYSCALL(__NR_setxattr, syscall_not_implemented)
+#define __NR_lsetxattr         189
+__SYSCALL(__NR_lsetxattr, syscall_not_implemented)
+#define __NR_fsetxattr         190
+__SYSCALL(__NR_fsetxattr, syscall_not_implemented)
+#define __NR_getxattr          191
+__SYSCALL(__NR_getxattr, syscall_not_implemented)
+#define __NR_lgetxattr         192
+__SYSCALL(__NR_lgetxattr, syscall_not_implemented)
+#define __NR_fgetxattr         193
+__SYSCALL(__NR_fgetxattr, syscall_not_implemented)
+#define __NR_listxattr         194
+__SYSCALL(__NR_listxattr, syscall_not_implemented)
+#define __NR_llistxattr                195
+__SYSCALL(__NR_llistxattr, syscall_not_implemented)
+#define __NR_flistxattr                196
+__SYSCALL(__NR_flistxattr, syscall_not_implemented)
+#define __NR_removexattr       197
+__SYSCALL(__NR_removexattr, syscall_not_implemented)
+#define __NR_lremovexattr      198
+__SYSCALL(__NR_lremovexattr, syscall_not_implemented)
+#define __NR_fremovexattr      199
+__SYSCALL(__NR_fremovexattr, syscall_not_implemented)
+#define __NR_tkill     200
+__SYSCALL(__NR_tkill, syscall_not_implemented)
+#define __NR_time      201
+__SYSCALL(__NR_time, sys_time)
+#define __NR_futex     202
+__SYSCALL(__NR_futex, syscall_not_implemented)
+#define __NR_sched_setaffinity    203
+__SYSCALL(__NR_sched_setaffinity, syscall_not_implemented)
+#define __NR_sched_getaffinity     204
+__SYSCALL(__NR_sched_getaffinity, syscall_not_implemented)
+#define __NR_set_thread_area   205
+__SYSCALL(__NR_set_thread_area, syscall_not_implemented)
+#define __NR_io_setup  206
+__SYSCALL(__NR_io_setup, syscall_not_implemented)
+#define __NR_io_destroy        207
+__SYSCALL(__NR_io_destroy, syscall_not_implemented)
+#define __NR_io_getevents      208
+__SYSCALL(__NR_io_getevents, syscall_not_implemented)
+#define __NR_io_submit 209
+__SYSCALL(__NR_io_submit, syscall_not_implemented)
+#define __NR_io_cancel 210
+__SYSCALL(__NR_io_cancel, syscall_not_implemented)
+#define __NR_get_thread_area   211
+__SYSCALL(__NR_get_thread_area, syscall_not_implemented)
+#define __NR_lookup_dcookie    212
+__SYSCALL(__NR_lookup_dcookie, syscall_not_implemented)
+#define __NR_epoll_create      213
+__SYSCALL(__NR_epoll_create, syscall_not_implemented)
+#define __NR_epoll_ctl_old     214
+__SYSCALL(__NR_epoll_ctl_old, syscall_not_implemented)
+#define __NR_epoll_wait_old    215
+__SYSCALL(__NR_epoll_wait_old, syscall_not_implemented)
+#define __NR_remap_file_pages  216
+__SYSCALL(__NR_remap_file_pages, syscall_not_implemented)
+#define __NR_getdents64        217
+__SYSCALL(__NR_getdents64, syscall_not_implemented)
+#define __NR_set_tid_address   218
+__SYSCALL(__NR_set_tid_address, syscall_not_implemented)
+#define __NR_restart_syscall   219
+__SYSCALL(__NR_restart_syscall, syscall_not_implemented)
+#define __NR_semtimedop                220
+__SYSCALL(__NR_semtimedop, syscall_not_implemented)
+#define __NR_fadvise64         221
+__SYSCALL(__NR_fadvise64, syscall_not_implemented)
+#define __NR_timer_create              222
+__SYSCALL(__NR_timer_create, syscall_not_implemented)
+#define __NR_timer_settime             223
+__SYSCALL(__NR_timer_settime, syscall_not_implemented)
+#define __NR_timer_gettime             224
+__SYSCALL(__NR_timer_gettime, syscall_not_implemented)
+#define __NR_timer_getoverrun          225
+__SYSCALL(__NR_timer_getoverrun, syscall_not_implemented)
+#define __NR_timer_delete      226
+__SYSCALL(__NR_timer_delete, syscall_not_implemented)
+#define __NR_clock_settime     227
+__SYSCALL(__NR_clock_settime, syscall_not_implemented)
+#define __NR_clock_gettime     228
+__SYSCALL(__NR_clock_gettime, syscall_not_implemented)
+#define __NR_clock_getres      229
+__SYSCALL(__NR_clock_getres, syscall_not_implemented)
+#define __NR_clock_nanosleep   230
+__SYSCALL(__NR_clock_nanosleep, syscall_not_implemented)
+#define __NR_exit_group                231
+__SYSCALL(__NR_exit_group, syscall_not_implemented)
+#define __NR_epoll_wait                232
+__SYSCALL(__NR_epoll_wait, syscall_not_implemented)
+#define __NR_epoll_ctl         233
+__SYSCALL(__NR_epoll_ctl, syscall_not_implemented)
+#define __NR_tgkill            234
+__SYSCALL(__NR_tgkill, syscall_not_implemented)
+#define __NR_utimes            235
+__SYSCALL(__NR_utimes, syscall_not_implemented)
+#define __NR_vserver           236
+__SYSCALL(__NR_vserver, syscall_not_implemented)
+#define __NR_mbind             237
+__SYSCALL(__NR_mbind, syscall_not_implemented)
+#define __NR_set_mempolicy     238
+__SYSCALL(__NR_set_mempolicy, syscall_not_implemented)
+#define __NR_get_mempolicy     239
+__SYSCALL(__NR_get_mempolicy, syscall_not_implemented)
+#define __NR_mq_open           240
+__SYSCALL(__NR_mq_open, syscall_not_implemented)
+#define __NR_mq_unlink                 241
+__SYSCALL(__NR_mq_unlink, syscall_not_implemented)
+#define __NR_mq_timedsend      242
+__SYSCALL(__NR_mq_timedsend, syscall_not_implemented)
+#define __NR_mq_timedreceive   243
+__SYSCALL(__NR_mq_timedreceive, syscall_not_implemented)
+#define __NR_mq_notify                 244
+__SYSCALL(__NR_mq_notify, syscall_not_implemented)
+#define __NR_mq_getsetattr     245
+__SYSCALL(__NR_mq_getsetattr, syscall_not_implemented)
+#define __NR_kexec_load        246
+__SYSCALL(__NR_kexec_load, syscall_not_implemented)
+#define __NR_waitid            247
+__SYSCALL(__NR_waitid, syscall_not_implemented)
+#define __NR_add_key           248
+__SYSCALL(__NR_add_key, syscall_not_implemented)
+#define __NR_request_key       249
+__SYSCALL(__NR_request_key, syscall_not_implemented)
+#define __NR_keyctl            250
+__SYSCALL(__NR_keyctl, syscall_not_implemented)
+#define __NR_ioprio_set                251
+__SYSCALL(__NR_ioprio_set, syscall_not_implemented)
+#define __NR_ioprio_get                252
+__SYSCALL(__NR_ioprio_get, syscall_not_implemented)
+#define __NR_inotify_init      253
+__SYSCALL(__NR_inotify_init, syscall_not_implemented)
+#define __NR_inotify_add_watch 254
+__SYSCALL(__NR_inotify_add_watch, syscall_not_implemented)
+#define __NR_inotify_rm_watch  255
+__SYSCALL(__NR_inotify_rm_watch, syscall_not_implemented)
+#define __NR_migrate_pages     256
+__SYSCALL(__NR_migrate_pages, syscall_not_implemented)
+#define __NR_openat            257
+__SYSCALL(__NR_openat, syscall_not_implemented)
+#define __NR_mkdirat           258
+__SYSCALL(__NR_mkdirat, syscall_not_implemented)
+#define __NR_mknodat           259
+__SYSCALL(__NR_mknodat, syscall_not_implemented)
+#define __NR_fchownat          260
+__SYSCALL(__NR_fchownat, syscall_not_implemented)
+#define __NR_futimesat         261
+__SYSCALL(__NR_futimesat, syscall_not_implemented)
+#define __NR_newfstatat                262
+__SYSCALL(__NR_newfstatat, syscall_not_implemented)
+#define __NR_unlinkat          263
+__SYSCALL(__NR_unlinkat, syscall_not_implemented)
+#define __NR_renameat          264
+__SYSCALL(__NR_renameat, syscall_not_implemented)
+#define __NR_linkat            265
+__SYSCALL(__NR_linkat, syscall_not_implemented)
+#define __NR_symlinkat         266
+__SYSCALL(__NR_symlinkat, syscall_not_implemented)
+#define __NR_readlinkat                267
+__SYSCALL(__NR_readlinkat, syscall_not_implemented)
+#define __NR_fchmodat          268
+__SYSCALL(__NR_fchmodat, syscall_not_implemented)
+#define __NR_faccessat         269
+__SYSCALL(__NR_faccessat, syscall_not_implemented)
+#define __NR_pselect6          270
+__SYSCALL(__NR_pselect6, syscall_not_implemented)
+#define __NR_ppoll             271
+__SYSCALL(__NR_ppoll,  syscall_not_implemented)
+#define __NR_unshare           272
+__SYSCALL(__NR_unshare,        syscall_not_implemented)
+#define __NR_set_robust_list   273
+__SYSCALL(__NR_set_robust_list, syscall_not_implemented)
+#define __NR_get_robust_list   274
+__SYSCALL(__NR_get_robust_list, syscall_not_implemented)
+#define __NR_splice            275
+__SYSCALL(__NR_splice, syscall_not_implemented)
+#define __NR_tee               276
+__SYSCALL(__NR_tee, syscall_not_implemented)
+#define __NR_sync_file_range   277
+__SYSCALL(__NR_sync_file_range, syscall_not_implemented)
+#define __NR_vmsplice          278
+__SYSCALL(__NR_vmsplice, syscall_not_implemented)
+#define __NR_move_pages                279
+__SYSCALL(__NR_move_pages, syscall_not_implemented)
+#define __NR_utimensat         280
+__SYSCALL(__NR_utimensat, syscall_not_implemented)
+#define __IGNORE_getcpu                /* implemented as a vsyscall */
+#define __NR_epoll_pwait       281
+__SYSCALL(__NR_epoll_pwait, syscall_not_implemented)
+#define __NR_signalfd          282
+__SYSCALL(__NR_signalfd, syscall_not_implemented)
+#define __NR_timerfd           283
+__SYSCALL(__NR_timerfd, syscall_not_implemented)
+#define __NR_eventfd           284
+__SYSCALL(__NR_eventfd, syscall_not_implemented)
+#define __NR_fallocate         285
+__SYSCALL(__NR_fallocate, syscall_not_implemented)
+
+/**
+ * LWK specific system calls.
+ */
+#define __NR_pmem_add          286
+__SYSCALL(__NR_pmem_add, sys_pmem_add)
+#define __NR_pmem_update       287
+__SYSCALL(__NR_pmem_update, sys_pmem_update)
+#define __NR_pmem_query                288
+__SYSCALL(__NR_pmem_query, sys_pmem_query)
+#define __NR_pmem_alloc                289
+__SYSCALL(__NR_pmem_alloc, sys_pmem_alloc)
+
+#define __NR_aspace_get_myid   290
+__SYSCALL(__NR_aspace_get_myid, sys_aspace_get_myid)
+#define __NR_aspace_create     291
+__SYSCALL(__NR_aspace_create, sys_aspace_create)
+#define __NR_aspace_destroy    292
+__SYSCALL(__NR_aspace_destroy, sys_aspace_destroy)
+#define __NR_aspace_find_hole  293
+__SYSCALL(__NR_aspace_find_hole, sys_aspace_find_hole)
+#define __NR_aspace_add_region 294
+__SYSCALL(__NR_aspace_add_region, sys_aspace_add_region)
+#define __NR_aspace_del_region 295
+__SYSCALL(__NR_aspace_del_region, sys_aspace_del_region)
+#define __NR_aspace_map_pmem   296
+__SYSCALL(__NR_aspace_map_pmem, sys_aspace_map_pmem)
+#define __NR_aspace_unmap_pmem 297
+__SYSCALL(__NR_aspace_unmap_pmem, sys_aspace_unmap_pmem)
+#define __NR_aspace_smartmap   298
+__SYSCALL(__NR_aspace_smartmap, sys_aspace_smartmap)
+#define __NR_aspace_unsmartmap 299
+__SYSCALL(__NR_aspace_unsmartmap, sys_aspace_unsmartmap)
+#define __NR_aspace_dump2console 300
+__SYSCALL(__NR_aspace_dump2console, sys_aspace_dump2console)
+
+#define __NR_task_get_myid      301
+__SYSCALL(__NR_task_get_myid, sys_task_get_myid)
+#define __NR_task_create        302
+__SYSCALL(__NR_task_create, sys_task_create)
+#define __NR_task_exit          303
+__SYSCALL(__NR_task_exit, sys_task_exit)
+#define __NR_task_yield         304
+__SYSCALL(__NR_task_yield, sys_task_yield)
+
+#define __NR_elf_hwcap          305
+__SYSCALL(__NR_task_yield, sys_elf_hwcap)
+
+#endif
diff --git a/kitten/include/arch-x86_64/user.h b/kitten/include/arch-x86_64/user.h
new file mode 100644 (file)
index 0000000..d5c1d56
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef _X86_64_USER_H
+#define _X86_64_USER_H
+
+#include <arch/types.h>
+#include <arch/page.h>
+/* Core file format: The core file is written in such a way that gdb
+   can understand it and provide useful information to the user.
+   There are quite a number of obstacles to being able to view the
+   contents of the floating point registers, and until these are
+   solved you will not be able to view the contents of them.
+   Actually, you can read in the core file and look at the contents of
+   the user struct to find out what the floating point registers
+   contain.
+
+   The actual file contents are as follows:
+   UPAGE: 1 page consisting of a user struct that tells gdb what is present
+   in the file.  Directly after this is a copy of the task_struct, which
+   is currently not used by gdb, but it may come in useful at some point.
+   All of the registers are stored as part of the upage.  The upage should
+   always be only one page.
+   DATA: The data area is stored.  We use current->end_text to
+   current->brk to pick up all of the user variables, plus any memory
+   that may have been malloced.  No attempt is made to determine if a page
+   is demand-zero or if a page is totally unused, we just cover the entire
+   range.  All of the addresses are rounded in such a way that an integral
+   number of pages is written.
+   STACK: We need the stack information in order to get a meaningful
+   backtrace.  We need to write the data from (esp) to
+   current->start_stack, so we round each of these off in order to be able
+   to write an integer number of pages.
+   The minimum core file size is 3 pages, or 12288 bytes.  */
+
+/*
+ * Pentium III FXSR, SSE support
+ *     Gareth Hughes <gareth@valinux.com>, May 2000
+ *
+ * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
+ * interacting with the FXSR-format floating point environment.  Floating
+ * point data can be accessed in the regular format in the usual manner,
+ * and both the standard and SIMD floating point data can be accessed via
+ * the new ptrace requests.  In either case, changes to the FPU environment
+ * will be reflected in the task's state as expected.
+ * 
+ * x86-64 support by Andi Kleen.
+ */
+
+/* This matches the 64bit FXSAVE format as defined by AMD. It is the same
+   as the 32bit format defined by Intel, except that the selector:offset pairs for
+   data and eip are replaced with flat 64bit pointers. */ 
+struct user_i387_struct {
+       unsigned short  cwd;
+       unsigned short  swd;
+       unsigned short  twd; /* Note this is not the same as the 32bit/x87/FSAVE twd */
+       unsigned short  fop;
+       __u64   rip;
+       __u64   rdp;
+       __u32   mxcsr;
+       __u32   mxcsr_mask;
+       __u32   st_space[32];   /* 8*16 bytes for each FP-reg = 128 bytes */
+       __u32   xmm_space[64];  /* 16*16 bytes for each XMM-reg = 256 bytes */
+       __u32   padding[24];
+};
+
+/*
+ * Segment register layout in coredumps.
+ */
+struct user_regs_struct {
+       unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
+       unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
+       unsigned long rip,cs,eflags;
+       unsigned long rsp,ss;
+       unsigned long fs_base, gs_base;
+       unsigned long ds,es,fs,gs; 
+}; 
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+   this will be used by gdb to figure out where the data and stack segments
+   are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+   from the ptrace(3,...) function.  */
+  struct user_regs_struct regs;                /* Where the registers are actually stored */
+/* ptrace does not yet supply these.  Someday.... */
+  int u_fpvalid;               /* True if math co-processor being used. */
+                                /* for this mess. Not yet used. */
+  int pad0;
+  struct user_i387_struct i387;        /* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+  unsigned long int u_tsize;   /* Text segment size (pages). */
+  unsigned long int u_dsize;   /* Data segment size (pages). */
+  unsigned long int u_ssize;   /* Stack segment size (pages). */
+  unsigned long start_code;     /* Starting virtual address of text. */
+  unsigned long start_stack;   /* Starting virtual address of stack area.
+                                  This is actually the bottom of the stack,
+                                  the top of the stack is always found in the
+                                  esp register.  */
+  long int signal;                     /* Signal that caused the core dump. */
+  int reserved;                        /* No longer used */
+  int pad1;
+  struct user_pt_regs * u_ar0; /* Used by gdb to help find the values for */
+                               /* the registers. */
+  struct user_i387_struct* u_fpstate;  /* Math Co-processor pointer. */
+  unsigned long magic;         /* To uniquely identify a core file */
+  char u_comm[32];             /* User command that was responsible */
+  unsigned long u_debugreg[8];
+  unsigned long error_code; /* CPU error code or 0 */
+  unsigned long fault_address; /* CR3 or 0 */
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _X86_64_USER_H */
diff --git a/kitten/include/arch-x86_64/vsyscall.h b/kitten/include/arch-x86_64/vsyscall.h
new file mode 100644 (file)
index 0000000..ae5d0cc
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _ASM_X86_64_VSYSCALL_H_
+#define _ASM_X86_64_VSYSCALL_H_
+
+enum vsyscall_num {
+       __NR_vgettimeofday,
+       __NR_vtime,
+       __NR_vgetcpu,
+};
+
+#define VSYSCALL_START (-10UL << 20)
+#define VSYSCALL_SIZE 1024
+#define VSYSCALL_END (-2UL << 20)
+#define VSYSCALL_MAPPED_PAGES 1
+#define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr))
+
+#ifdef __KERNEL__
+#include <lwk/init.h>
+
+void __init vsyscall_map(void);
+void __init vsyscall_init(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_64_VSYSCALL_H_ */
diff --git a/kitten/include/arch-x86_64/xcall.h b/kitten/include/arch-x86_64/xcall.h
new file mode 100644 (file)
index 0000000..eb3dd90
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _X86_64_XCALL_H
+#define _X86_64_XCALL_H
+
+#include <arch/ptrace.h>
+
+void arch_xcall_function_interrupt(struct pt_regs *regs, unsigned int vector);
+void arch_xcall_reschedule_interrupt(struct pt_regs *regs, unsigned int vector);
+
+#endif
diff --git a/kitten/include/lwk/aspace.h b/kitten/include/lwk/aspace.h
new file mode 100644 (file)
index 0000000..5ecac03
--- /dev/null
@@ -0,0 +1,239 @@
+/* Copyright (c) 2007,2008 Sandia National Laboratories */
+
+#ifndef _LWK_ASPACE_H
+#define _LWK_ASPACE_H
+
+#include <lwk/types.h>
+#include <lwk/idspace.h>
+#include <arch/aspace.h>
+
+/**
+ * Valid user-space created address space IDs are in interval
+ * [ASPACE_MIN_ID, ASPACE_MAX_ID].
+ */
+#define ASPACE_MIN_ID     0
+#define ASPACE_MAX_ID     4094
+
+/**
+ * The address space ID to use for the init_task.
+ * Put it at the top of the space to keep it out of the way.
+ */
+#define INIT_ASPACE_ID    ASPACE_MAX_ID
+
+/**
+ * Protection and memory type flags.
+ */
+#define VM_READ           (1 << 0)
+#define VM_WRITE          (1 << 1)
+#define VM_EXEC           (1 << 2)
+#define VM_NOCACHE        (1 << 3)
+#define VM_WRITETHRU      (1 << 4)
+#define VM_GLOBAL         (1 << 5)
+#define VM_USER           (1 << 6)
+#define VM_KERNEL         (1 << 7)
+#define VM_HEAP           (1 << 8)
+#define VM_SMARTMAP       (1 << 9)
+typedef unsigned long vmflags_t;
+
+/**
+ * Page sizes.
+ */
+#define VM_PAGE_4KB       (1 << 12)
+#define VM_PAGE_2MB       (1 << 21)
+#define VM_PAGE_1GB       (1 << 30)
+typedef unsigned long vmpagesize_t;
+
+/**
+ * Core address space management API.
+ * These are accessible from both kernel-space and user-space (via syscalls).
+ */
+extern int aspace_get_myid(id_t *id);
+extern int aspace_create(id_t id_request, const char *name, id_t *id);
+extern int aspace_destroy(id_t id);
+
+extern int aspace_find_hole(id_t id,
+                            vaddr_t start_hint, size_t extent, size_t alignment,
+                            vaddr_t *start);
+
+extern int aspace_add_region(id_t id,
+                             vaddr_t start, size_t extent,
+                             vmflags_t flags, vmpagesize_t pagesz,
+                             const char *name);
+extern int aspace_del_region(id_t id, vaddr_t start, size_t extent);
+
+extern int aspace_map_pmem(id_t id,
+                           paddr_t pmem, vaddr_t start, size_t extent);
+extern int aspace_unmap_pmem(id_t id, vaddr_t start, size_t extent);
+
+extern int aspace_smartmap(id_t src, id_t dst, vaddr_t start, size_t extent);
+extern int aspace_unsmartmap(id_t src, id_t dst);
+
+extern int aspace_dump2console(id_t id);
+
+/**
+ * Convenience functions defined in liblwk.
+ */
+extern int
+aspace_map_region(
+       id_t         id,
+       vaddr_t      start,
+       size_t       extent,
+       vmflags_t    flags,
+       vmpagesize_t pagesz,
+       const char * name,
+       paddr_t      pmem
+);
+
+extern int
+aspace_map_region_anywhere(
+       id_t         id,
+       vaddr_t *    start,
+       size_t       extent,
+       vmflags_t    flags,
+       vmpagesize_t pagesz,
+       const char * name,
+       paddr_t      pmem
+);
+
+#ifdef __KERNEL__
+
+#include <lwk/spinlock.h>
+#include <lwk/list.h>
+#include <lwk/init.h>
+#include <arch/aspace.h>
+
+/**
+ * Address space structure.
+ */
+struct aspace {
+       spinlock_t         lock;        /* Must be held to access addr space */
+
+       id_t               id;          /* The address space's ID */
+       char               name[16];    /* Address space's name */
+       struct hlist_node  ht_link;     /* Adress space hash table linkage */
+       int                refcnt;      /* # of users of this address space */
+
+       struct list_head   region_list; /* Sorted non-overlapping region list */
+
+       /**
+        * The address space's "Heap" region spans from:
+        *     [heap_start, heap_end)
+        */
+       vaddr_t            heap_start;
+       vaddr_t            heap_end;
+
+       /**
+        * The traditional UNIX data segment is contained in the address
+        * space's heap region, ranging from:
+        *     [heap_start, brk)
+        *
+        * GLIBC/malloc will call the sys_brk() system call when it wants to
+        * expand or shrink the data segment. The kernel verifies that the new
+        * brk value is legal before updating it. The data segment may not
+        * extend beyond the address space's heap region or overlap with
+        * any anonymous mmap regions (see mmap_brk below).
+        */
+       vaddr_t            brk;
+
+       /**
+        * Memory for anonymous mmap() regions is allocated from the top of the
+        * address space's heap region, ranging from:
+        *     [mmap_brk, heap_end)
+        *
+        * GLIBC makes at least one mmap() call during pre-main app startup
+        * to allocate some "anonymous" memory (i.e., normal memory, not a
+        * file mapping). mmap_brk starts out set to heap_end and grows down
+        * as anonymous mmap() calls are made. The kernel takes care to prevent
+        * mmap_brk from extending into the UNIX data segment (see brk above).
+        */
+       vaddr_t            mmap_brk;
+
+       /**
+        * Architecture specific address space data.
+        */
+       struct arch_aspace arch;
+};
+
+/**
+ * Valid address space IDs are in interval [__ASPACE_MIN_ID, __ASPACE_MAX_ID].
+ */
+#define __ASPACE_MIN_ID   ASPACE_MIN_ID
+#define __ASPACE_MAX_ID   ASPACE_MAX_ID+1  /* +1 for KERNEL_ASPACE_ID */
+
+/**
+ * ID of the address space used by kernel threads.
+ */
+#define KERNEL_ASPACE_ID  ASPACE_MAX_ID+1
+
+/**
+ * Kernel-only unlocked versions of the core adress space management API.
+ * These assume that the aspace objects passed in have already been locked.
+ * The caller must unlock the aspaces. The caller must also ensure that
+ * interrupts are disabled before calling these functions.
+ */
+extern int __aspace_find_hole(struct aspace *aspace,
+                              vaddr_t start_hint, size_t extent, size_t alignment,
+                              vaddr_t *start);
+extern int __aspace_add_region(struct aspace *aspace,
+                               vaddr_t start, size_t extent,
+                               vmflags_t flags, vmpagesize_t pagesz,
+                               const char *name);
+extern int __aspace_del_region(struct aspace *aspace,
+                               vaddr_t start, size_t extent);
+extern int __aspace_map_pmem(struct aspace *aspace,
+                             paddr_t pmem, vaddr_t start, size_t extent);
+extern int __aspace_unmap_pmem(struct aspace *aspace,
+                               vaddr_t start, size_t extent);
+extern int __aspace_smartmap(struct aspace *src, struct aspace *dst,
+                             vaddr_t start, size_t extent);
+extern int __aspace_unsmartmap(struct aspace *src, struct aspace *dst);
+
+/**
+ * Kernel-only address space management API.
+ * These are not accessible from user-space.
+ */
+extern int __init aspace_subsys_init(void);
+extern struct aspace *aspace_acquire(id_t id);
+extern void aspace_release(struct aspace *aspace);
+
+/**
+ * Architecture specific address space functions.
+ * Each architecture port must provide these.
+ */
+extern int arch_aspace_create(struct aspace *aspace);
+extern void arch_aspace_destroy(struct aspace *aspace);
+extern void arch_aspace_activate(struct aspace *aspace);
+extern int arch_aspace_map_page(struct aspace * aspace,
+                                vaddr_t start, paddr_t paddr,
+                                vmflags_t flags, vmpagesize_t pagesz);
+extern void arch_aspace_unmap_page(struct aspace * aspace,
+                                   vaddr_t start, vmpagesize_t pagesz);
+extern int arch_aspace_smartmap(struct aspace *src, struct aspace *dst,
+                                vaddr_t start, size_t extent);
+extern int arch_aspace_unsmartmap(struct aspace *src, struct aspace *dst,
+                                  vaddr_t start, size_t extent);
+
+/**
+ * System call handlers.
+ */
+extern int sys_aspace_get_myid(id_t __user *id);
+extern int sys_aspace_create(id_t id_request, const char __user *name,
+                             id_t __user *id);
+extern int sys_aspace_destroy(id_t id);
+extern int sys_aspace_find_hole(id_t id, vaddr_t start_hint, size_t extent,
+                                size_t alignment, vaddr_t __user *start);
+extern int sys_aspace_add_region(id_t id,
+                                 vaddr_t start, size_t extent,
+                                 vmflags_t flags, vmpagesize_t pagesz,
+                                 const char __user *name);
+extern int sys_aspace_del_region(id_t id, vaddr_t start, size_t extent);
+extern int sys_aspace_map_pmem(id_t id,
+                               paddr_t pmem, vaddr_t start, size_t extent);
+extern int sys_aspace_unmap_pmem(id_t id, vaddr_t start, size_t extent);
+extern int sys_aspace_smartmap(id_t src, id_t dst,
+                               vaddr_t start, size_t extent);
+extern int sys_aspace_unsmartmap(id_t src, id_t dst);
+extern int sys_aspace_dump2console(id_t id);
+
+#endif
+#endif
diff --git a/kitten/include/lwk/auxvec.h b/kitten/include/lwk/auxvec.h
new file mode 100644 (file)
index 0000000..d62ddc4
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _LWK_AUXVEC_H
+#define _LWK_AUXVEC_H
+
+/**
+ * Auxiliary info table entry.  A table of these entries gets placed at the
+ * top of a new task's stack so user-space can figure out things that are
+ * difficult or impossible to determine otherwise (e.g., its base load
+ * address).
+ */
+struct aux_ent {
+       unsigned long id;
+       unsigned long val;
+};
+
+#include <arch/auxvec.h>
+
+/* Symbolic values for the entries in the auxiliary table
+   put on the initial stack */
+#define AT_NULL   0    /* end of vector */
+#define AT_IGNORE 1    /* entry should be ignored */
+#define AT_EXECFD 2    /* file descriptor of program */
+#define AT_PHDR   3    /* program headers for program */
+#define AT_PHENT  4    /* size of program header entry */
+#define AT_PHNUM  5    /* number of program headers */
+#define AT_PAGESZ 6    /* system page size */
+#define AT_BASE   7    /* base address of interpreter */
+#define AT_FLAGS  8    /* flags */
+#define AT_ENTRY  9    /* entry point of program */
+#define AT_NOTELF 10   /* program is not ELF */
+#define AT_UID    11   /* real uid */
+#define AT_EUID   12   /* effective uid */
+#define AT_GID    13   /* real gid */
+#define AT_EGID   14   /* effective gid */
+#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
+#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17   /* frequency at which times() increments */
+
+#define AT_SECURE 23   /* secure mode boolean */
+
+#define AT_ENTRIES  22 /* Number of entries in the auxiliary table */
+
+#endif /* _LWK_AUXVEC_H */
diff --git a/kitten/include/lwk/bitmap.h b/kitten/include/lwk/bitmap.h
new file mode 100644 (file)
index 0000000..ac6e9bc
--- /dev/null
@@ -0,0 +1,270 @@
+#ifndef _LWK_BITMAP_H
+#define _LWK_BITMAP_H
+
+#ifndef __ASSEMBLY__
+
+#include <lwk/types.h>
+#include <lwk/bitops.h>
+#include <lwk/string.h>
+
+/*
+ * bitmaps provide bit arrays that consume one or more unsigned
+ * longs.  The bitmap interface and available operations are listed
+ * here, in bitmap.h
+ *
+ * Function implementations generic to all architectures are in
+ * lib/bitmap.c.  Functions implementations that are architecture
+ * specific are in various include/arch-<arch>/bitops.h headers
+ * and other arch/<arch> specific files.
+ *
+ * See lib/bitmap.c for more details.
+ */
+
+/*
+ * The available bitmap operations and their rough meaning in the
+ * case that the bitmap is a single unsigned long are thus:
+ *
+ * bitmap_zero(dst, nbits)                     *dst = 0UL
+ * bitmap_fill(dst, nbits)                     *dst = ~0UL
+ * bitmap_copy(dst, src, nbits)                        *dst = *src
+ * bitmap_and(dst, src1, src2, nbits)          *dst = *src1 & *src2
+ * bitmap_or(dst, src1, src2, nbits)           *dst = *src1 | *src2
+ * bitmap_xor(dst, src1, src2, nbits)          *dst = *src1 ^ *src2
+ * bitmap_andnot(dst, src1, src2, nbits)       *dst = *src1 & ~(*src2)
+ * bitmap_complement(dst, src, nbits)          *dst = ~(*src)
+ * bitmap_equal(src1, src2, nbits)             Are *src1 and *src2 equal?
+ * bitmap_intersects(src1, src2, nbits)        Do *src1 and *src2 overlap?
+ * bitmap_subset(src1, src2, nbits)            Is *src1 a subset of *src2?
+ * bitmap_empty(src, nbits)                    Are all bits zero in *src?
+ * bitmap_full(src, nbits)                     Are all bits set in *src?
+ * bitmap_weight(src, nbits)                   Hamming Weight: number set bits
+ * bitmap_shift_right(dst, src, n, nbits)      *dst = *src >> n
+ * bitmap_shift_left(dst, src, n, nbits)       *dst = *src << n
+ * bitmap_remap(dst, src, old, new, nbits)     *dst = map(old, new)(src)
+ * bitmap_bitremap(oldbit, old, new, nbits)    newbit = map(old, new)(oldbit)
+ * bitmap_scnprintf(buf, len, src, nbits)      Print bitmap src to buf
+ * bitmap_parse(ubuf, ulen, dst, nbits)                Parse bitmap dst from user buf
+ * bitmap_scnlistprintf(buf, len, src, nbits)  Print bitmap src as list to buf
+ * bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from list
+ * bitmap_find_free_region(bitmap, bits, order)        Find and allocate bit region
+ * bitmap_release_region(bitmap, pos, order)   Free specified bit region
+ * bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
+ */
+
+/*
+ * Also the following operations in asm/bitops.h apply to bitmaps.
+ *
+ * set_bit(bit, addr)                  *addr |= bit
+ * clear_bit(bit, addr)                        *addr &= ~bit
+ * change_bit(bit, addr)               *addr ^= bit
+ * test_bit(bit, addr)                 Is bit set in *addr?
+ * test_and_set_bit(bit, addr)         Set bit and return old value
+ * test_and_clear_bit(bit, addr)       Clear bit and return old value
+ * test_and_change_bit(bit, addr)      Change bit and return old value
+ * find_first_zero_bit(addr, nbits)    Position first zero bit in *addr
+ * find_first_bit(addr, nbits)         Position first set bit in *addr
+ * find_next_zero_bit(addr, nbits, bit)        Position next zero bit in *addr >= bit
+ * find_next_bit(addr, nbits, bit)     Position next set bit in *addr >= bit
+ */
+
+/*
+ * The DECLARE_BITMAP(name,bits) macro, in lwk/types.h, can be used
+ * to declare an array named 'name' of just enough unsigned longs to
+ * contain all bit positions from 0 to 'bits' - 1.
+ */
+
+/*
+ * lib/bitmap.c provides these functions:
+ */
+
+extern int __bitmap_empty(const unsigned long *bitmap, int bits);
+extern int __bitmap_full(const unsigned long *bitmap, int bits);
+extern int __bitmap_equal(const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern void __bitmap_complement(unsigned long *dst, const unsigned long *src,
+                       int bits);
+extern void __bitmap_shift_right(unsigned long *dst,
+                        const unsigned long *src, int shift, int bits);
+extern void __bitmap_shift_left(unsigned long *dst,
+                        const unsigned long *src, int shift, int bits);
+extern void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern int __bitmap_intersects(const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern int __bitmap_subset(const unsigned long *bitmap1,
+                       const unsigned long *bitmap2, int bits);
+extern int __bitmap_weight(const unsigned long *bitmap, int bits);
+
+extern int bitmap_scnprintf(char *buf, unsigned int len,
+                       const unsigned long *src, int nbits);
+extern int bitmap_parse(const char __user *ubuf, unsigned int ulen,
+                       unsigned long *dst, int nbits);
+extern int bitmap_scnlistprintf(char *buf, unsigned int len,
+                       const unsigned long *src, int nbits);
+extern int bitmap_parselist(const char *buf, unsigned long *maskp,
+                       int nmaskbits);
+extern void bitmap_remap(unsigned long *dst, const unsigned long *src,
+               const unsigned long *old, const unsigned long *new, int bits);
+extern int bitmap_bitremap(int oldbit,
+               const unsigned long *old, const unsigned long *new, int bits);
+extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
+extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
+extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
+
+#define BITMAP_LAST_WORD_MASK(nbits)                                   \
+(                                                                      \
+       ((nbits) % BITS_PER_LONG) ?                                     \
+               (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL               \
+)
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = 0UL;
+       else {
+               int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+               memset(dst, 0, len);
+       }
+}
+
+static inline void bitmap_fill(unsigned long *dst, int nbits)
+{
+       size_t nlongs = BITS_TO_LONGS(nbits);
+       if (nlongs > 1) {
+               int len = (nlongs - 1) * sizeof(unsigned long);
+               memset(dst, 0xff,  len);
+       }
+       dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
+}
+
+static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
+                       int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = *src;
+       else {
+               int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+               memcpy(dst, src, len);
+       }
+}
+
+static inline void bitmap_and(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = *src1 & *src2;
+       else
+               __bitmap_and(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = *src1 | *src2;
+       else
+               __bitmap_or(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = *src1 ^ *src2;
+       else
+               __bitmap_xor(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = *src1 & ~(*src2);
+       else
+               __bitmap_andnot(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
+                       int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
+       else
+               __bitmap_complement(dst, src, nbits);
+}
+
+static inline int bitmap_equal(const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
+       else
+               return __bitmap_equal(src1, src2, nbits);
+}
+
+static inline int bitmap_intersects(const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+       else
+               return __bitmap_intersects(src1, src2, nbits);
+}
+
+static inline int bitmap_subset(const unsigned long *src1,
+                       const unsigned long *src2, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
+       else
+               return __bitmap_subset(src1, src2, nbits);
+}
+
+static inline int bitmap_empty(const unsigned long *src, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
+       else
+               return __bitmap_empty(src, nbits);
+}
+
+static inline int bitmap_full(const unsigned long *src, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
+       else
+               return __bitmap_full(src, nbits);
+}
+
+static inline int bitmap_weight(const unsigned long *src, int nbits)
+{
+       return __bitmap_weight(src, nbits);
+}
+
+static inline void bitmap_shift_right(unsigned long *dst,
+                       const unsigned long *src, int n, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = *src >> n;
+       else
+               __bitmap_shift_right(dst, src, n, nbits);
+}
+
+static inline void bitmap_shift_left(unsigned long *dst,
+                       const unsigned long *src, int n, int nbits)
+{
+       if (nbits <= BITS_PER_LONG)
+               *dst = (*src << n) & BITMAP_LAST_WORD_MASK(nbits);
+       else
+               __bitmap_shift_left(dst, src, n, nbits);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _LWK_BITMAP_H */
diff --git a/kitten/include/lwk/bitops.h b/kitten/include/lwk/bitops.h
new file mode 100644 (file)
index 0000000..4bb2ea2
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _LWK_BITOPS_H
+#define _LWK_BITOPS_H
+#include <arch/types.h>
+
+/*
+ * Include this here because some architectures need generic_ffs/fls in
+ * scope
+ */
+#include <arch/bitops.h>
+
+static __inline__ int get_bitmask_order(unsigned int count)
+{
+       int order;
+       
+       order = fls(count);
+       return order;   /* We could be slightly more clever with -1 here... */
+}
+
+static __inline__ int get_count_order(unsigned int count)
+{
+       int order;
+       
+       order = fls(count) - 1;
+       if (count & (count - 1))
+               order++;
+       return order;
+}
+
+static inline unsigned long hweight_long(unsigned long w)
+{
+       return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
+}
+
+/*
+ * rol32 - rotate a 32-bit value left
+ *
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline __u32 rol32(__u32 word, unsigned int shift)
+{
+       return (word << shift) | (word >> (32 - shift));
+}
+
+/*
+ * ror32 - rotate a 32-bit value right
+ *
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline __u32 ror32(__u32 word, unsigned int shift)
+{
+       return (word >> shift) | (word << (32 - shift));
+}
+
+static inline unsigned fls_long(unsigned long l)
+{
+       if (sizeof(l) == 4)
+               return fls(l);
+       return fls64(l);
+}
+
+#endif
diff --git a/kitten/include/lwk/bootmem.h b/kitten/include/lwk/bootmem.h
new file mode 100644 (file)
index 0000000..2fe3611
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _LWK_BOOTMEM_H
+#define _LWK_BOOTMEM_H
+
+#include <lwk/list.h>
+#include <lwk/init.h>
+
+/**
+ * Bootmem control structure.
+ *
+ * The node_bootmem_map field is a map pointer - the bits represent
+ * all physical memory pages (including holes) for the region represented
+ * by the enclosing bootmem_data structure.
+ */
+typedef struct bootmem_data {
+       unsigned long   node_boot_start;
+       unsigned long   node_low_pfn;
+       void            *node_bootmem_map;      // bitmap, one bit per page
+       unsigned long   last_offset;
+       unsigned long   last_pos;
+       unsigned long   last_success;           // previous allocation point,
+                                               // used to speed up search.
+       struct list_head list;
+} bootmem_data_t;
+
+extern unsigned long __init bootmem_bootmap_pages(unsigned long pages);
+extern unsigned long __init init_bootmem(unsigned long start,
+                                         unsigned long pages);
+extern void __init reserve_bootmem(unsigned long addr, unsigned long size);
+extern void * __init alloc_bootmem(unsigned long size);
+extern void * __init alloc_bootmem_aligned(unsigned long size,
+                                           unsigned long alignment);
+extern void __init free_bootmem(unsigned long addr, unsigned long size);
+extern void __init free_all_bootmem(void);
+
+extern void __init mem_subsys_init(void);
+extern void __init arch_memsys_init(size_t kmem_size);
+
+#endif
diff --git a/kitten/include/lwk/buddy.h b/kitten/include/lwk/buddy.h
new file mode 100644 (file)
index 0000000..58a6e32
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (c) 2007, Sandia National Laboratories */
+
+#ifndef _LWK_BUDDY_H
+#define _LWK_BUDDY_H
+
+#include <lwk/list.h>
+
+/**
+ * This structure stores the state of a buddy system memory allocator object.
+ */
+struct buddy_mempool {
+       unsigned long    base_addr;    /* base address of the memory pool */
+       unsigned long    pool_order;   /* size of memory pool = 2^pool_order */
+       unsigned long    min_order;    /* minimum allocatable block size */
+
+       unsigned long    num_blocks;   /* number of bits in tag_bits */
+       unsigned long    *tag_bits;    /* one bit for each 2^min_order block
+                                       *   0 = block is allocated
+                                       *   1 = block is available
+                                       */
+
+       struct list_head *avail;       /* one free list for each block size,
+                                       * indexed by block order:
+                                       *   avail[i] = free list of 2^i blocks
+                                       */
+};
+
+struct buddy_mempool *
+buddy_init(
+       unsigned long base_addr,
+       unsigned long pool_order,
+       unsigned long min_order
+);
+
+void *buddy_alloc(struct buddy_mempool *mp, unsigned long order);
+void buddy_free(struct buddy_mempool *mp, void *addr, unsigned long order);
+
+void buddy_dump_mempool(struct buddy_mempool *mp);
+
+#endif
diff --git a/kitten/include/lwk/byteorder/Kbuild b/kitten/include/lwk/byteorder/Kbuild
new file mode 100644 (file)
index 0000000..eb1f189
--- /dev/null
@@ -0,0 +1,2 @@
+unifdef-y += generic.h swab.h
+header-y += big_endian.h little_endian.h
diff --git a/kitten/include/lwk/byteorder/big_endian.h b/kitten/include/lwk/byteorder/big_endian.h
new file mode 100644 (file)
index 0000000..68993de
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef _LWK_BYTEORDER_BIG_ENDIAN_H
+#define _LWK_BYTEORDER_BIG_ENDIAN_H
+
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+#ifndef __BIG_ENDIAN_BITFIELD
+#define __BIG_ENDIAN_BITFIELD
+#endif
+
+#include <lwk/types.h>
+#include <lwk/byteorder/swab.h>
+
+#define __constant_htonl(x) ((__force __be32)(__u32)(x))
+#define __constant_ntohl(x) ((__force __u32)(__be32)(x))
+#define __constant_htons(x) ((__force __be16)(__u16)(x))
+#define __constant_ntohs(x) ((__force __u16)(__be16)(x))
+#define __constant_cpu_to_le64(x) ((__force __le64)___constant_swab64((x)))
+#define __constant_le64_to_cpu(x) ___constant_swab64((__force __u64)(__le64)(x))
+#define __constant_cpu_to_le32(x) ((__force __le32)___constant_swab32((x)))
+#define __constant_le32_to_cpu(x) ___constant_swab32((__force __u32)(__le32)(x))
+#define __constant_cpu_to_le16(x) ((__force __le16)___constant_swab16((x)))
+#define __constant_le16_to_cpu(x) ___constant_swab16((__force __u16)(__le16)(x))
+#define __constant_cpu_to_be64(x) ((__force __be64)(__u64)(x))
+#define __constant_be64_to_cpu(x) ((__force __u64)(__be64)(x))
+#define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x))
+#define __constant_be32_to_cpu(x) ((__force __u32)(__be32)(x))
+#define __constant_cpu_to_be16(x) ((__force __be16)(__u16)(x))
+#define __constant_be16_to_cpu(x) ((__force __u16)(__be16)(x))
+#define __cpu_to_le64(x) ((__force __le64)__swab64((x)))
+#define __le64_to_cpu(x) __swab64((__force __u64)(__le64)(x))
+#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
+#define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x))
+#define __cpu_to_le16(x) ((__force __le16)__swab16((x)))
+#define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x))
+#define __cpu_to_be64(x) ((__force __be64)(__u64)(x))
+#define __be64_to_cpu(x) ((__force __u64)(__be64)(x))
+#define __cpu_to_be32(x) ((__force __be32)(__u32)(x))
+#define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
+#define __cpu_to_be16(x) ((__force __be16)(__u16)(x))
+#define __be16_to_cpu(x) ((__force __u16)(__be16)(x))
+
+static inline __le64 __cpu_to_le64p(const __u64 *p)
+{
+       return (__force __le64)__swab64p(p);
+}
+static inline __u64 __le64_to_cpup(const __le64 *p)
+{
+       return __swab64p((__u64 *)p);
+}
+static inline __le32 __cpu_to_le32p(const __u32 *p)
+{
+       return (__force __le32)__swab32p(p);
+}
+static inline __u32 __le32_to_cpup(const __le32 *p)
+{
+       return __swab32p((__u32 *)p);
+}
+static inline __le16 __cpu_to_le16p(const __u16 *p)
+{
+       return (__force __le16)__swab16p(p);
+}
+static inline __u16 __le16_to_cpup(const __le16 *p)
+{
+       return __swab16p((__u16 *)p);
+}
+static inline __be64 __cpu_to_be64p(const __u64 *p)
+{
+       return (__force __be64)*p;
+}
+static inline __u64 __be64_to_cpup(const __be64 *p)
+{
+       return (__force __u64)*p;
+}
+static inline __be32 __cpu_to_be32p(const __u32 *p)
+{
+       return (__force __be32)*p;
+}
+static inline __u32 __be32_to_cpup(const __be32 *p)
+{
+       return (__force __u32)*p;
+}
+static inline __be16 __cpu_to_be16p(const __u16 *p)
+{
+       return (__force __be16)*p;
+}
+static inline __u16 __be16_to_cpup(const __be16 *p)
+{
+       return (__force __u16)*p;
+}
+#define __cpu_to_le64s(x) __swab64s((x))
+#define __le64_to_cpus(x) __swab64s((x))
+#define __cpu_to_le32s(x) __swab32s((x))
+#define __le32_to_cpus(x) __swab32s((x))
+#define __cpu_to_le16s(x) __swab16s((x))
+#define __le16_to_cpus(x) __swab16s((x))
+#define __cpu_to_be64s(x) do {} while (0)
+#define __be64_to_cpus(x) do {} while (0)
+#define __cpu_to_be32s(x) do {} while (0)
+#define __be32_to_cpus(x) do {} while (0)
+#define __cpu_to_be16s(x) do {} while (0)
+#define __be16_to_cpus(x) do {} while (0)
+
+#include <lwk/byteorder/generic.h>
+
+#endif /* _LWK_BYTEORDER_BIG_ENDIAN_H */
diff --git a/kitten/include/lwk/byteorder/generic.h b/kitten/include/lwk/byteorder/generic.h
new file mode 100644 (file)
index 0000000..a392358
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef _LWK_BYTEORDER_GENERIC_H
+#define _LWK_BYTEORDER_GENERIC_H
+
+/*
+ * lwk/byteorder/generic.h
+ * Generic Byte-reordering support
+ *
+ * The "... p" macros, like le64_to_cpup, can be used with pointers
+ * to unaligned data, but there will be a performance penalty on 
+ * some architectures.  Use get_unaligned for unaligned data.
+ *
+ * Francois-Rene Rideau <fare@tunes.org> 19970707
+ *    gathered all the good ideas from all asm-foo/byteorder.h into one file,
+ *    cleaned them up.
+ *    I hope it is compliant with non-GCC compilers.
+ *    I decided to put __BYTEORDER_HAS_U64__ in byteorder.h,
+ *    because I wasn't sure it would be ok to put it in types.h
+ *    Upgraded it to 2.1.43
+ * Francois-Rene Rideau <fare@tunes.org> 19971012
+ *    Upgraded it to 2.1.57
+ *    to please Linus T., replaced huge #ifdef's between little/big endian
+ *    by nestedly #include'd files.
+ * Francois-Rene Rideau <fare@tunes.org> 19971205
+ *    Made it to 2.1.71; now a facelift:
+ *    Put files under include/linux/byteorder/
+ *    Split swab from generic support.
+ *
+ * TODO:
+ *   = Regular kernel maintainers could also replace all these manual
+ *    byteswap macros that remain, disseminated among drivers,
+ *    after some grep or the sources...
+ *   = Linus might want to rename all these macros and files to fit his taste,
+ *    to fit his personal naming scheme.
+ *   = it seems that a few drivers would also appreciate
+ *    nybble swapping support...
+ *   = every architecture could add their byteswap macro in asm/byteorder.h
+ *    see how some architectures already do (i386, alpha, ppc, etc)
+ *   = cpu_to_beXX and beXX_to_cpu might some day need to be well
+ *    distinguished throughout the kernel. This is not the case currently,
+ *    since little endian, big endian, and pdp endian machines needn't it.
+ *    But this might be the case for, say, a port of Linux to 20/21 bit
+ *    architectures (and F21 Linux addict around?).
+ */
+
+/*
+ * The following macros are to be defined by <asm/byteorder.h>:
+ *
+ * Conversion of long and short int between network and host format
+ *     ntohl(__u32 x)
+ *     ntohs(__u16 x)
+ *     htonl(__u32 x)
+ *     htons(__u16 x)
+ * It seems that some programs (which? where? or perhaps a standard? POSIX?)
+ * might like the above to be functions, not macros (why?).
+ * if that's true, then detect them, and take measures.
+ * Anyway, the measure is: define only ___ntohl as a macro instead,
+ * and in a separate file, have
+ * unsigned long inline ntohl(x){return ___ntohl(x);}
+ *
+ * The same for constant arguments
+ *     __constant_ntohl(__u32 x)
+ *     __constant_ntohs(__u16 x)
+ *     __constant_htonl(__u32 x)
+ *     __constant_htons(__u16 x)
+ *
+ * Conversion of XX-bit integers (16- 32- or 64-)
+ * between native CPU format and little/big endian format
+ * 64-bit stuff only defined for proper architectures
+ *     cpu_to_[bl]eXX(__uXX x)
+ *     [bl]eXX_to_cpu(__uXX x)
+ *
+ * The same, but takes a pointer to the value to convert
+ *     cpu_to_[bl]eXXp(__uXX x)
+ *     [bl]eXX_to_cpup(__uXX x)
+ *
+ * The same, but change in situ
+ *     cpu_to_[bl]eXXs(__uXX x)
+ *     [bl]eXX_to_cpus(__uXX x)
+ *
+ * See asm-foo/byteorder.h for examples of how to provide
+ * architecture-optimized versions
+ *
+ */
+
+
+#if defined(__KERNEL__)
+/*
+ * inside the kernel, we can use nicknames;
+ * outside of it, we must avoid POSIX namespace pollution...
+ */
+#define cpu_to_le64 __cpu_to_le64
+#define le64_to_cpu __le64_to_cpu
+#define cpu_to_le32 __cpu_to_le32
+#define le32_to_cpu __le32_to_cpu
+#define cpu_to_le16 __cpu_to_le16
+#define le16_to_cpu __le16_to_cpu
+#define cpu_to_be64 __cpu_to_be64
+#define be64_to_cpu __be64_to_cpu
+#define cpu_to_be32 __cpu_to_be32
+#define be32_to_cpu __be32_to_cpu
+#define cpu_to_be16 __cpu_to_be16
+#define be16_to_cpu __be16_to_cpu
+#define cpu_to_le64p __cpu_to_le64p
+#define le64_to_cpup __le64_to_cpup
+#define cpu_to_le32p __cpu_to_le32p
+#define le32_to_cpup __le32_to_cpup
+#define cpu_to_le16p __cpu_to_le16p
+#define le16_to_cpup __le16_to_cpup
+#define cpu_to_be64p __cpu_to_be64p
+#define be64_to_cpup __be64_to_cpup
+#define cpu_to_be32p __cpu_to_be32p
+#define be32_to_cpup __be32_to_cpup
+#define cpu_to_be16p __cpu_to_be16p
+#define be16_to_cpup __be16_to_cpup
+#define cpu_to_le64s __cpu_to_le64s
+#define le64_to_cpus __le64_to_cpus
+#define cpu_to_le32s __cpu_to_le32s
+#define le32_to_cpus __le32_to_cpus
+#define cpu_to_le16s __cpu_to_le16s
+#define le16_to_cpus __le16_to_cpus
+#define cpu_to_be64s __cpu_to_be64s
+#define be64_to_cpus __be64_to_cpus
+#define cpu_to_be32s __cpu_to_be32s
+#define be32_to_cpus __be32_to_cpus
+#define cpu_to_be16s __cpu_to_be16s
+#define be16_to_cpus __be16_to_cpus
+#endif
+
+
+#if defined(__KERNEL__)
+/*
+ * Handle ntohl and suches. These have various compatibility
+ * issues - like we want to give the prototype even though we
+ * also have a macro for them in case some strange program
+ * wants to take the address of the thing or something..
+ *
+ * Note that these used to return a "long" in libc5, even though
+ * long is often 64-bit these days.. Thus the casts.
+ *
+ * They have to be macros in order to do the constant folding
+ * correctly - if the argument passed into a inline function
+ * it is no longer constant according to gcc..
+ */
+
+#undef ntohl
+#undef ntohs
+#undef htonl
+#undef htons
+
+/*
+ * Do the prototypes. Somebody might want to take the
+ * address or some such sick thing..
+ */
+extern __u32                   ntohl(__be32);
+extern __be32                  htonl(__u32);
+extern __u16                   ntohs(__be16);
+extern __be16                  htons(__u16);
+
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
+
+#define ___htonl(x) __cpu_to_be32(x)
+#define ___htons(x) __cpu_to_be16(x)
+#define ___ntohl(x) __be32_to_cpu(x)
+#define ___ntohs(x) __be16_to_cpu(x)
+
+#define htonl(x) ___htonl(x)
+#define ntohl(x) ___ntohl(x)
+#define htons(x) ___htons(x)
+#define ntohs(x) ___ntohs(x)
+
+#endif /* OPTIMIZE */
+
+#endif /* KERNEL */
+
+
+#endif /* _LWK_BYTEORDER_GENERIC_H */
diff --git a/kitten/include/lwk/byteorder/little_endian.h b/kitten/include/lwk/byteorder/little_endian.h
new file mode 100644 (file)
index 0000000..ff98d8e
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef _LWK_BYTEORDER_LITTLE_ENDIAN_H
+#define _LWK_BYTEORDER_LITTLE_ENDIAN_H
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
+#endif
+
+#include <lwk/types.h>
+#include <lwk/byteorder/swab.h>
+
+#define __constant_htonl(x) ((__force __be32)___constant_swab32((x)))
+#define __constant_ntohl(x) ___constant_swab32((__force __be32)(x))
+#define __constant_htons(x) ((__force __be16)___constant_swab16((x)))
+#define __constant_ntohs(x) ___constant_swab16((__force __be16)(x))
+#define __constant_cpu_to_le64(x) ((__force __le64)(__u64)(x))
+#define __constant_le64_to_cpu(x) ((__force __u64)(__le64)(x))
+#define __constant_cpu_to_le32(x) ((__force __le32)(__u32)(x))
+#define __constant_le32_to_cpu(x) ((__force __u32)(__le32)(x))
+#define __constant_cpu_to_le16(x) ((__force __le16)(__u16)(x))
+#define __constant_le16_to_cpu(x) ((__force __u16)(__le16)(x))
+#define __constant_cpu_to_be64(x) ((__force __be64)___constant_swab64((x)))
+#define __constant_be64_to_cpu(x) ___constant_swab64((__force __u64)(__be64)(x))
+#define __constant_cpu_to_be32(x) ((__force __be32)___constant_swab32((x)))
+#define __constant_be32_to_cpu(x) ___constant_swab32((__force __u32)(__be32)(x))
+#define __constant_cpu_to_be16(x) ((__force __be16)___constant_swab16((x)))
+#define __constant_be16_to_cpu(x) ___constant_swab16((__force __u16)(__be16)(x))
+#define __cpu_to_le64(x) ((__force __le64)(__u64)(x))
+#define __le64_to_cpu(x) ((__force __u64)(__le64)(x))
+#define __cpu_to_le32(x) ((__force __le32)(__u32)(x))
+#define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
+#define __cpu_to_le16(x) ((__force __le16)(__u16)(x))
+#define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
+#define __cpu_to_be64(x) ((__force __be64)__swab64((x)))
+#define __be64_to_cpu(x) __swab64((__force __u64)(__be64)(x))
+#define __cpu_to_be32(x) ((__force __be32)__swab32((x)))
+#define __be32_to_cpu(x) __swab32((__force __u32)(__be32)(x))
+#define __cpu_to_be16(x) ((__force __be16)__swab16((x)))
+#define __be16_to_cpu(x) __swab16((__force __u16)(__be16)(x))
+
+static inline __le64 __cpu_to_le64p(const __u64 *p)
+{
+       return (__force __le64)*p;
+}
+static inline __u64 __le64_to_cpup(const __le64 *p)
+{
+       return (__force __u64)*p;
+}
+static inline __le32 __cpu_to_le32p(const __u32 *p)
+{
+       return (__force __le32)*p;
+}
+static inline __u32 __le32_to_cpup(const __le32 *p)
+{
+       return (__force __u32)*p;
+}
+static inline __le16 __cpu_to_le16p(const __u16 *p)
+{
+       return (__force __le16)*p;
+}
+static inline __u16 __le16_to_cpup(const __le16 *p)
+{
+       return (__force __u16)*p;
+}
+static inline __be64 __cpu_to_be64p(const __u64 *p)
+{
+       return (__force __be64)__swab64p(p);
+}
+static inline __u64 __be64_to_cpup(const __be64 *p)
+{
+       return __swab64p((__u64 *)p);
+}
+static inline __be32 __cpu_to_be32p(const __u32 *p)
+{
+       return (__force __be32)__swab32p(p);
+}
+static inline __u32 __be32_to_cpup(const __be32 *p)
+{
+       return __swab32p((__u32 *)p);
+}
+static inline __be16 __cpu_to_be16p(const __u16 *p)
+{
+       return (__force __be16)__swab16p(p);
+}
+static inline __u16 __be16_to_cpup(const __be16 *p)
+{
+       return __swab16p((__u16 *)p);
+}
+#define __cpu_to_le64s(x) do {} while (0)
+#define __le64_to_cpus(x) do {} while (0)
+#define __cpu_to_le32s(x) do {} while (0)
+#define __le32_to_cpus(x) do {} while (0)
+#define __cpu_to_le16s(x) do {} while (0)
+#define __le16_to_cpus(x) do {} while (0)
+#define __cpu_to_be64s(x) __swab64s((x))
+#define __be64_to_cpus(x) __swab64s((x))
+#define __cpu_to_be32s(x) __swab32s((x))
+#define __be32_to_cpus(x) __swab32s((x))
+#define __cpu_to_be16s(x) __swab16s((x))
+#define __be16_to_cpus(x) __swab16s((x))
+
+#include <lwk/byteorder/generic.h>
+
+#endif /* _LWK_BYTEORDER_LITTLE_ENDIAN_H */
diff --git a/kitten/include/lwk/byteorder/swab.h b/kitten/include/lwk/byteorder/swab.h
new file mode 100644 (file)
index 0000000..0d9a946
--- /dev/null
@@ -0,0 +1,192 @@
+#ifndef _LWK_BYTEORDER_SWAB_H
+#define _LWK_BYTEORDER_SWAB_H
+
+/*
+ * lwk/byteorder/swab.h
+ * Byte-swapping, independently from CPU endianness
+ *     swabXX[ps]?(foo)
+ *
+ * Francois-Rene Rideau <fare@tunes.org> 19971205
+ *    separated swab functions from cpu_to_XX,
+ *    to clean up support for bizarre-endian architectures.
+ *
+ * See asm-i386/byteorder.h and suches for examples of how to provide
+ * architecture-dependent optimized versions
+ *
+ */
+
+#include <lwk/compiler.h>
+
+/* casts are necessary for constants, because we never know how for sure
+ * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
+ */
+#define ___swab16(x) \
+({ \
+       __u16 __x = (x); \
+       ((__u16)( \
+               (((__u16)(__x) & (__u16)0x00ffU) << 8) | \
+               (((__u16)(__x) & (__u16)0xff00U) >> 8) )); \
+})
+
+#define ___swab32(x) \
+({ \
+       __u32 __x = (x); \
+       ((__u32)( \
+               (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \
+               (((__u32)(__x) & (__u32)0x0000ff00UL) <<  8) | \
+               (((__u32)(__x) & (__u32)0x00ff0000UL) >>  8) | \
+               (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \
+})
+
+#define ___swab64(x) \
+({ \
+       __u64 __x = (x); \
+       ((__u64)( \
+               (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
+               (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
+               (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
+               (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) <<  8) | \
+               (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >>  8) | \
+               (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
+               (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
+               (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \
+})
+
+#define ___constant_swab16(x) \
+       ((__u16)( \
+               (((__u16)(x) & (__u16)0x00ffU) << 8) | \
+               (((__u16)(x) & (__u16)0xff00U) >> 8) ))
+#define ___constant_swab32(x) \
+       ((__u32)( \
+               (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
+               (((__u32)(x) & (__u32)0x0000ff00UL) <<  8) | \
+               (((__u32)(x) & (__u32)0x00ff0000UL) >>  8) | \
+               (((__u32)(x) & (__u32)0xff000000UL) >> 24) ))
+#define ___constant_swab64(x) \
+       ((__u64)( \
+               (__u64)(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \
+               (__u64)(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \
+               (__u64)(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \
+               (__u64)(((__u64)(x) & (__u64)0x00000000ff000000ULL) <<  8) | \
+               (__u64)(((__u64)(x) & (__u64)0x000000ff00000000ULL) >>  8) | \
+               (__u64)(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
+               (__u64)(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \
+               (__u64)(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56) ))
+
+/*
+ * provide defaults when no architecture-specific optimization is detected
+ */
+#ifndef __arch__swab16
+#  define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); })
+#endif
+#ifndef __arch__swab32
+#  define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); })
+#endif
+#ifndef __arch__swab64
+#  define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); })
+#endif
+
+#ifndef __arch__swab16p
+#  define __arch__swab16p(x) __arch__swab16(*(x))
+#endif
+#ifndef __arch__swab32p
+#  define __arch__swab32p(x) __arch__swab32(*(x))
+#endif
+#ifndef __arch__swab64p
+#  define __arch__swab64p(x) __arch__swab64(*(x))
+#endif
+
+#ifndef __arch__swab16s
+#  define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0)
+#endif
+#ifndef __arch__swab32s
+#  define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0)
+#endif
+#ifndef __arch__swab64s
+#  define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0)
+#endif
+
+
+/*
+ * Allow constant folding
+ */
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
+#  define __swab16(x) \
+(__builtin_constant_p((__u16)(x)) ? \
+ ___swab16((x)) : \
+ __fswab16((x)))
+#  define __swab32(x) \
+(__builtin_constant_p((__u32)(x)) ? \
+ ___swab32((x)) : \
+ __fswab32((x)))
+#  define __swab64(x) \
+(__builtin_constant_p((__u64)(x)) ? \
+ ___swab64((x)) : \
+ __fswab64((x)))
+#else
+#  define __swab16(x) __fswab16(x)
+#  define __swab32(x) __fswab32(x)
+#  define __swab64(x) __fswab64(x)
+#endif /* OPTIMIZE */
+
+
+static __inline__ __attribute_const__ __u16 __fswab16(__u16 x)
+{
+       return __arch__swab16(x);
+}
+static __inline__ __u16 __swab16p(const __u16 *x)
+{
+       return __arch__swab16p(x);
+}
+static __inline__ void __swab16s(__u16 *addr)
+{
+       __arch__swab16s(addr);
+}
+
+static __inline__ __attribute_const__ __u32 __fswab32(__u32 x)
+{
+       return __arch__swab32(x);
+}
+static __inline__ __u32 __swab32p(const __u32 *x)
+{
+       return __arch__swab32p(x);
+}
+static __inline__ void __swab32s(__u32 *addr)
+{
+       __arch__swab32s(addr);
+}
+
+#ifdef __BYTEORDER_HAS_U64__
+static __inline__ __attribute_const__ __u64 __fswab64(__u64 x)
+{
+#  ifdef __SWAB_64_THRU_32__
+       __u32 h = x >> 32;
+        __u32 l = x & ((1ULL<<32)-1);
+        return (((__u64)__swab32(l)) << 32) | ((__u64)(__swab32(h)));
+#  else
+       return __arch__swab64(x);
+#  endif
+}
+static __inline__ __u64 __swab64p(const __u64 *x)
+{
+       return __arch__swab64p(x);
+}
+static __inline__ void __swab64s(__u64 *addr)
+{
+       __arch__swab64s(addr);
+}
+#endif /* __BYTEORDER_HAS_U64__ */
+
+#if defined(__KERNEL__)
+#define swab16 __swab16
+#define swab32 __swab32
+#define swab64 __swab64
+#define swab16p __swab16p
+#define swab32p __swab32p
+#define swab64p __swab64p
+#define swab16s __swab16s
+#define swab32s __swab32s
+#define swab64s __swab64s
+#endif
+
+#endif /* _LWK_BYTEORDER_SWAB_H */
diff --git a/kitten/include/lwk/cache.h b/kitten/include/lwk/cache.h
new file mode 100644 (file)
index 0000000..dc87a63
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _LWK_CACHE_H
+#define _LWK_CACHE_H
+
+#include <lwk/kernel.h>
+#include <arch/cache.h>
+
+#ifndef L1_CACHE_ALIGN
+#define L1_CACHE_ALIGN(x) ALIGN(x, L1_CACHE_BYTES)
+#endif
+
+#ifndef SMP_CACHE_BYTES
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
+#endif
+
+#ifndef __read_mostly
+#define __read_mostly
+#endif
+
+#ifndef ____cacheline_aligned
+#define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
+#endif
+
+#ifndef ____cacheline_aligned_in_smp
+#define ____cacheline_aligned_in_smp ____cacheline_aligned
+#endif
+
+#ifndef __cacheline_aligned
+#define __cacheline_aligned                                    \
+  __attribute__((__aligned__(SMP_CACHE_BYTES),                 \
+                __section__(".data.cacheline_aligned")))
+#endif
+
+#ifndef __cacheline_aligned_in_smp
+#define __cacheline_aligned_in_smp __cacheline_aligned
+#endif
+
+/*
+ * The maximum alignment needed for some critical structures
+ * These could be inter-node cacheline sizes/L3 cacheline
+ * size etc.  Define this in asm/cache.h for your arch
+ */
+#ifndef INTERNODE_CACHE_SHIFT
+#define INTERNODE_CACHE_SHIFT L1_CACHE_SHIFT
+#endif
+
+#if !defined(____cacheline_internodealigned_in_smp)
+#define ____cacheline_internodealigned_in_smp \
+       __attribute__((__aligned__(1 << (INTERNODE_CACHE_SHIFT))))
+#endif
+
+#endif /* _LWK_CACHE_H */
diff --git a/kitten/include/lwk/compiler-gcc.h b/kitten/include/lwk/compiler-gcc.h
new file mode 100644 (file)
index 0000000..dc85d45
--- /dev/null
@@ -0,0 +1,32 @@
+/* Never include this file directly.  Include <lwk/compiler.h> instead.  */
+
+/*
+ * Common definitions for all gcc versions go here.
+ */
+
+
+/* Optimization barrier */
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+/* This macro obfuscates arithmetic on a variable address so that gcc
+   shouldn't recognize the original var, and make assumptions about it */
+/*
+ * Versions of the ppc64 compiler before 4.1 had a bug where use of
+ * RELOC_HIDE could trash r30. The bug can be worked around by changing
+ * the inline assembly constraint from =g to =r, in this particular
+ * case either is valid.
+ */
+#define RELOC_HIDE(ptr, off)                                   \
+  ({ unsigned long __ptr;                                      \
+    __asm__ ("" : "=r"(__ptr) : "0"(ptr));                     \
+    (typeof(ptr)) (__ptr + (off)); })
+
+
+#define inline         inline          __attribute__((always_inline))
+#define __inline__     __inline__      __attribute__((always_inline))
+#define __inline       __inline        __attribute__((always_inline))
+#define __deprecated                   __attribute__((deprecated))
+#define  noinline                      __attribute__((noinline))
+#define __attribute_pure__             __attribute__((pure))
+#define __attribute_const__            __attribute__((__const__))
diff --git a/kitten/include/lwk/compiler-gcc4.h b/kitten/include/lwk/compiler-gcc4.h
new file mode 100644 (file)
index 0000000..83c06d0
--- /dev/null
@@ -0,0 +1,18 @@
+/* Never include this file directly.  Include <lwk/compiler.h> instead.  */
+
+/* These definitions are for GCC v4.x.  */
+#include <lwk/compiler-gcc.h>
+
+#ifdef CONFIG_FORCED_INLINING
+# undef inline
+# undef __inline__
+# undef __inline
+# define inline                        inline          __attribute__((always_inline))
+# define __inline__            __inline__      __attribute__((always_inline))
+# define __inline              __inline        __attribute__((always_inline))
+#endif
+
+#define __attribute_used__     __attribute__((__used__))
+#define __must_check           __attribute__((warn_unused_result))
+#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
+#define __always_inline                inline __attribute__((always_inline))
diff --git a/kitten/include/lwk/compiler.h b/kitten/include/lwk/compiler.h
new file mode 100644 (file)
index 0000000..37de68b
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef _LWK_COMPILER_H
+#define _LWK_COMPILER_H
+
+#ifndef __ASSEMBLY__
+
+#ifdef __CHECKER__
+# define __user                __attribute__((noderef, address_space(1)))
+# define __kernel      /* default address space */
+# define __safe                __attribute__((safe))
+# define __force       __attribute__((force))
+# define __nocast      __attribute__((nocast))
+# define __iomem       __attribute__((noderef, address_space(2)))
+# define __acquires(x) __attribute__((context(0,1)))
+# define __releases(x) __attribute__((context(1,0)))
+# define __acquire(x)  __context__(1)
+# define __release(x)  __context__(-1)
+# define __cond_lock(x)        ((x) ? ({ __context__(1); 1; }) : 0)
+extern void __chk_user_ptr(void __user *);
+extern void __chk_io_ptr(void __iomem *);
+#else
+# define __user
+# define __kernel
+# define __safe
+# define __force
+# define __nocast
+# define __iomem
+# define __chk_user_ptr(x) (void)0
+# define __chk_io_ptr(x) (void)0
+# define __builtin_warning(x, y...) (1)
+# define __acquires(x)
+# define __releases(x)
+# define __acquire(x) (void)0
+# define __release(x) (void)0
+# define __cond_lock(x) (x)
+#endif
+
+#ifdef __KERNEL__
+
+#if __GNUC__ > 4
+#error no compiler-gcc.h file for this gcc version
+#elif __GNUC__ == 4
+# include <lwk/compiler-gcc4.h>
+#else
+# error Sorry, your compiler is too old/not recognized.
+#endif
+
+/*
+ * Generic compiler-dependent macros required for kernel
+ * build go below this comment. Actual compiler/compiler version
+ * specific implementations come from the above header files
+ */
+
+#define likely(x)      __builtin_expect(!!(x), 1)
+#define unlikely(x)    __builtin_expect(!!(x), 0)
+
+/* Optimization barrier */
+#ifndef barrier
+# define barrier() __memory_barrier()
+#endif
+
+#ifndef RELOC_HIDE
+# define RELOC_HIDE(ptr, off)                                  \
+  ({ unsigned long __ptr;                                      \
+     __ptr = (unsigned long) (ptr);                            \
+    (typeof(ptr)) (__ptr + (off)); })
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef __KERNEL__
+/*
+ * Allow us to mark functions as 'deprecated' and have gcc emit a nice
+ * warning for each use, in hopes of speeding the functions removal.
+ * Usage is:
+ *             int __deprecated foo(void)
+ */
+#ifndef __deprecated
+# define __deprecated          /* unimplemented */
+#endif
+
+#ifndef __must_check
+#define __must_check
+#endif
+
+/*
+ * Allow us to avoid 'defined but not used' warnings on functions and data,
+ * as well as force them to be emitted to the assembly file.
+ *
+ * As of gcc 3.3, static functions that are not marked with attribute((used))
+ * may be elided from the assembly file.  As of gcc 3.3, static data not so
+ * marked will not be elided, but this may change in a future gcc version.
+ *
+ * In prior versions of gcc, such functions and data would be emitted, but
+ * would be warned about except with attribute((unused)).
+ */
+#ifndef __attribute_used__
+# define __attribute_used__    /* unimplemented */
+#endif
+
+/*
+ * From the GCC manual:
+ *
+ * Many functions have no effects except the return value and their
+ * return value depends only on the parameters and/or global
+ * variables.  Such a function can be subject to common subexpression
+ * elimination and loop optimization just as an arithmetic operator
+ * would be.
+ * [...]
+ */
+#ifndef __attribute_pure__
+# define __attribute_pure__    /* unimplemented */
+#endif
+
+#ifndef noinline
+#define noinline
+#endif
+
+#ifndef __always_inline
+#define __always_inline inline
+#endif
+
+#endif /* __KERNEL__ */
+
+/*
+ * From the GCC manual:
+ *
+ * Many functions do not examine any values except their arguments,
+ * and have no effects except the return value.  Basically this is
+ * just slightly more strict class than the `pure' attribute above,
+ * since function is not allowed to read global memory.
+ *
+ * Note that a function that has pointer arguments and examines the
+ * data pointed to must _not_ be declared `const'.  Likewise, a
+ * function that calls a non-`const' function usually must not be
+ * `const'.  It does not make sense for a `const' function to return
+ * `void'.
+ */
+#ifndef __attribute_const__
+# define __attribute_const__   /* unimplemented */
+#endif
+
+#endif /* _LWK_COMPILER_H */
diff --git a/kitten/include/lwk/console.h b/kitten/include/lwk/console.h
new file mode 100644 (file)
index 0000000..085c5a0
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _LWK_CONSOLE_H
+#define _LWK_CONSOLE_H
+
+#include <lwk/list.h>
+#include <lwk/compiler.h>
+
+/** Console structure.
+ *
+ * Each console in the system is represented by one of these
+ * structures.  A console driver (e.g., VGA, Serial) fills in
+ * one of these structures and passes it to ::console_register().
+ */
+struct console {
+       char    name[64];
+       void    (*write)(struct console *, const char *);
+       void *  private_data;
+
+       struct list_head next;
+};
+
+extern void console_register(struct console *);
+extern void console_write(const char *);
+extern void console_init(void);
+
+#endif
diff --git a/kitten/include/lwk/const.h b/kitten/include/lwk/const.h
new file mode 100644 (file)
index 0000000..16bf595
--- /dev/null
@@ -0,0 +1,19 @@
+/* const.h: Macros for dealing with constants.  */
+
+#ifndef _LWK_CONST_H
+#define _LWK_CONST_H
+
+/* Some constant macros are used in both assembler and
+ * C code.  Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally.  We
+ * use the following macros to deal with this.
+ */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y)       X
+#else
+#define __AC(X,Y)      (X##Y)
+#define _AC(X,Y)       __AC(X,Y)
+#endif
+
+#endif /* !(_LWK_CONST_H) */
diff --git a/kitten/include/lwk/cpu.h b/kitten/include/lwk/cpu.h
new file mode 100644 (file)
index 0000000..4c3fff6
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _LWK_CPU_H
+#define _LWK_CPU_H
+
+/** Maximum number of CPUs supported. */
+#define NR_CPUS                CONFIG_NR_CPUS
+
+#endif
diff --git a/kitten/include/lwk/cpuinfo.h b/kitten/include/lwk/cpuinfo.h
new file mode 100644 (file)
index 0000000..f7c4152
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _LWK_CPUINFO_H
+#define _LWK_CPUINFO_H
+
+#include <lwk/types.h>
+#include <lwk/cpumask.h>
+#include <lwk/cache.h>
+#include <lwk/aspace.h>
+#include <arch/cpuinfo.h>
+
+/**
+ * CPU information.
+ * Each CPU in the system is described by one of these structures.
+ */
+struct cpuinfo {
+       /* Identification */
+       uint16_t        logical_id;        // CPU's kernel assigned ID
+       uint16_t        physical_id;       // CPU's hardware ID
+
+       /* Topology information */
+       uint16_t        numa_node_id;      // NUMA node ID this CPU is in
+       cpumask_t       numa_node_map;     // CPUs in this CPU's NUMA node
+       cpumask_t       llc_share_map;     // CPUs sharing last level cache
+
+       /* Physical packaging */
+       uint16_t        phys_socket_id;    // Physical socket/package
+       uint16_t        phys_core_id;      // Core ID in the socket/package
+       uint16_t        phys_hwthread_id;  // Hardware thread ID in core
+
+       /* Memory management info */
+       vmpagesize_t    pagesz_mask;       // Page sizes supported by the CPU
+
+       /* Architecture specific */
+       struct arch_cpuinfo arch;
+} ____cacheline_aligned;
+
+extern struct cpuinfo  cpu_info[NR_CPUS];
+extern cpumask_t       cpu_present_map;
+extern cpumask_t       cpu_online_map;
+
+/**
+ * Returns the number of CPUs in the system.
+ */
+#define num_cpus()     cpus_weight(cpu_present_map)
+
+extern void print_cpuinfo(struct cpuinfo *);
+
+#endif
diff --git a/kitten/include/lwk/cpumask.h b/kitten/include/lwk/cpumask.h
new file mode 100644 (file)
index 0000000..026a186
--- /dev/null
@@ -0,0 +1,423 @@
+#ifndef _LWK_CPUMASK_H
+#define _LWK_CPUMASK_H
+
+/*
+ * Cpumasks provide a bitmap suitable for representing the
+ * set of CPU's in a system, one bit position per CPU number.
+ *
+ * See detailed comments in the file linux/bitmap.h describing the
+ * data type on which these cpumasks are based.
+ *
+ * For details of cpumask_scnprintf() and cpumask_parse(),
+ * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ * For details of cpulist_scnprintf() and cpulist_parse(), see
+ * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
+ * For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
+ * For details of cpus_remap(), see bitmap_remap in lib/bitmap.c.
+ *
+ * The available cpumask operations are:
+ *
+ * void cpu_set(cpu, mask)             turn on bit 'cpu' in mask
+ * void cpu_clear(cpu, mask)           turn off bit 'cpu' in mask
+ * void cpus_setall(mask)              set all bits
+ * void cpus_clear(mask)               clear all bits
+ * int cpu_isset(cpu, mask)            true iff bit 'cpu' set in mask
+ * int cpu_test_and_set(cpu, mask)     test and set bit 'cpu' in mask
+ *
+ * void cpus_and(dst, src1, src2)      dst = src1 & src2  [intersection]
+ * void cpus_or(dst, src1, src2)       dst = src1 | src2  [union]
+ * void cpus_xor(dst, src1, src2)      dst = src1 ^ src2
+ * void cpus_andnot(dst, src1, src2)   dst = src1 & ~src2
+ * void cpus_complement(dst, src)      dst = ~src
+ *
+ * int cpus_equal(mask1, mask2)                Does mask1 == mask2?
+ * int cpus_intersects(mask1, mask2)   Do mask1 and mask2 intersect?
+ * int cpus_subset(mask1, mask2)       Is mask1 a subset of mask2?
+ * int cpus_empty(mask)                        Is mask empty (no bits sets)?
+ * int cpus_full(mask)                 Is mask full (all bits sets)?
+ * int cpus_weight(mask)               Hamming weigh - number of set bits
+ *
+ * void cpus_shift_right(dst, src, n)  Shift right
+ * void cpus_shift_left(dst, src, n)   Shift left
+ *
+ * int first_cpu(mask)                 Number lowest set bit, or NR_CPUS
+ * int next_cpu(cpu, mask)             Next cpu past 'cpu', or NR_CPUS
+ *
+ * cpumask_t cpumask_of_cpu(cpu)       Return cpumask with bit 'cpu' set
+ * CPU_MASK_ALL                                Initializer - all bits set
+ * CPU_MASK_NONE                       Initializer - no bits set
+ * unsigned long *cpus_addr(mask)      Array of unsigned long's in mask
+ *
+ * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
+ * int cpumask_parse(ubuf, ulen, mask) Parse ascii string as cpumask
+ * int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
+ * int cpulist_parse(buf, map)         Parse ascii string as cpulist
+ * int cpu_remap(oldbit, old, new)     newbit = map(old, new)(oldbit)
+ * int cpus_remap(dst, src, old, new)  *dst = map(old, new)(src)
+ *
+ * for_each_cpu_mask(cpu, mask)                for-loop cpu over mask
+ *
+ * int num_online_cpus()               Number of online CPUs
+ * int num_possible_cpus()             Number of all possible CPUs
+ * int num_present_cpus()              Number of present CPUs
+ *
+ * int cpu_online(cpu)                 Is some cpu online?
+ * int cpu_possible(cpu)               Is some cpu possible?
+ * int cpu_present(cpu)                        Is some cpu present (can schedule)?
+ *
+ * int any_online_cpu(mask)            First online cpu in mask
+ *
+ * for_each_possible_cpu(cpu)          for-loop cpu over cpu_possible_map
+ * for_each_online_cpu(cpu)            for-loop cpu over cpu_online_map
+ * for_each_present_cpu(cpu)           for-loop cpu over cpu_present_map
+ *
+ * Subtlety:
+ * 1) The 'type-checked' form of cpu_isset() causes gcc (3.3.2, anyway)
+ *    to generate slightly worse code.  Note for example the additional
+ *    40 lines of assembly code compiling the "for each possible cpu"
+ *    loops buried in the disk_stat_read() macros calls when compiling
+ *    drivers/block/genhd.c (arch i386, CONFIG_SMP=y).  So use a simple
+ *    one-line #define for cpu_isset(), instead of wrapping an inline
+ *    inside a macro, the way we do the other calls.
+ */
+
+/**
+ * Fixed size cpumask structure for user-space.
+ * As long as CPU_MAX_ID >= NR_CPUS, we're good to go... 
+ * otherwise we need to bump up CPU_MAX_ID and therefore break
+ * user-level binary compatibility, causing a flag day.
+ */
+
+#define CPU_MIN_ID 0
+#define CPU_MAX_ID 2047
+typedef struct {
+       unsigned long bits[(CPU_MAX_ID+1)/(sizeof(unsigned long) * 8)];
+} user_cpumask_t;
+
+#ifdef __KERNEL__
+
+#include <lwk/kernel.h>
+#include <lwk/bitmap.h>
+#include <lwk/cpu.h>
+
+#if (CPU_MAX_ID + 1 < NR_CPUS)
+#error "NR_CPUS must be <= CPU_MAX_ID"
+#endif
+
+typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
+extern cpumask_t _unused_cpumask_arg_;
+
+static inline void
+cpumask_kernel2user(const cpumask_t *kernel, user_cpumask_t *user)
+{
+       memset(user, 0, sizeof(user_cpumask_t));
+       memcpy(user, kernel, sizeof(*kernel));
+}
+
+static inline void
+cpumask_user2kernel(const user_cpumask_t *user, cpumask_t *kernel)
+{
+       memcpy(kernel, user, sizeof(*kernel));
+}
+
+#define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
+static inline void __cpu_set(int cpu, volatile cpumask_t *dstp)
+{
+       set_bit(cpu, dstp->bits);
+}
+
+#define cpu_clear(cpu, dst) __cpu_clear((cpu), &(dst))
+static inline void __cpu_clear(int cpu, volatile cpumask_t *dstp)
+{
+       clear_bit(cpu, dstp->bits);
+}
+
+#define cpus_setall(dst) __cpus_setall(&(dst), NR_CPUS)
+static inline void __cpus_setall(cpumask_t *dstp, int nbits)
+{
+       bitmap_fill(dstp->bits, nbits);
+}
+
+#define cpus_clear(dst) __cpus_clear(&(dst), NR_CPUS)
+static inline void __cpus_clear(cpumask_t *dstp, int nbits)
+{
+       bitmap_zero(dstp->bits, nbits);
+}
+
+/* No static inline type checking - see Subtlety (1) above. */
+#define cpu_isset(cpu, cpumask) test_bit((cpu), (cpumask).bits)
+
+#define cpu_test_and_set(cpu, cpumask) __cpu_test_and_set((cpu), &(cpumask))
+static inline int __cpu_test_and_set(int cpu, cpumask_t *addr)
+{
+       return test_and_set_bit(cpu, addr->bits);
+}
+
+#define cpus_and(dst, src1, src2) __cpus_and(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_and(cpumask_t *dstp, const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_or(dst, src1, src2) __cpus_or(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_or(cpumask_t *dstp, const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_xor(dst, src1, src2) __cpus_xor(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_xor(cpumask_t *dstp, const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_andnot(dst, src1, src2) \
+                               __cpus_andnot(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_andnot(cpumask_t *dstp, const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_complement(dst, src) __cpus_complement(&(dst), &(src), NR_CPUS)
+static inline void __cpus_complement(cpumask_t *dstp,
+                                       const cpumask_t *srcp, int nbits)
+{
+       bitmap_complement(dstp->bits, srcp->bits, nbits);
+}
+
+#define cpus_equal(src1, src2) __cpus_equal(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_equal(const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       return bitmap_equal(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_intersects(src1, src2) __cpus_intersects(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_intersects(const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       return bitmap_intersects(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_subset(src1, src2) __cpus_subset(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_subset(const cpumask_t *src1p,
+                                       const cpumask_t *src2p, int nbits)
+{
+       return bitmap_subset(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_empty(src) __cpus_empty(&(src), NR_CPUS)
+static inline int __cpus_empty(const cpumask_t *srcp, int nbits)
+{
+       return bitmap_empty(srcp->bits, nbits);
+}
+
+#define cpus_full(cpumask) __cpus_full(&(cpumask), NR_CPUS)
+static inline int __cpus_full(const cpumask_t *srcp, int nbits)
+{
+       return bitmap_full(srcp->bits, nbits);
+}
+
+#define cpus_weight(cpumask) __cpus_weight(&(cpumask), NR_CPUS)
+static inline int __cpus_weight(const cpumask_t *srcp, int nbits)
+{
+       return bitmap_weight(srcp->bits, nbits);
+}
+
+#define cpus_shift_right(dst, src, n) \
+                       __cpus_shift_right(&(dst), &(src), (n), NR_CPUS)
+static inline void __cpus_shift_right(cpumask_t *dstp,
+                                       const cpumask_t *srcp, int n, int nbits)
+{
+       bitmap_shift_right(dstp->bits, srcp->bits, n, nbits);
+}
+
+#define cpus_shift_left(dst, src, n) \
+                       __cpus_shift_left(&(dst), &(src), (n), NR_CPUS)
+static inline void __cpus_shift_left(cpumask_t *dstp,
+                                       const cpumask_t *srcp, int n, int nbits)
+{
+       bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
+}
+
+int __first_cpu(const cpumask_t *srcp);
+#define first_cpu(src) __first_cpu(&(src))
+int __next_cpu(int n, const cpumask_t *srcp);
+#define next_cpu(n, src) __next_cpu((n), &(src))
+
+#define cpumask_of_cpu(cpu)                                            \
+({                                                                     \
+       typeof(_unused_cpumask_arg_) m;                                 \
+       if (sizeof(m) == sizeof(unsigned long)) {                       \
+               m.bits[0] = 1UL<<(cpu);                                 \
+       } else {                                                        \
+               cpus_clear(m);                                          \
+               cpu_set((cpu), m);                                      \
+       }                                                               \
+       m;                                                              \
+})
+
+#define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
+
+#if NR_CPUS <= BITS_PER_LONG
+
+#define CPU_MASK_ALL                                                   \
+(cpumask_t) { {                                                                \
+       [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD                 \
+} }
+
+#else
+
+#define CPU_MASK_ALL                                                   \
+(cpumask_t) { {                                                                \
+       [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL,                        \
+       [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD                 \
+} }
+
+#endif
+
+#define CPU_MASK_NONE                                                  \
+(cpumask_t) { {                                                                \
+       [0 ... BITS_TO_LONGS(NR_CPUS)-1] =  0UL                         \
+} }
+
+#define CPU_MASK_CPU0                                                  \
+(cpumask_t) { {                                                                \
+       [0] =  1UL                                                      \
+} }
+
+#define cpus_addr(src) ((src).bits)
+
+#define cpumask_scnprintf(buf, len, src) \
+                       __cpumask_scnprintf((buf), (len), &(src), NR_CPUS)
+static inline int __cpumask_scnprintf(char *buf, int len,
+                                       const cpumask_t *srcp, int nbits)
+{
+       return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+}
+
+#define cpumask_parse(ubuf, ulen, dst) \
+                       __cpumask_parse((ubuf), (ulen), &(dst), NR_CPUS)
+static inline int __cpumask_parse(const char __user *buf, int len,
+                                       cpumask_t *dstp, int nbits)
+{
+       return bitmap_parse(buf, len, dstp->bits, nbits);
+}
+
+#define cpulist_scnprintf(buf, len, src) \
+                       __cpulist_scnprintf((buf), (len), &(src), NR_CPUS)
+static inline int __cpulist_scnprintf(char *buf, int len,
+                                       const cpumask_t *srcp, int nbits)
+{
+       return bitmap_scnlistprintf(buf, len, srcp->bits, nbits);
+}
+
+#define cpulist_parse(buf, dst) __cpulist_parse((buf), &(dst), NR_CPUS)
+static inline int __cpulist_parse(const char *buf, cpumask_t *dstp, int nbits)
+{
+       return bitmap_parselist(buf, dstp->bits, nbits);
+}
+
+#define cpu_remap(oldbit, old, new) \
+               __cpu_remap((oldbit), &(old), &(new), NR_CPUS)
+static inline int __cpu_remap(int oldbit,
+               const cpumask_t *oldp, const cpumask_t *newp, int nbits)
+{
+       return bitmap_bitremap(oldbit, oldp->bits, newp->bits, nbits);
+}
+
+#define cpus_remap(dst, src, old, new) \
+               __cpus_remap(&(dst), &(src), &(old), &(new), NR_CPUS)
+static inline void __cpus_remap(cpumask_t *dstp, const cpumask_t *srcp,
+               const cpumask_t *oldp, const cpumask_t *newp, int nbits)
+{
+       bitmap_remap(dstp->bits, srcp->bits, oldp->bits, newp->bits, nbits);
+}
+
+#define for_each_cpu_mask(cpu, mask)           \
+       for ((cpu) = first_cpu(mask);           \
+               (cpu) < NR_CPUS;                \
+               (cpu) = next_cpu((cpu), (mask)))
+
+/*
+ * The following particular system cpumasks and operations manage
+ * possible, present and online cpus.  Each of them is a fixed size
+ * bitmap of size NR_CPUS.
+ *
+ *  #ifdef CONFIG_HOTPLUG_CPU
+ *     cpu_possible_map - has bit 'cpu' set iff cpu is populatable
+ *     cpu_present_map  - has bit 'cpu' set iff cpu is populated
+ *     cpu_online_map   - has bit 'cpu' set iff cpu available to scheduler
+ *  #else
+ *     cpu_possible_map - has bit 'cpu' set iff cpu is populated
+ *     cpu_present_map  - copy of cpu_possible_map
+ *     cpu_online_map   - has bit 'cpu' set iff cpu available to scheduler
+ *  #endif
+ *
+ *  In either case, NR_CPUS is fixed at compile time, as the static
+ *  size of these bitmaps.  The cpu_possible_map is fixed at boot
+ *  time, as the set of CPU id's that it is possible might ever
+ *  be plugged in at anytime during the life of that system boot.
+ *  The cpu_present_map is dynamic(*), representing which CPUs
+ *  are currently plugged in.  And cpu_online_map is the dynamic
+ *  subset of cpu_present_map, indicating those CPUs available
+ *  for scheduling.
+ *
+ *  If HOTPLUG is enabled, then cpu_possible_map is forced to have
+ *  all NR_CPUS bits set, otherwise it is just the set of CPUs that
+ *  ACPI reports present at boot.
+ *
+ *  If HOTPLUG is enabled, then cpu_present_map varies dynamically,
+ *  depending on what ACPI reports as currently plugged in, otherwise
+ *  cpu_present_map is just a copy of cpu_possible_map.
+ *
+ *  (*) Well, cpu_present_map is dynamic in the hotplug case.  If not
+ *      hotplug, it's a copy of cpu_possible_map, hence fixed at boot.
+ *
+ * Subtleties:
+ * 1) UP arch's (NR_CPUS == 1, CONFIG_SMP not defined) hardcode
+ *    assumption that their single CPU is online.  The UP
+ *    cpu_{online,possible,present}_maps are placebos.  Changing them
+ *    will have no useful affect on the following num_*_cpus()
+ *    and cpu_*() macros in the UP case.  This ugliness is a UP
+ *    optimization - don't waste any instructions or memory references
+ *    asking if you're online or how many CPUs there are if there is
+ *    only one CPU.
+ * 2) Most SMP arch's #define some of these maps to be some
+ *    other map specific to that arch.  Therefore, the following
+ *    must be #define macros, not inlines.  To see why, examine
+ *    the assembly code produced by the following.  Note that
+ *    set1() writes phys_x_map, but set2() writes x_map:
+ *        int x_map, phys_x_map;
+ *        #define set1(a) x_map = a
+ *        inline void set2(int a) { x_map = a; }
+ *        #define x_map phys_x_map
+ *        main(){ set1(3); set2(5); }
+ */
+
+extern cpumask_t cpu_possible_map;
+extern cpumask_t cpu_online_map;
+extern cpumask_t cpu_present_map;
+
+#define num_online_cpus()      cpus_weight(cpu_online_map)
+#define num_possible_cpus()    cpus_weight(cpu_possible_map)
+#define num_present_cpus()     cpus_weight(cpu_present_map)
+#define cpu_online(cpu)                cpu_isset((cpu), cpu_online_map)
+#define cpu_possible(cpu)      cpu_isset((cpu), cpu_possible_map)
+#define cpu_present(cpu)       cpu_isset((cpu), cpu_present_map)
+
+int highest_possible_processor_id(void);
+#define any_online_cpu(mask) __any_online_cpu(&(mask))
+int __any_online_cpu(const cpumask_t *mask);
+
+#define for_each_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
+#define for_each_possible_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
+#define for_each_online_cpu(cpu)  for_each_cpu_mask((cpu), cpu_online_map)
+#define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map)
+
+#endif
+#endif /* _LWK_CPUMASK_H */
diff --git a/kitten/include/lwk/ctype.h b/kitten/include/lwk/ctype.h
new file mode 100644 (file)
index 0000000..7ed3317
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _LWK_CTYPE_H
+#define _LWK_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U     0x01    /* upper */
+#define _L     0x02    /* lower */
+#define _D     0x04    /* digit */
+#define _C     0x08    /* cntrl */
+#define _P     0x10    /* punct */
+#define _S     0x20    /* white space (space/lf/tab) */
+#define _X     0x40    /* hex digit */
+#define _SP    0x80    /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c)     ((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c)     ((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c)     ((__ismask(c)&(_C)) != 0)
+#define isdigit(c)     ((__ismask(c)&(_D)) != 0)
+#define isgraph(c)     ((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c)     ((__ismask(c)&(_L)) != 0)
+#define isprint(c)     ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c)     ((__ismask(c)&(_P)) != 0)
+#define isspace(c)     ((__ismask(c)&(_S)) != 0)
+#define isupper(c)     ((__ismask(c)&(_U)) != 0)
+#define isxdigit(c)    ((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+       if (isupper(c))
+               c -= 'A'-'a';
+       return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+       if (islower(c))
+               c -= 'a'-'A';
+       return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
diff --git a/kitten/include/lwk/delay.h b/kitten/include/lwk/delay.h
new file mode 100644 (file)
index 0000000..c16675d
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _LWK_DELAY_H
+#define _LWK_DELAY_H
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines, using a pre-computed "loops_per_jiffy" value.
+ */
+
+extern unsigned long loops_per_jiffy;
+
+#include <arch/delay.h>
+
+/*
+ * Using udelay() for intervals greater than a few milliseconds can
+ * risk overflow for high loops_per_jiffy (high bogomips) machines. The
+ * mdelay() provides a wrapper to prevent this.  For delays greater
+ * than MAX_UDELAY_MS milliseconds, the wrapper is used.  Architecture
+ * specific values can be defined in asm-???/delay.h as an override.
+ * The 2nd mdelay() definition ensures GCC will optimize away the 
+ * while loop for the common cases where n <= MAX_UDELAY_MS  --  Paul G.
+ */
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_MS  5
+#endif
+
+#ifdef notdef
+#define mdelay(n) (\
+       {unsigned long __ms=(n); while (__ms--) udelay(1000);})
+#else
+#define mdelay(n) (\
+       (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
+       ({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
+#endif
+
+#ifndef ndelay
+#define ndelay(x)      udelay(((x)+999)/1000)
+#endif
+
+void calibrate_delay(void);
+void msleep(unsigned int msecs);
+unsigned long msleep_interruptible(unsigned int msecs);
+
+static inline void ssleep(unsigned int seconds)
+{
+       msleep(seconds * 1000);
+}
+
+#endif /* defined(_LWK_DELAY_H) */
diff --git a/kitten/include/lwk/driver.h b/kitten/include/lwk/driver.h
new file mode 100644 (file)
index 0000000..d5eebea
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef _LWK_DRIVER_H
+#define _LWK_DRIVER_H
+
+#include <lwk/kernel.h>
+#include <lwk/types.h>
+
+/*
+ * Drivers may set DRIVER_NAME before including this header.
+ * Otherwise, the KBUILD name is used.
+ */
+#ifndef DRIVER_NAME
+#define DRIVER_NAME KBUILD_MODNAME
+#endif
+
+/*
+ * Driver parameter names have the form:
+ *
+ *      driver_name.parameter_name
+ *
+ * Example:
+ * To set integer parameter foo in driver bar, add this
+ * to the kernel boot command line:
+ *
+ *      bar.foo=1
+ */
+#define __DRIVER_PARAM_PREFIX  DRIVER_NAME "."
+
+/*
+ * For driver parameters.  Parameters can be configured via the
+ * kernel boot command line or some other platform-dependent
+ * runtime mechanism.
+ */
+#include <lwk/params.h>
+
+#define driver_param(name, type) \
+       __param_named(__DRIVER_PARAM_PREFIX, name, name, type)
+
+#define driver_param_named(name, value, type) \
+       __param_named(__DRIVER_PARAM_PREFIX, name, value, type)
+
+#define driver_param_string(name, string, len) \
+       __param_string(__DRIVER_PARAM_PREFIX, name, string, len)
+
+#define driver_param_array(name, type, nump) \
+       __param_array_named(__DRIVER_PARAM_PREFIX, name, name, type, nump)
+
+#define driver_param_array_named(name, array, type, nump) \
+       __param_array_named(__DRIVER_PARAM_PREFIX, name, array, type, nump)
+
+/*
+ * Every driver defines one of these structures via the
+ * driver_init() macro.  The structure gets placed in the 
+ * __driver_table ELF section and the kernel walks this table
+ * to find/initialize all drivers in the system.
+ */
+struct driver_info {
+       const char *    name;           // name of the driver
+       void            (*init)(void);  // driver initialization function
+       int             init_called;    // set when .init() has been called,
+                                       // used to prevent double inits.
+};
+
+/*
+ * This adds a function to the __driver_table ELF section.
+ */
+#define driver_init(init_func)                                                 \
+       static char __driver_name[] = DRIVER_NAME;                      \
+       static struct driver_info const __driver_info                   \
+       __attribute_used__                                              \
+       __attribute__ ((unused,__section__ ("__driver_table"),          \
+                       aligned(sizeof(void *))))                       \
+       = { __driver_name, init_func };
+
+/*
+ * The __driver_table ELF section is surrounded by these symbols,
+ * which are defined in the platform's linker script.
+ */
+extern struct driver_info __start___driver_table[];
+extern struct driver_info __stop___driver_table[];
+
+/*
+ * This is a placeholder.  Currently drivers are never unloaded once loaded.
+ */
+#define driver_exit(exit_func) 
+
+extern int driver_init_by_name(const char *name);
+
+#endif
diff --git a/kitten/include/lwk/elf-em.h b/kitten/include/lwk/elf-em.h
new file mode 100644 (file)
index 0000000..083a6be
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _LWK_ELF_EM_H
+#define _LWK_ELF_EM_H
+
+/* These constants define the various ELF target machines */
+#define EM_NONE                0
+#define EM_X86_64      62      /* AMD x86-64 */
+
+#endif /* _LWK_ELF_EM_H */
diff --git a/kitten/include/lwk/elf.h b/kitten/include/lwk/elf.h
new file mode 100644 (file)
index 0000000..46aee1e
--- /dev/null
@@ -0,0 +1,464 @@
+#ifndef _LWK_ELF_H
+#define _LWK_ELF_H
+
+#include <lwk/types.h>
+#include <lwk/task.h>
+#include <lwk/elf-em.h>
+#include <arch/elf.h>
+
+struct file;
+
+#ifndef elf_read_implies_exec
+  /* Executables for which elf_read_implies_exec() returns TRUE will
+     have the READ_IMPLIES_EXEC personality flag set automatically.
+     Override in asm/elf.h as needed.  */
+# define elf_read_implies_exec(ex, have_pt_gnu_stack)  0
+#endif
+
+/* 32-bit ELF base types. */
+typedef __u32  Elf32_Addr;
+typedef __u16  Elf32_Half;
+typedef __u32  Elf32_Off;
+typedef __s32  Elf32_Sword;
+typedef __u32  Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef __u64  Elf64_Addr;
+typedef __u16  Elf64_Half;
+typedef __s16  Elf64_SHalf;
+typedef __u64  Elf64_Off;
+typedef __s32  Elf64_Sword;
+typedef __u32  Elf64_Word;
+typedef __u64  Elf64_Xword;
+typedef __s64  Elf64_Sxword;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL    0
+#define PT_LOAD    1
+#define PT_DYNAMIC 2
+#define PT_INTERP  3
+#define PT_NOTE    4
+#define PT_SHLIB   5
+#define PT_PHDR    6
+#define PT_TLS     7               /* Thread local storage segment */
+#define PT_LOOS    0x60000000      /* OS-specific */
+#define PT_HIOS    0x6fffffff      /* OS-specific */
+#define PT_LOPROC  0x70000000
+#define PT_HIPROC  0x7fffffff
+#define PT_GNU_EH_FRAME                0x6474e550
+
+#define PT_GNU_STACK   (PT_LOOS + 0x474e551)
+
+/* These constants define the different elf file types */
+#define ET_NONE   0
+#define ET_REL    1
+#define ET_EXEC   2
+#define ET_DYN    3
+#define ET_CORE   4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* This is the info that is needed to parse the dynamic section of the file */
+#define DT_NULL                0
+#define DT_NEEDED      1
+#define DT_PLTRELSZ    2
+#define DT_PLTGOT      3
+#define DT_HASH                4
+#define DT_STRTAB      5
+#define DT_SYMTAB      6
+#define DT_RELA                7
+#define DT_RELASZ      8
+#define DT_RELAENT     9
+#define DT_STRSZ       10
+#define DT_SYMENT      11
+#define DT_INIT                12
+#define DT_FINI                13
+#define DT_SONAME      14
+#define DT_RPATH       15
+#define DT_SYMBOLIC    16
+#define DT_REL         17
+#define DT_RELSZ       18
+#define DT_RELENT      19
+#define DT_PLTREL      20
+#define DT_DEBUG       21
+#define DT_TEXTREL     22
+#define DT_JMPREL      23
+#define DT_ENCODING    32
+#define OLD_DT_LOOS    0x60000000
+#define DT_LOOS                0x6000000d
+#define DT_HIOS                0x6ffff000
+#define DT_VALRNGLO    0x6ffffd00
+#define DT_VALRNGHI    0x6ffffdff
+#define DT_ADDRRNGLO   0x6ffffe00
+#define DT_ADDRRNGHI   0x6ffffeff
+#define DT_VERSYM      0x6ffffff0
+#define DT_RELACOUNT   0x6ffffff9
+#define DT_RELCOUNT    0x6ffffffa
+#define DT_FLAGS_1     0x6ffffffb
+#define DT_VERDEF      0x6ffffffc
+#define        DT_VERDEFNUM    0x6ffffffd
+#define DT_VERNEED     0x6ffffffe
+#define        DT_VERNEEDNUM   0x6fffffff
+#define OLD_DT_HIOS     0x6fffffff
+#define DT_LOPROC      0x70000000
+#define DT_HIPROC      0x7fffffff
+
+/* This info is needed when parsing the symbol table */
+#define STB_LOCAL  0
+#define STB_GLOBAL 1
+#define STB_WEAK   2
+
+#define STT_NOTYPE  0
+#define STT_OBJECT  1
+#define STT_FUNC    2
+#define STT_SECTION 3
+#define STT_FILE    4
+#define STT_COMMON  5
+#define STT_TLS     6
+
+#define ELF_ST_BIND(x)         ((x) >> 4)
+#define ELF_ST_TYPE(x)         (((unsigned int) x) & 0xf)
+#define ELF32_ST_BIND(x)       ELF_ST_BIND(x)
+#define ELF32_ST_TYPE(x)       ELF_ST_TYPE(x)
+#define ELF64_ST_BIND(x)       ELF_ST_BIND(x)
+#define ELF64_ST_TYPE(x)       ELF_ST_TYPE(x)
+
+typedef struct dynamic{
+  Elf32_Sword d_tag;
+  union{
+    Elf32_Sword        d_val;
+    Elf32_Addr d_ptr;
+  } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+  Elf64_Sxword d_tag;          /* entry tag value */
+  union {
+    Elf64_Xword d_val;
+    Elf64_Addr d_ptr;
+  } d_un;
+} Elf64_Dyn;
+
+/* The following are used with relocations */
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+
+#define ELF64_R_SYM(i)                 ((i) >> 32)
+#define ELF64_R_TYPE(i)                        ((i) & 0xffffffff)
+
+typedef struct elf32_rel {
+  Elf32_Addr   r_offset;
+  Elf32_Word   r_info;
+} Elf32_Rel;
+
+typedef struct elf64_rel {
+  Elf64_Addr r_offset; /* Location at which to apply the action */
+  Elf64_Xword r_info;  /* index and type of relocation */
+} Elf64_Rel;
+
+typedef struct elf32_rela{
+  Elf32_Addr   r_offset;
+  Elf32_Word   r_info;
+  Elf32_Sword  r_addend;
+} Elf32_Rela;
+
+typedef struct elf64_rela {
+  Elf64_Addr r_offset; /* Location at which to apply the action */
+  Elf64_Xword r_info;  /* index and type of relocation */
+  Elf64_Sxword r_addend;       /* Constant addend used to compute value */
+} Elf64_Rela;
+
+typedef struct elf32_sym{
+  Elf32_Word   st_name;
+  Elf32_Addr   st_value;
+  Elf32_Word   st_size;
+  unsigned char        st_info;
+  unsigned char        st_other;
+  Elf32_Half   st_shndx;
+} Elf32_Sym;
+
+typedef struct elf64_sym {
+  Elf64_Word st_name;          /* Symbol name, index in string tbl */
+  unsigned char        st_info;        /* Type and binding attributes */
+  unsigned char        st_other;       /* No defined meaning, 0 */
+  Elf64_Half st_shndx;         /* Associated section index */
+  Elf64_Addr st_value;         /* Value of the symbol */
+  Elf64_Xword st_size;         /* Associated symbol size */
+} Elf64_Sym;
+
+
+#define EI_NIDENT      16
+
+typedef struct elf32_hdr{
+  unsigned char        e_ident[EI_NIDENT];
+  Elf32_Half   e_type;
+  Elf32_Half   e_machine;
+  Elf32_Word   e_version;
+  Elf32_Addr   e_entry;  /* Entry point */
+  Elf32_Off    e_phoff;
+  Elf32_Off    e_shoff;
+  Elf32_Word   e_flags;
+  Elf32_Half   e_ehsize;
+  Elf32_Half   e_phentsize;
+  Elf32_Half   e_phnum;
+  Elf32_Half   e_shentsize;
+  Elf32_Half   e_shnum;
+  Elf32_Half   e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+  unsigned char        e_ident[16];            /* ELF "magic number" */
+  Elf64_Half e_type;
+  Elf64_Half e_machine;
+  Elf64_Word e_version;
+  Elf64_Addr e_entry;          /* Entry point virtual address */
+  Elf64_Off e_phoff;           /* Program header table file offset */
+  Elf64_Off e_shoff;           /* Section header table file offset */
+  Elf64_Word e_flags;
+  Elf64_Half e_ehsize;
+  Elf64_Half e_phentsize;
+  Elf64_Half e_phnum;
+  Elf64_Half e_shentsize;
+  Elf64_Half e_shnum;
+  Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* These constants define the permissions on sections in the program
+   header, p_flags. */
+#define PF_R           0x4
+#define PF_W           0x2
+#define PF_X           0x1
+
+typedef struct elf32_phdr{
+  Elf32_Word   p_type;
+  Elf32_Off    p_offset;
+  Elf32_Addr   p_vaddr;
+  Elf32_Addr   p_paddr;
+  Elf32_Word   p_filesz;
+  Elf32_Word   p_memsz;
+  Elf32_Word   p_flags;
+  Elf32_Word   p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+  Elf64_Word p_type;
+  Elf64_Word p_flags;
+  Elf64_Off p_offset;          /* Segment file offset */
+  Elf64_Addr p_vaddr;          /* Segment virtual address */
+  Elf64_Addr p_paddr;          /* Segment physical address */
+  Elf64_Xword p_filesz;                /* Segment size in file */
+  Elf64_Xword p_memsz;         /* Segment size in memory */
+  Elf64_Xword p_align;         /* Segment alignment, file & memory */
+} Elf64_Phdr;
+
+/* sh_type */
+#define SHT_NULL       0
+#define SHT_PROGBITS   1
+#define SHT_SYMTAB     2
+#define SHT_STRTAB     3
+#define SHT_RELA       4
+#define SHT_HASH       5
+#define SHT_DYNAMIC    6
+#define SHT_NOTE       7
+#define SHT_NOBITS     8
+#define SHT_REL                9
+#define SHT_SHLIB      10
+#define SHT_DYNSYM     11
+#define SHT_NUM                12
+#define SHT_LOPROC     0x70000000
+#define SHT_HIPROC     0x7fffffff
+#define SHT_LOUSER     0x80000000
+#define SHT_HIUSER     0xffffffff
+
+/* sh_flags */
+#define SHF_WRITE      0x1
+#define SHF_ALLOC      0x2
+#define SHF_EXECINSTR  0x4
+#define SHF_MASKPROC   0xf0000000
+
+/* special section indexes */
+#define SHN_UNDEF      0
+#define SHN_LORESERVE  0xff00
+#define SHN_LOPROC     0xff00
+#define SHN_HIPROC     0xff1f
+#define SHN_ABS                0xfff1
+#define SHN_COMMON     0xfff2
+#define SHN_HIRESERVE  0xffff
+typedef struct {
+  Elf32_Word   sh_name;
+  Elf32_Word   sh_type;
+  Elf32_Word   sh_flags;
+  Elf32_Addr   sh_addr;
+  Elf32_Off    sh_offset;
+  Elf32_Word   sh_size;
+  Elf32_Word   sh_link;
+  Elf32_Word   sh_info;
+  Elf32_Word   sh_addralign;
+  Elf32_Word   sh_entsize;
+} Elf32_Shdr;
+
+typedef struct elf64_shdr {
+  Elf64_Word sh_name;          /* Section name, index in string tbl */
+  Elf64_Word sh_type;          /* Type of section */
+  Elf64_Xword sh_flags;                /* Miscellaneous section attributes */
+  Elf64_Addr sh_addr;          /* Section virtual addr at execution */
+  Elf64_Off sh_offset;         /* Section file offset */
+  Elf64_Xword sh_size;         /* Size of section in bytes */
+  Elf64_Word sh_link;          /* Index of another section */
+  Elf64_Word sh_info;          /* Additional section information */
+  Elf64_Xword sh_addralign;    /* Section alignment */
+  Elf64_Xword sh_entsize;      /* Entry size if section holds table */
+} Elf64_Shdr;
+
+#define        EI_MAG0         0               /* e_ident[] indexes */
+#define        EI_MAG1         1
+#define        EI_MAG2         2
+#define        EI_MAG3         3
+#define        EI_CLASS        4
+#define        EI_DATA         5
+#define        EI_VERSION      6
+#define        EI_OSABI        7
+#define        EI_PAD          8
+
+#define        ELFMAG0         0x7f            /* EI_MAG */
+#define        ELFMAG1         'E'
+#define        ELFMAG2         'L'
+#define        ELFMAG3         'F'
+#define        ELFMAG          "\177ELF"
+#define        SELFMAG         4
+
+#define        ELFCLASSNONE    0               /* EI_CLASS */
+#define        ELFCLASS32      1
+#define        ELFCLASS64      2
+#define        ELFCLASSNUM     3
+
+#define ELFDATANONE    0               /* e_ident[EI_DATA] */
+#define ELFDATA2LSB    1
+#define ELFDATA2MSB    2
+
+#define EV_NONE                0               /* e_version, EI_VERSION */
+#define EV_CURRENT     1
+#define EV_NUM         2
+
+#define ELFOSABI_NONE  0
+#define ELFOSABI_LINUX 3
+
+#ifndef ELF_OSABI
+#define ELF_OSABI ELFOSABI_NONE
+#endif
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS    1
+#define NT_PRFPREG     2
+#define NT_PRPSINFO    3
+#define NT_TASKSTRUCT  4
+#define NT_AUXV                6
+#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
+
+
+/* Note header in a PT_NOTE section */
+typedef struct elf32_note {
+  Elf32_Word   n_namesz;       /* Name size */
+  Elf32_Word   n_descsz;       /* Content size */
+  Elf32_Word   n_type;         /* Content type */
+} Elf32_Nhdr;
+
+/* Note header in a PT_NOTE section */
+typedef struct elf64_note {
+  Elf64_Word n_namesz; /* Name size */
+  Elf64_Word n_descsz; /* Content size */
+  Elf64_Word n_type;   /* Content type */
+} Elf64_Nhdr;
+
+#if ELF_CLASS == ELFCLASS32
+
+extern Elf32_Dyn _DYNAMIC [];
+#define elfhdr         elf32_hdr
+#define elf_phdr       elf32_phdr
+#define elf_note       elf32_note
+#define elf_addr_t     Elf32_Off
+
+#else
+
+extern Elf64_Dyn _DYNAMIC [];
+#define elfhdr         elf64_hdr
+#define elf_phdr       elf64_phdr
+#define elf_note       elf64_note
+#define elf_addr_t     Elf64_Off
+
+#endif
+
+#ifndef ARCH_HAVE_EXTRA_ELF_NOTES
+static inline int arch_notes_size(void) { return 0; }
+static inline void arch_write_notes(struct file *file) { }
+
+#define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size()
+#define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file)
+#endif /* ARCH_HAVE_EXTRA_ELF_NOTES */
+
+#include <lwk/types.h>
+#include <lwk/idspace.h>
+#include <lwk/aspace.h>
+
+int elf_check_hdr(const struct elfhdr *hdr);
+void elf_print_elfhdr(const struct elfhdr *hdr);
+void elf_print_phdr(const struct elf_phdr *hdr);
+vmflags_t elf_pflags_to_vmflags(unsigned int elf_flags);
+vaddr_t elf_entry_point(const void *elf_image);
+vaddr_t elf_phdr_table_addr(const void *elf_image);
+unsigned int elf_num_phdrs(const void *elf_image);
+vaddr_t elf_heap_start(const void *elf_image);
+int elf_init_str_array(size_t size, char *ptrs[], char *str);
+paddr_t elf_dflt_alloc_pmem(size_t size, size_t alignment, uintptr_t arg);
+
+int
+elf_init_stack(
+       void *    elf_image,
+       void *    stack_mapping,
+       vaddr_t   stack_start,
+       size_t    stack_extent,
+       char *    argv[],
+       char *    envp[],
+       uid_t     uid,
+       gid_t     gid,
+       uint32_t  hwcap,
+       vaddr_t * stack_ptr
+);
+
+int
+elf_load_executable(
+       void *       elf_image,
+       paddr_t      elf_image_paddr,
+       id_t         aspace_id,
+       vmpagesize_t pagesz,
+       uintptr_t    alloc_pmem_arg,
+       paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
+);
+
+int
+elf_load(
+       void *          elf_image,
+       paddr_t         elf_image_paddr,
+       const char *    name,
+       id_t            desired_aspace_id,
+       vmpagesize_t    pagesz,
+       size_t          heap_size,
+       size_t          stack_size,
+       char *          argv_str,
+       char *          envp_str,
+       start_state_t * start_state,
+       uintptr_t       alloc_pmem_arg,
+       paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
+);
+
+/**
+ * ELF related system calls.
+ */
+extern int elf_hwcap(id_t cpu, uint32_t *hwcap);
+
+#ifdef __KERNEL__
+extern int sys_elf_hwcap(id_t cpu, uint32_t __user *hwcap);
+#endif
+
+#endif /* _LWK_ELF_H */
diff --git a/kitten/include/lwk/errno.h b/kitten/include/lwk/errno.h
new file mode 100644 (file)
index 0000000..3c57b67
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _LWK_ERRNO_H
+#define _LWK_ERRNO_H
+
+#include <arch/errno.h>
+
+#ifdef __KERNEL__
+
+/* Should never be seen by user programs */
+#define ERESTARTSYS    512
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514     /* restart if no handler.. */
+#define ENOIOCTLCMD    515     /* No ioctl command */
+#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
+
+/* Defined for the NFSv3 protocol */
+#define EBADHANDLE     521     /* Illegal NFS file handle */
+#define ENOTSYNC       522     /* Update synchronization mismatch */
+#define EBADCOOKIE     523     /* Cookie is stale */
+#define ENOTSUPP       524     /* Operation is not supported */
+#define ETOOSMALL      525     /* Buffer or request is too small */
+#define ESERVERFAULT   526     /* An untranslatable error occurred */
+#define EBADTYPE       527     /* Type not supported by server */
+#define EJUKEBOX       528     /* Request initiated, but will not complete before timeout */
+#define EIOCBQUEUED    529     /* iocb queued, will get completion event */
+#define EIOCBRETRY     530     /* iocb queued, will trigger a retry */
+
+#endif
+
+#endif
diff --git a/kitten/include/lwk/extable.h b/kitten/include/lwk/extable.h
new file mode 100644 (file)
index 0000000..0c51dca
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _LWK_EXTABLE_H
+#define _LWK_EXTABLE_H
+
+#include <lwk/init.h>
+#include <arch/extable.h>
+
+extern void __init
+sort_exception_table(void);
+
+extern const struct exception_table_entry *
+search_exception_table(unsigned long);
+
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+               const struct exception_table_entry *last,
+               unsigned long value);
+
+void
+sort_extable(struct exception_table_entry *start,
+             struct exception_table_entry *finish);
+
+#endif
diff --git a/kitten/include/lwk/hash.h b/kitten/include/lwk/hash.h
new file mode 100644 (file)
index 0000000..842c958
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef _LINUX_HASH_H
+#define _LINUX_HASH_H
+/* Fast hashing routine for ints,  longs and pointers.
+   (C) 2002 William Lee Irwin III, IBM */
+
+/*
+ * Knuth recommends primes in approximately golden ratio to the maximum
+ * integer representable by a machine word for multiplicative hashing.
+ * Chuck Lever verified the effectiveness of this technique:
+ * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
+ *
+ * These primes are chosen to be bit-sparse, that is operations on
+ * them can use shifts and additions instead of multiplications for
+ * machines where multiplications are slow.
+ */
+
+#include <arch/types.h>
+
+/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
+#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
+/*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
+#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
+
+#if BITS_PER_LONG == 32
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32
+#define hash_long(val, bits) hash_32(val, bits)
+#elif BITS_PER_LONG == 64
+#define hash_long(val, bits) hash_64(val, bits)
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64
+#else
+#error Wordsize not 32 or 64
+#endif
+
+static inline u64 hash_64(u64 val, unsigned int bits)
+{
+       u64 hash = val;
+
+       /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
+       u64 n = hash;
+       n <<= 18;
+       hash -= n;
+       n <<= 33;
+       hash -= n;
+       n <<= 3;
+       hash += n;
+       n <<= 3;
+       hash -= n;
+       n <<= 4;
+       hash += n;
+       n <<= 2;
+       hash += n;
+
+       /* High bits are more random, so use them. */
+       return hash >> (64 - bits);
+}
+
+static inline u32 hash_32(u32 val, unsigned int bits)
+{
+       /* On some cpus multiply is faster, on others gcc will do shifts */
+       u32 hash = val * GOLDEN_RATIO_PRIME_32;
+
+       /* High bits are more random, so use them. */
+       return hash >> (32 - bits);
+}
+
+static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
+{
+       return hash_long((unsigned long)ptr, bits);
+}
+#endif /* _LINUX_HASH_H */
diff --git a/kitten/include/lwk/htable.h b/kitten/include/lwk/htable.h
new file mode 100644 (file)
index 0000000..feac02b
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#ifndef _LWK_HTABLE_H
+#define _LWK_HTABLE_H
+
+#include <lwk/idspace.h>
+
+/**
+ * Hash table object.
+ */
+typedef void * htable_t;
+
+/**
+ * Hash table API.
+ */
+extern int htable_create(size_t tbl_order,
+                         size_t obj_key_offset, size_t obj_link_offset,
+                         htable_t *tbl);
+extern int htable_destroy(htable_t tbl);
+extern int htable_add(htable_t tbl, void *obj);
+extern int htable_del(htable_t tbl, void *obj);
+extern void *htable_lookup(htable_t tbl, id_t key);
+
+#endif
diff --git a/kitten/include/lwk/idspace.h b/kitten/include/lwk/idspace.h
new file mode 100644 (file)
index 0000000..e70de80
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#ifndef _LWK_IDSPACE_H
+#define _LWK_IDSPACE_H
+
+/**
+ * ID space object.
+ * An ID space consists of a range of IDs and keeps track of which are
+ * allocated and which are available for allocation.
+ */
+typedef void * idspace_t;
+
+/**
+ * Numeric identifier type.
+ */
+typedef unsigned int id_t;
+
+/**
+ * Used to request any available ID... pass as 'request' arg to id_alloc().
+ */
+#define ANY_ID (-1)
+
+/**
+ * ID space API.
+ */
+int idspace_create(id_t min_id, id_t max_id, idspace_t *idspace);
+int idspace_destroy(idspace_t idspace);
+int idspace_alloc_id(idspace_t idspace, id_t request, id_t *id);
+int idspace_free_id(idspace_t idspace, id_t id);
+
+#endif
diff --git a/kitten/include/lwk/init.h b/kitten/include/lwk/init.h
new file mode 100644 (file)
index 0000000..abb2cd7
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _LWK_INIT_H
+#define _LWK_INIT_H
+
+#include <lwk/compiler.h>
+
+/* These macros are used to mark some functions or 
+ * initialized data (doesn't apply to uninitialized data)
+ * as `initialization' functions. The kernel can take this
+ * as hint that the function is used only during the initialization
+ * phase and free up used memory resources after
+ *
+ * Usage:
+ * For functions:
+ * 
+ * You should add __init immediately before the function name, like:
+ *
+ * static void __init initme(int x, int y)
+ * {
+ *    extern int z; z = x * y;
+ * }
+ *
+ * If the function has a prototype somewhere, you can also add
+ * __init between closing brace of the prototype and semicolon:
+ *
+ * extern int initialize_foobar_device(int, int, int) __init;
+ *
+ * For initialized data:
+ * You should insert __initdata between the variable name and equal
+ * sign followed by value, e.g.:
+ *
+ * static int init_variable __initdata = 0;
+ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ *
+ * Don't forget to initialize data not at file scope, i.e. within a function,
+ * as gcc otherwise puts the data into the bss section and not into the init
+ * section.
+ * 
+ * Also note, that this data cannot be "const".
+ */
+
+/* These are for everybody (although not all archs will actually
+   discard it in modules) */
+#define __init         __attribute__ ((__section__ (".init.text")))
+#define __meminit      __init
+#define __cpuinit      __init
+#define __initdata     __attribute__ ((__section__ (".init.data")))
+#define __exitdata     __attribute__ ((__section__(".exit.data")))
+#define __exit_call    __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
+#define __exit         __attribute_used__ __attribute__ ((__section__(".exit.text")))
+#define __cpuinitdata  __initdata
+
+/* For assembly routines */
+#define __INIT         .section        ".init.text","ax"
+#define __FINIT                .previous
+#define __INITDATA     .section        ".init.data","aw"
+
+/* TODO: move this */
+#define COMMAND_LINE_SIZE       1024
+
+#ifndef __ASSEMBLY__
+
+#include <lwk/types.h>
+
+/* Defined in init/main.c */
+extern char lwk_command_line[COMMAND_LINE_SIZE];
+
+/* used by init/main.c */
+extern void setup_arch(void);
+
+extern void start_kernel(void);
+
+extern int create_init_task(void);
+extern paddr_t init_elf_image;
+
+#endif /* !__ASSEMBLY__ */
+  
+#endif /* _LWK_INIT_H */
diff --git a/kitten/include/lwk/init_task.h b/kitten/include/lwk/init_task.h
new file mode 100644 (file)
index 0000000..c703a3c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _LWK_INIT_TASK_H
+#define _LWK_INIT_TASK_H
+
+/**
+ * Initializes architecture-independent fields in the initial address space.
+ */
+#define BOOTSTRAP_ASPACE(name)
+
+/**
+ * Initializes architecture-independent fields in the initial task structure.
+ */
+#define BOOTSTRAP_TASK(task_info) \
+       .id             =       0,                                      \
+       .name           =       "bootstrap",                            \
+       .cpu_id         =       0,                                      \
+       .aspace         =       &bootstrap_aspace,                      \
+       .sched_link     =       LIST_HEAD_INIT(task_info.sched_link),   \
+
+#define bootstrap_task  bootstrap_task_union.task_info
+#define bootstrap_stack bootstrap_task_union.stack
+
+#endif
diff --git a/kitten/include/lwk/interrupt.h b/kitten/include/lwk/interrupt.h
new file mode 100644 (file)
index 0000000..0a7ad5f
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _LWK_INTERRUPT_H
+#define _LWK_INTERRUPT_H
+
+/**
+ * IRQ handler return type.
+ *
+ *    IRQ_NONE means we didn't handle the interrupt.
+ *    IRQ_HANDLED means we did handle the interrupt.
+ *    IRQ_RETVAL(x) returns IRQ_HANDLED if x is non-zero, IRQ_NONE otherwise.
+ */
+typedef int irqreturn_t;
+#define IRQ_NONE       (0)
+#define IRQ_HANDLED    (1)
+#define IRQ_RETVAL     ((x) != 0)
+
+/**
+ * IRQ handler prototype.
+ */
+typedef irqreturn_t (*irq_handler_t)(unsigned int irq, void *dev_id);
+
+/**
+ * Registers an interrupt handler.
+ */
+extern int request_irq(unsigned int    irq,
+                       irq_handler_t   handler,
+                       unsigned long   irqflags,
+                       const char      *devname,
+                       void            *dev_id);
+
+/**
+ * Unregisters an interrupt handler.
+ */
+extern void free_irq(unsigned int irq, void *dev_id);
+
+#endif
diff --git a/kitten/include/lwk/kallsyms.h b/kitten/include/lwk/kallsyms.h
new file mode 100644 (file)
index 0000000..d2b55f6
--- /dev/null
@@ -0,0 +1,17 @@
+/* Rewritten and vastly simplified by Rusty Russell for in-kernel
+ * module loader:
+ *   Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ */
+#ifndef _LWK_KALLSYMS_H
+#define _LWK_KALLSYMS_H
+
+#define KSYM_NAME_LEN 127
+
+unsigned long kallsyms_lookup_name(const char *name);
+
+const char *kallsyms_lookup(unsigned long addr,
+                           unsigned long *symbolsize,
+                           unsigned long *offset,
+                           char *namebuf);
+
+#endif /* _LWK_KALLSYMS_H */
diff --git a/kitten/include/lwk/kernel.h b/kitten/include/lwk/kernel.h
new file mode 100644 (file)
index 0000000..b0a6824
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef _LWK_KERNEL_H
+#define _LWK_KERNEL_H
+
+/*
+ * 'kernel.h' contains some often used function prototypes etc
+ */
+
+#include <stdarg.h>
+#include <lwk/linkage.h>
+#include <lwk/stddef.h>
+#include <lwk/types.h>
+#include <lwk/compiler.h>
+#include <lwk/kmem.h>
+#include <lwk/errno.h>
+#include <lwk/utsname.h>
+#include <lwk/print.h>
+#include <arch/byteorder.h>
+#include <arch/bug.h>
+
+extern const char lwk_banner[];
+extern struct utsname linux_utsname;
+
+#define INT_MAX         ((int)(~0U>>1))
+#define INT_MIN         (-INT_MAX - 1)
+#define UINT_MAX        (~0U)
+#define LONG_MAX        ((long)(~0UL>>1))
+#define LONG_MIN        (-LONG_MAX - 1)
+#define ULONG_MAX       (~0UL)
+
+#define STACK_MAGIC     0xdeadbeef
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+void panic(const char * fmt, ...);
+
+extern unsigned long simple_strtoul(const char *,char **,unsigned int);
+extern long simple_strtol(const char *,char **,unsigned int);
+extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
+extern long long simple_strtoll(const char *,char **,unsigned int);
+extern int get_option(char **str, int *pint);
+extern char *get_options(const char *str, int nints, int *ints);
+extern unsigned long long memparse(char *ptr, char **retptr);
+
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x > _y ? _x : _y; })
+
+/*
+ * ..and if you can't take the strict
+ * types, you can specify one yourself.
+ *
+ * Or not use min/max at all, of course.
+ */
+#define min_t(type,x,y) \
+       ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+       ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+/*
+ * Round x up to the nearest y aligned boundary.  y must be a power of two.
+ */
+#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
+
+/*
+ * Round x down to the nearest y aligned boundary.  y must be a power of two.
+ */
+#define round_down(x,y) ((x) & ~((y)-1))
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ */
+#define container_of(ptr, type, member) ({                     \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * Check at compile time that something is of a particular type.
+ * Always evaluates to 1 so you may use it easily in comparisons.
+ */
+#define typecheck(type,x) \
+({     type __dummy; \
+       typeof(x) __dummy2; \
+       (void)(&__dummy == &__dummy2); \
+       1; \
+})
+
+/*
+ * Check at compile time that 'function' is a certain type, or is a pointer
+ * to that type (needs to use typedef for the function type.)
+ */
+#define typecheck_fn(type,function) \
+({     typeof(type) __tmp = function; \
+       (void)__tmp; \
+})
+
+/*
+ * Check at compile time that 'type' is a multiple of align.
+ */
+#define aligncheck(type,align) \
+       extern int __align_check[ (sizeof(type) % (align) == 0 ? 0 : 1/0) ]
+
+/*
+ * Check at compile time that the type 'type' has the expected 'size'.
+ * NOTE: 'type' must be a single word, so this doesn't work for structures.
+ *       For structures, use sizecheck_struct().
+ */
+#define sizecheck(type,size) \
+       extern int __size_check_##type[ (sizeof(type) == (size) ? 0 : 1/0) ]
+
+/*
+ * Check at compile time that the structure 'name' has the expected size 'size'.
+ */
+#define sizecheck_struct(name,size) \
+       extern int __size_check_struct_##name[ (sizeof(struct name) == (size) ? 0 : 1/0) ]
+
+/*
+ * Force a compilation error if condition is true
+ */
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+
+#endif
diff --git a/kitten/include/lwk/kmem.h b/kitten/include/lwk/kmem.h
new file mode 100644 (file)
index 0000000..553f982
--- /dev/null
@@ -0,0 +1,15 @@
+/* Copyright (c) 2007, Sandia National Laboratories */
+
+#ifndef _LWK_KMEM_H
+#define _LWK_KMEM_H
+
+void kmem_create_zone(unsigned long base_addr, size_t size);
+void kmem_add_memory(unsigned long base_addr, size_t size);
+
+void *kmem_alloc(size_t size);
+void kmem_free(void *addr);
+
+void * kmem_get_pages(unsigned long order);
+void kmem_free_pages(void *addr, unsigned long order);
+
+#endif
diff --git a/kitten/include/lwk/liblwk.h b/kitten/include/lwk/liblwk.h
new file mode 120000 (symlink)
index 0000000..99c9b24
--- /dev/null
@@ -0,0 +1 @@
+../../user/liblwk/include/lwk/liblwk.h
\ No newline at end of file
diff --git a/kitten/include/lwk/linkage.h b/kitten/include/lwk/linkage.h
new file mode 100644 (file)
index 0000000..832627b
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _LWK_LINKAGE_H
+#define _LWK_LINKAGE_H
+
+#include <arch/linkage.h>
+
+#ifdef __cplusplus
+#define CPP_ASMLINKAGE extern "C"
+#else
+#define CPP_ASMLINKAGE
+#endif
+
+#ifndef asmlinkage
+#define asmlinkage CPP_ASMLINKAGE
+#endif
+
+#ifndef prevent_tail_call
+# define prevent_tail_call(ret) do { } while (0)
+#endif
+
+#ifndef __ALIGN
+#define __ALIGN                .align 4,0x90
+#define __ALIGN_STR    ".align 4,0x90"
+#endif
+
+#ifdef __ASSEMBLY__
+
+#define ALIGN __ALIGN
+#define ALIGN_STR __ALIGN_STR
+
+#ifndef ENTRY
+#define ENTRY(name) \
+  .globl name; \
+  ALIGN; \
+  name:
+#endif
+
+#define KPROBE_ENTRY(name) \
+  .section .kprobes.text, "ax"; \
+  ENTRY(name)
+
+#ifndef END
+#define END(name) \
+  .size name, .-name
+#endif
+
+#ifndef ENDPROC
+#define ENDPROC(name) \
+  .type name, @function; \
+  END(name)
+#endif
+
+#endif
+
+#define NORET_TYPE    /**/
+#define ATTRIB_NORET  __attribute__((noreturn))
+#define NORET_AND     noreturn,
+
+#ifndef FASTCALL
+#define FASTCALL(x)    x
+#define fastcall
+#endif
+
+#endif
diff --git a/kitten/include/lwk/linux_compat.h b/kitten/include/lwk/linux_compat.h
new file mode 100644 (file)
index 0000000..9257b3c
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _LWK_LINUX_COMPAT_H
+#define _LWK_LINUX_COMPAT_H
+
+/* Mostly Linux stuff that is not implemented or supported in LWK */
+
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)
+#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
+#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
+
+#endif
diff --git a/kitten/include/lwk/list.h b/kitten/include/lwk/list.h
new file mode 100644 (file)
index 0000000..d50bdbd
--- /dev/null
@@ -0,0 +1,532 @@
+#ifndef _LWK_LIST_H
+#define _LWK_LIST_H
+
+#ifdef __KERNEL__
+
+#include <lwk/stddef.h>
+#include <lwk/prefetch.h>
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+static inline void list_head_init(struct list_head *list)
+{
+       INIT_LIST_HEAD(list);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = LIST_POISON1;
+       entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                 struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+       return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+       struct list_head *next = head->next;
+       return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+                                struct list_head *head)
+{
+       struct list_head *first = list->next;
+       struct list_head *last = list->prev;
+       struct list_head *at = head->next;
+
+       first->prev = head;
+       head->next = first;
+
+       last->next = at;
+       at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+       if (!list_empty(list))
+               __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+                                   struct list_head *head)
+{
+       if (!list_empty(list)) {
+               __list_splice(list, head);
+               INIT_LIST_HEAD(list);
+       }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+               pos = pos->next)
+
+/**
+ * __list_for_each     -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev  -       iterate over a list backwards
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+       for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+               pos = pos->prev)
+
+/**
+ * list_for_each_safe  -       iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry -       iterate over list of given type
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_entry((head)->next, typeof(*pos), member);      \
+            prefetch(pos->member.next), &pos->member != (head);        \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)                 \
+       for (pos = list_entry((head)->prev, typeof(*pos), member);      \
+            prefetch(pos->member.prev), &pos->member != (head);        \
+            pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ *                     list_for_each_entry_continue
+ * @pos:       the type * to use as a start point
+ * @head:      the head of the list
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+       ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue -      iterate over list of given type
+ *                     continuing after existing point
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member)                \
+       for (pos = list_entry(pos->member.next, typeof(*pos), member);  \
+            prefetch(pos->member.next), &pos->member != (head);        \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from -  iterate over list of given type
+ *                     continuing from existing point
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_from(pos, head, member)                    \
+       for (; prefetch(pos->member.next), &pos->member != (head);      \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_entry((head)->next, typeof(*pos), member),      \
+               n = list_entry(pos->member.next, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue - iterate over list of given type
+ *                     continuing after existing point safe against removal of list entry
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member)                \
+       for (pos = list_entry(pos->member.next, typeof(*pos), member),          \
+               n = list_entry(pos->member.next, typeof(*pos), member);         \
+            &pos->member != (head);                                            \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list of given type
+ *                     from existing point safe against removal of list entry
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member)                    \
+       for (n = list_entry(pos->member.next, typeof(*pos), member);            \
+            &pos->member != (head);                                            \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
+ *                                   removal of list entry
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)         \
+       for (pos = list_entry((head)->prev, typeof(*pos), member),      \
+               n = list_entry(pos->member.prev, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+       struct hlist_node *first;
+};
+
+struct hlist_node {
+       struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+       h->next = NULL;
+       h->pprev = NULL;
+}
+
+static inline void hlist_node_init(struct hlist_node *h)
+{
+       INIT_HLIST_NODE(h);
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+       return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+       return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+       struct hlist_node *next = n->next;
+       struct hlist_node **pprev = n->pprev;
+       *pprev = next;
+       if (next)
+               next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+       __hlist_del(n);
+       n->next = LIST_POISON1;
+       n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+       if (!hlist_unhashed(n)) {
+               __hlist_del(n);
+               INIT_HLIST_NODE(n);
+       }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+       struct hlist_node *first = h->first;
+       n->next = first;
+       if (first)
+               first->pprev = &n->next;
+       h->first = n;
+       n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+                                       struct hlist_node *next)
+{
+       n->pprev = next->pprev;
+       n->next = next;
+       next->pprev = &n->next;
+       *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+                                       struct hlist_node *next)
+{
+       next->next = n->next;
+       n->next = next;
+       next->pprev = &n->next;
+
+       if(next->next)
+               next->next->pprev  = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+       for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+            pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+       for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+            pos = n)
+
+/**
+ * hlist_for_each_entry        - iterate over list of given type
+ * @tpos:      the type * to use as a loop counter.
+ * @pos:       the &struct hlist_node to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)                   \
+       for (pos = (head)->first;                                        \
+            pos && ({ prefetch(pos->next); 1;}) &&                      \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos:      the type * to use as a loop counter.
+ * @pos:       the &struct hlist_node to use as a loop counter.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)                \
+       for (pos = (pos)->next;                                          \
+            pos && ({ prefetch(pos->next); 1;}) &&                      \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos:      the type * to use as a loop counter.
+ * @pos:       the &struct hlist_node to use as a loop counter.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)                    \
+       for (; pos && ({ prefetch(pos->next); 1;}) &&                    \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos:      the type * to use as a loop counter.
+ * @pos:       the &struct hlist_node to use as a loop counter.
+ * @n:         another &struct hlist_node to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member)           \
+       for (pos = (head)->first;                                        \
+            pos && ({ n = pos->next; 1; }) &&                           \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+            pos = n)
+
+#else
+#warning "don't include kernel headers in userspace"
+#endif /* __KERNEL__ */
+#endif
diff --git a/kitten/include/lwk/log2.h b/kitten/include/lwk/log2.h
new file mode 100644 (file)
index 0000000..ac2aa63
--- /dev/null
@@ -0,0 +1,168 @@
+/* Integer base 2 logarithm calculation
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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 _LWK_LOG2_H
+#define _LWK_LOG2_H
+
+#include <lwk/types.h>
+#include <lwk/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const, noreturn))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ *   more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+#ifndef CONFIG_ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+       return fls(n) - 1;
+}
+#endif
+
+#ifndef CONFIG_ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+       return fls64(n) - 1;
+}
+#endif
+
+/*
+ *  Determine whether some value is a power of two, where zero is
+ * *not* considered a power of two.
+ */
+
+static inline __attribute__((const))
+bool is_power_of_2(unsigned long n)
+{
+       return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/*
+ * round up to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __roundup_pow_of_two(unsigned long n)
+{
+       return 1UL << fls_long(n - 1);
+}
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ *   the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n)                               \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               (n) < 1 ? ____ilog2_NaN() :     \
+               (n) & (1ULL << 63) ? 63 :       \
+               (n) & (1ULL << 62) ? 62 :       \
+               (n) & (1ULL << 61) ? 61 :       \
+               (n) & (1ULL << 60) ? 60 :       \
+               (n) & (1ULL << 59) ? 59 :       \
+               (n) & (1ULL << 58) ? 58 :       \
+               (n) & (1ULL << 57) ? 57 :       \
+               (n) & (1ULL << 56) ? 56 :       \
+               (n) & (1ULL << 55) ? 55 :       \
+               (n) & (1ULL << 54) ? 54 :       \
+               (n) & (1ULL << 53) ? 53 :       \
+               (n) & (1ULL << 52) ? 52 :       \
+               (n) & (1ULL << 51) ? 51 :       \
+               (n) & (1ULL << 50) ? 50 :       \
+               (n) & (1ULL << 49) ? 49 :       \
+               (n) & (1ULL << 48) ? 48 :       \
+               (n) & (1ULL << 47) ? 47 :       \
+               (n) & (1ULL << 46) ? 46 :       \
+               (n) & (1ULL << 45) ? 45 :       \
+               (n) & (1ULL << 44) ? 44 :       \
+               (n) & (1ULL << 43) ? 43 :       \
+               (n) & (1ULL << 42) ? 42 :       \
+               (n) & (1ULL << 41) ? 41 :       \
+               (n) & (1ULL << 40) ? 40 :       \
+               (n) & (1ULL << 39) ? 39 :       \
+               (n) & (1ULL << 38) ? 38 :       \
+               (n) & (1ULL << 37) ? 37 :       \
+               (n) & (1ULL << 36) ? 36 :       \
+               (n) & (1ULL << 35) ? 35 :       \
+               (n) & (1ULL << 34) ? 34 :       \
+               (n) & (1ULL << 33) ? 33 :       \
+               (n) & (1ULL << 32) ? 32 :       \
+               (n) & (1ULL << 31) ? 31 :       \
+               (n) & (1ULL << 30) ? 30 :       \
+               (n) & (1ULL << 29) ? 29 :       \
+               (n) & (1ULL << 28) ? 28 :       \
+               (n) & (1ULL << 27) ? 27 :       \
+               (n) & (1ULL << 26) ? 26 :       \
+               (n) & (1ULL << 25) ? 25 :       \
+               (n) & (1ULL << 24) ? 24 :       \
+               (n) & (1ULL << 23) ? 23 :       \
+               (n) & (1ULL << 22) ? 22 :       \
+               (n) & (1ULL << 21) ? 21 :       \
+               (n) & (1ULL << 20) ? 20 :       \
+               (n) & (1ULL << 19) ? 19 :       \
+               (n) & (1ULL << 18) ? 18 :       \
+               (n) & (1ULL << 17) ? 17 :       \
+               (n) & (1ULL << 16) ? 16 :       \
+               (n) & (1ULL << 15) ? 15 :       \
+               (n) & (1ULL << 14) ? 14 :       \
+               (n) & (1ULL << 13) ? 13 :       \
+               (n) & (1ULL << 12) ? 12 :       \
+               (n) & (1ULL << 11) ? 11 :       \
+               (n) & (1ULL << 10) ? 10 :       \
+               (n) & (1ULL <<  9) ?  9 :       \
+               (n) & (1ULL <<  8) ?  8 :       \
+               (n) & (1ULL <<  7) ?  7 :       \
+               (n) & (1ULL <<  6) ?  6 :       \
+               (n) & (1ULL <<  5) ?  5 :       \
+               (n) & (1ULL <<  4) ?  4 :       \
+               (n) & (1ULL <<  3) ?  3 :       \
+               (n) & (1ULL <<  2) ?  2 :       \
+               (n) & (1ULL <<  1) ?  1 :       \
+               (n) & (1ULL <<  0) ?  0 :       \
+               ____ilog2_NaN()                 \
+                                  ) :          \
+       (sizeof(n) <= 4) ?                      \
+       __ilog2_u32(n) :                        \
+       __ilog2_u64(n)                          \
+ )
+
+/**
+ * roundup_pow_of_two - round the given value up to nearest power of two
+ * @n - parameter
+ *
+ * round the given value up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two(n)                  \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               (n == 1) ? 1 :                  \
+               (1UL << (ilog2((n) - 1) + 1))   \
+                                  ) :          \
+       __roundup_pow_of_two(n)                 \
+ )
+
+#endif /* _LWK_LOG2_H */
diff --git a/kitten/include/lwk/palacios.h b/kitten/include/lwk/palacios.h
new file mode 100644 (file)
index 0000000..270b538
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (c) 2007,2008 Sandia National Laboratories */
+
+#ifndef _LWK_PALACIOS_H_
+#define _LWK_PALACIOS_H_
+
+#ifdef CONFIG_V3VEE
+
+#include <lwk/types.h>
+#include <palacios/vmm.h>
+#include <palacios/vmm_host_events.h>
+
+extern struct guest_info * g_vm_guest;
+
+
+extern void
+v3vee_init_stubs( void );
+
+
+extern int
+v3vee_run_vmm( void );
+
+
+extern struct v3_os_hooks v3vee_os_hooks;
+
+/**** 
+ * 
+ * stubs called by geekos....
+ * 
+ ***/
+void send_key_to_vmm(unsigned char status, unsigned char scancode);
+void send_mouse_to_vmm(unsigned char packet[3]);
+void send_tick_to_vmm(unsigned int period_us);
+
+
+/* Location of the ROM Bios and VGA Bios used by palacios */
+extern uint8_t rombios_start, rombios_end;
+extern uint8_t vgabios_start, vgabios_end;
+extern paddr_t initrd_start, initrd_end;
+
+
+#endif // CONFIG_V3VEE
+
+#endif
diff --git a/kitten/include/lwk/params.h b/kitten/include/lwk/params.h
new file mode 100644 (file)
index 0000000..d333e71
--- /dev/null
@@ -0,0 +1,164 @@
+#ifndef _LWK_PARAMS_H
+#define _LWK_PARAMS_H
+/* (C) Copyright 2001, 2002 Rusty Russell IBM Corporation */
+#include <lwk/init.h>
+#include <lwk/stringify.h>
+#include <lwk/kernel.h>
+
+struct kernel_param;
+
+/* Returns 0, or -errno.  arg is in kp->arg. */
+typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
+/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
+typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
+
+struct kernel_param {
+       const char *    name;
+       param_set_fn    set;
+       param_get_fn    get;
+       void *          arg;
+};
+
+/* Special one for strings we want to copy into */
+struct kparam_string {
+       unsigned int    maxlen;
+       char *          string;
+};
+
+/* Special one for arrays */
+struct kparam_array {
+       unsigned int    max;
+       unsigned int *  num;
+       param_set_fn    set;
+       param_get_fn    get;
+       unsigned int    elemsize;
+       void *          elem;
+};
+
+/* This is the fundamental function for registering kernel parameters. */
+#define __param_call(prefix, name, set, get, arg)                      \
+       static char __param_str_##name[] = prefix #name;                \
+       static struct kernel_param const __param_##name                 \
+       __attribute_used__                                              \
+    __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
+       = { __param_str_##name, set, get, arg }
+
+/* Helper functions: type is byte, short, ushort, int, uint, long,
+   ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
+   param_set_XXX and param_check_XXX. */
+#define __param_named(prefix, name, value, type)                       \
+       param_check_##type(name, &(value));                             \
+       __param_call(prefix, name, param_set_##type, param_get_##type, &value)
+
+/* Actually copy string: maxlen param is usually sizeof(string). */
+#define __param_string(prefix, name, string, len)                      \
+       static struct kparam_string __param_string_##name               \
+               = { len, string };                                      \
+       __param_call(prefix, name, param_set_copystring,                \
+                  param_get_string, &__param_string_##name)
+
+/* Comma-separated array: *nump is set to number they actually specified. */
+#define __param_array_named(prefix, name, array, type, nump)           \
+       static struct kparam_array __param_arr_##name                   \
+       = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
+           sizeof(array[0]), array };                                  \
+       __param_call(prefix, name, param_array_set, param_array_get,    \
+                         &__param_arr_##name)
+
+/* Call a function to parse the parameter */
+#define __param_func(prefix, name, func)                               \
+       __param_call(prefix, name, func, NULL, NULL)
+
+/*
+ * Basic parameter interface.  These are just raw... they have no prefix.
+ */
+#define param(name, type) \
+       __param_named("", name, name, type)
+
+#define param_named(name, value, type) \
+       __param_named("", name, value, type)
+
+#define param_string(name, string, len) \
+       __param_string("", name, string, len)
+
+#define param_array(name, type, nump) \
+       __param_array_named("", name, name, type, nump)
+
+#define param_array_named(name, array, type, nump) \
+       __param_array_named("", name, array, type, nump)
+
+#define param_func(name, func) \
+       __param_func("", name, func)
+
+/* Called at kernel boot */
+extern int parse_args(const char *name,
+                     char *args,
+                     struct kernel_param *params,
+                     unsigned num,
+                     int (*unknown)(char *param, char *val));
+
+/* All the helper functions */
+/* The macros to do compile-time type checking stolen from Jakub
+   Jelinek, who IIRC came up with this idea for the 2.4 module init code. */
+#define __param_check(name, p, type) \
+       static inline type *__check_##name(void) { return(p); }
+
+extern int param_set_byte(const char *val, struct kernel_param *kp);
+extern int param_get_byte(char *buffer, struct kernel_param *kp);
+#define param_check_byte(name, p) __param_check(name, p, unsigned char)
+
+extern int param_set_short(const char *val, struct kernel_param *kp);
+extern int param_get_short(char *buffer, struct kernel_param *kp);
+#define param_check_short(name, p) __param_check(name, p, short)
+
+extern int param_set_ushort(const char *val, struct kernel_param *kp);
+extern int param_get_ushort(char *buffer, struct kernel_param *kp);
+#define param_check_ushort(name, p) __param_check(name, p, unsigned short)
+
+extern int param_set_int(const char *val, struct kernel_param *kp);
+extern int param_get_int(char *buffer, struct kernel_param *kp);
+#define param_check_int(name, p) __param_check(name, p, int)
+
+extern int param_set_uint(const char *val, struct kernel_param *kp);
+extern int param_get_uint(char *buffer, struct kernel_param *kp);
+#define param_check_uint(name, p) __param_check(name, p, unsigned int)
+
+extern int param_set_long(const char *val, struct kernel_param *kp);
+extern int param_get_long(char *buffer, struct kernel_param *kp);
+#define param_check_long(name, p) __param_check(name, p, long)
+
+extern int param_set_ulong(const char *val, struct kernel_param *kp);
+extern int param_get_ulong(char *buffer, struct kernel_param *kp);
+#define param_check_ulong(name, p) __param_check(name, p, unsigned long)
+
+extern int param_set_charp(const char *val, struct kernel_param *kp);
+extern int param_get_charp(char *buffer, struct kernel_param *kp);
+#define param_check_charp(name, p) __param_check(name, p, char *)
+
+extern int param_set_bool(const char *val, struct kernel_param *kp);
+extern int param_get_bool(char *buffer, struct kernel_param *kp);
+#define param_check_bool(name, p) __param_check(name, p, int)
+
+extern int param_set_invbool(const char *val, struct kernel_param *kp);
+extern int param_get_invbool(char *buffer, struct kernel_param *kp);
+#define param_check_invbool(name, p) __param_check(name, p, int)
+
+extern int param_array_set(const char *val, struct kernel_param *kp);
+extern int param_array_get(char *buffer, struct kernel_param *kp);
+
+extern int param_set_copystring(const char *val, struct kernel_param *kp);
+extern int param_get_string(char *buffer, struct kernel_param *kp);
+
+extern int parse_params(const char *str);
+extern int param_set_by_name_int(char *param, int val);
+
+/*
+ * These two symbols are defined by the platform's linker script.
+ * They surround a table of kernel parameter descriptors.  This table
+ * is used by the command line parser to determine how each argument
+ * should be handled... each encountered argument causes a search of
+ * this table.
+ */
+extern struct kernel_param __start___param[], __stop___param[];
+
+#endif /* _LWK_PARAMS_H */
diff --git a/kitten/include/lwk/percpu.h b/kitten/include/lwk/percpu.h
new file mode 100644 (file)
index 0000000..2e31649
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _LWK_PERCPU_H
+#define _LWK_PERCPU_H
+#include <lwk/smp.h>
+#include <lwk/string.h>
+#include <arch/percpu.h>
+
+/* Enough to cover all DEFINE_PER_CPU()'s in kernel. */
+#ifndef PERCPU_ENOUGH_ROOM
+#define PERCPU_ENOUGH_ROOM 32768
+#endif
+
+/* Must be an lvalue. */
+#define get_cpu_var(var) __get_cpu_var(var)
+#define put_cpu_var(var) 
+
+struct percpu_data {
+       void *ptrs[NR_CPUS];
+};
+
+/* 
+ * Use this to get to a cpu's version of the per-cpu object allocated using
+ * alloc_percpu.  Non-atomic access to the current CPU's version should
+ * probably be combined with get_cpu()/put_cpu().
+ */ 
+#define per_cpu_ptr(ptr, cpu)                   \
+({                                              \
+        struct percpu_data *__p = (struct percpu_data *)~(unsigned long)(ptr); \
+        (__typeof__(ptr))__p->ptrs[(cpu)];     \
+})
+
+extern void *__alloc_percpu(size_t size);
+extern void free_percpu(const void *);
+
+/* Simple wrapper for the common case: zeros memory. */
+#define alloc_percpu(type)     ((type *)(__alloc_percpu(sizeof(type))))
+
+extern void setup_per_cpu_areas(void);
+
+#endif /* _LWK_PERCPU_H */
diff --git a/kitten/include/lwk/pfn.h b/kitten/include/lwk/pfn.h
new file mode 100644 (file)
index 0000000..8d01aed
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _LWK_PFN_H
+#define _LWK_PFN_H
+
+#define PFN_ALIGN(x)   (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
+#define PFN_UP(x)      (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)    ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)    ((x) << PAGE_SHIFT)
+
+#endif
diff --git a/kitten/include/lwk/pmem.h b/kitten/include/lwk/pmem.h
new file mode 100644 (file)
index 0000000..d00d6e9
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#ifndef _LWK_PMEM_H
+#define _LWK_PMEM_H
+
+/**
+ * Physical memory types.
+ */
+typedef enum {
+       PMEM_TYPE_BOOTMEM     = 0,  /* memory allocated at boot-time */
+       PMEM_TYPE_BIGPHYSAREA = 1,  /* memory set-aside for a device/driver */
+       PMEM_TYPE_INITRD      = 2,  /* initrd image provided by bootloader */
+       PMEM_TYPE_INIT_TASK   = 3,  /* memory used by the initial task */
+       PMEM_TYPE_KMEM        = 4,  /* memory managed by the kernel */
+       PMEM_TYPE_UMEM        = 5,  /* memory managed by user-space */
+} pmem_type_t;
+
+/**
+ * Defines a physical memory region.
+ */
+struct pmem_region {
+       paddr_t         start;             /* region occupies: [start, end) */
+       paddr_t         end;
+
+       bool            type_is_set;       /* type field is set? */
+       pmem_type_t     type;              /* physical memory type */
+
+       bool            lgroup_is_set;     /* lgroup field is set? */
+       lgroup_t        lgroup;            /* locality group region is in */
+
+       bool            allocated_is_set;  /* allocated field set? */
+       bool            allocated;         /* region is allocated? */ 
+
+       bool            name_is_set;       /* name field is set? */
+       char            name[32];          /* human-readable name of region */
+
+};
+
+/**
+ * Core physical memory management functions.
+ */
+int pmem_add(const struct pmem_region *rgn);
+int pmem_update(const struct pmem_region *update);
+int pmem_query(const struct pmem_region *query, struct pmem_region *result);
+int pmem_alloc(size_t size, size_t alignment,
+               const struct pmem_region *constraint,
+               struct pmem_region *result);
+
+/**
+ * Convenience functions.
+ */
+void pmem_region_unset_all(struct pmem_region *rgn);
+const char *pmem_type_to_string(pmem_type_t type);
+int pmem_alloc_umem(size_t size, size_t alignment, struct pmem_region *rgn);
+bool pmem_is_umem(paddr_t start, size_t extent);
+
+#ifdef __KERNEL__
+
+/**
+ * System call handlers.
+ */
+int sys_pmem_add(const struct pmem_region __user * rgn);
+int sys_pmem_update(const struct pmem_region __user * update);
+int sys_pmem_query(const struct pmem_region __user * query,
+                   struct pmem_region __user * result);
+int sys_pmem_alloc(size_t size, size_t alignment,
+                   const struct pmem_region __user *constraint,
+                   struct pmem_region __user *result);
+
+#endif
+#endif
diff --git a/kitten/include/lwk/posix_types.h b/kitten/include/lwk/posix_types.h
new file mode 100644 (file)
index 0000000..16bd915
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _LWK_POSIX_TYPES_H
+#define _LWK_POSIX_TYPES_H
+
+#include <lwk/stddef.h>
+
+/*
+ * This allows for 1024 file descriptors: if NR_OPEN is ever grown
+ * beyond that you'll have to change this too. But 1024 fd's seem to be
+ * enough even for such "real" unices like OSF/1, so hopefully this is
+ * one limit that doesn't have to be changed [again].
+ *
+ * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in
+ * <sys/time.h> (and thus <linux/time.h>) - but this is a more logical
+ * place for them. Solved by having dummy defines in <sys/time.h>.
+ */
+
+/*
+ * Those macros may have been defined in <gnu/types.h>. But we always
+ * use the ones here. 
+ */
+#undef __NFDBITS
+#define __NFDBITS      (8 * sizeof(unsigned long))
+
+#undef __FD_SETSIZE
+#define __FD_SETSIZE   1024
+
+#undef __FDSET_LONGS
+#define __FDSET_LONGS  (__FD_SETSIZE/__NFDBITS)
+
+#undef __FDELT
+#define        __FDELT(d)      ((d) / __NFDBITS)
+
+#undef __FDMASK
+#define        __FDMASK(d)     (1UL << ((d) % __NFDBITS))
+
+typedef struct {
+       unsigned long fds_bits [__FDSET_LONGS];
+} __kernel_fd_set;
+
+/* Type of a signal handler.  */
+typedef void (*__kernel_sighandler_t)(int);
+
+/* Type of a SYSV IPC key.  */
+typedef int __kernel_key_t;
+typedef int __kernel_mqd_t;
+
+#include <arch/posix_types.h>
+
+#endif /* _LWK_POSIX_TYPES_H */
diff --git a/kitten/include/lwk/prefetch.h b/kitten/include/lwk/prefetch.h
new file mode 100644 (file)
index 0000000..4be0445
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  Generic cache management functions. Everything is arch-specific,  
+ *  but this header exists to make sure the defines/functions can be
+ *  used in a generic way.
+ *
+ *  2000-11-13  Arjan van de Ven   <arjan@fenrus.demon.nl>
+ *
+ */
+
+#ifndef _LWK_PREFETCH_H
+#define _LWK_PREFETCH_H
+
+#include <lwk/types.h>
+#include <arch/processor.h>
+#include <arch/cache.h>
+
+/*
+       prefetch(x) attempts to pre-emptively get the memory pointed to
+       by address "x" into the CPU L1 cache. 
+       prefetch(x) should not cause any kind of exception, prefetch(0) is
+       specifically ok.
+
+       prefetch() should be defined by the architecture, if not, the 
+       #define below provides a no-op define.  
+       
+       There are 3 prefetch() macros:
+       
+       prefetch(x)     - prefetches the cacheline at "x" for read
+       prefetchw(x)    - prefetches the cacheline at "x" for write
+       spin_lock_prefetch(x) - prefectches the spinlock *x for taking
+       
+       there is also PREFETCH_STRIDE which is the architecure-prefered 
+       "lookahead" size for prefetching streamed operations.
+       
+*/
+
+/*
+ *     These cannot be do{}while(0) macros. See the mental gymnastics in
+ *     the loop macro.
+ */
+#ifndef ARCH_HAS_PREFETCH
+static inline void prefetch(const void *x) {;}
+#endif
+
+#ifndef ARCH_HAS_PREFETCHW
+static inline void prefetchw(const void *x) {;}
+#endif
+
+#ifndef ARCH_HAS_SPINLOCK_PREFETCH
+#define spin_lock_prefetch(x) prefetchw(x)
+#endif
+
+#ifndef PREFETCH_STRIDE
+#define PREFETCH_STRIDE (4*L1_CACHE_BYTES)
+#endif
+
+static inline void prefetch_range(void *addr, size_t len)
+{
+#ifdef ARCH_HAS_PREFETCH
+       char *cp;
+       char *end = addr + len;
+
+       for (cp = addr; cp < end; cp += PREFETCH_STRIDE)
+               prefetch(cp);
+#endif
+}
+
+#endif
diff --git a/kitten/include/lwk/print.h b/kitten/include/lwk/print.h
new file mode 100644 (file)
index 0000000..d940305
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef _LWK_PRINT_H
+#define _LWK_PRINT_H
+
+#define KERN_EMERG     "<0>"   /* system is unusable                   */
+#define KERN_ALERT     "<1>"   /* action must be taken immediately     */
+#define KERN_CRIT      "<2>"   /* critical conditions                  */
+#define KERN_ERR       "<3>"   /* error conditions                     */
+#define KERN_WARNING   "<4>"   /* warning conditions                   */
+#define KERN_NOTICE    "<5>"   /* normal but significant condition     */
+#define KERN_INFO      "<6>"   /* informational                        */
+#define KERN_DEBUG     "<7>"   /* debug-level messages                 */
+#define KERN_USERMSG   "<8>"   /* message from user-space              */
+#define KERN_NORM      "<9>"   /* a "normal" message, nothing special  */
+
+#define USER_EMERG     "<0>"   /* system is unusable                   */
+#define USER_ALERT     "<1>"   /* action must be taken immediately     */
+#define USER_CRIT      "<2>"   /* critical conditions                  */
+#define USER_ERR       "<3>"   /* error conditions                     */
+#define USER_WARNING   "<4>"   /* warning conditions                   */
+#define USER_NOTICE    "<5>"   /* normal but significant condition     */
+#define USER_INFO      "<6>"   /* informational                        */
+#define USER_DEBUG     "<7>"   /* debug-level messages                 */
+#define USER_USERMSG   "<8>"   /* message from user-space              */
+#define USER_NORM      ""      /* a "normal" message, nothing special  */
+
+#ifdef __KERNEL__
+#define TYPE_EMERG     KERN_EMERG
+#define TYPE_ALERT     KERN_ALERT
+#define TYPE_CRIT      KERN_CRIT
+#define TYPE_ERR       KERN_ERR
+#define TYPE_WARNING   KERN_WARNING
+#define TYPE_NOTICE    KERN_NOTICE
+#define TYPE_INFO      KERN_INFO
+#define TYPE_DEBUG     KERN_DEBUG
+#define TYPE_USERMSG   KERN_USERMSG
+#define TYPE_NORM      KERN_NORM
+#else
+#define TYPE_EMERG     USER_EMERG
+#define TYPE_ALERT     USER_ALERT
+#define TYPE_CRIT      USER_CRIT
+#define TYPE_ERR       USER_ERR
+#define TYPE_WARNING   USER_WARNING
+#define TYPE_NOTICE    USER_NOTICE
+#define TYPE_INFO      USER_INFO
+#define TYPE_DEBUG     USER_DEBUG
+#define TYPE_USERMSG   USER_USERMSG
+#define TYPE_NORM      USER_NORM
+#endif
+
+#ifdef __KERNEL__
+#include <stdarg.h>
+#include <lwk/types.h>
+extern int sprintf(char * buf, const char * fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+extern int vsprintf(char *buf, const char *, va_list)
+       __attribute__ ((format (printf, 2, 0)));
+extern int snprintf(char * buf, size_t size, const char * fmt, ...)
+       __attribute__ ((format (printf, 3, 4)));
+extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+       __attribute__ ((format (printf, 3, 0)));
+extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
+       __attribute__ ((format (printf, 3, 4)));
+extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+       __attribute__ ((format (printf, 3, 0)));
+extern int vprintk(const char *fmt, va_list args)
+        __attribute__ ((format (printf, 1, 0)));
+extern int printk(const char * fmt, ...)
+        __attribute__ ((format (printf, 1, 2)));
+#define print printk
+#else
+#include <stdio.h>
+#include <stdarg.h>
+#define print printf
+#endif
+
+#endif
diff --git a/kitten/include/lwk/ptrace.h b/kitten/include/lwk/ptrace.h
new file mode 100644 (file)
index 0000000..22dc49f
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef _LWK_PTRACE_H
+#define _LWK_PTRACE_H
+/* ptrace.h */
+/* structs and defines to help the user use the ptrace system call. */
+
+/* has the defines to get at the registers. */
+
+#define PTRACE_TRACEME            0
+#define PTRACE_PEEKTEXT                   1
+#define PTRACE_PEEKDATA                   2
+#define PTRACE_PEEKUSR            3
+#define PTRACE_POKETEXT                   4
+#define PTRACE_POKEDATA                   5
+#define PTRACE_POKEUSR            6
+#define PTRACE_CONT               7
+#define PTRACE_KILL               8
+#define PTRACE_SINGLESTEP         9
+
+#define PTRACE_ATTACH          0x10
+#define PTRACE_DETACH          0x11
+
+#define PTRACE_SYSCALL           24
+
+/* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+#define PTRACE_SETOPTIONS      0x4200
+#define PTRACE_GETEVENTMSG     0x4201
+#define PTRACE_GETSIGINFO      0x4202
+#define PTRACE_SETSIGINFO      0x4203
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD  0x00000001
+#define PTRACE_O_TRACEFORK     0x00000002
+#define PTRACE_O_TRACEVFORK    0x00000004
+#define PTRACE_O_TRACECLONE    0x00000008
+#define PTRACE_O_TRACEEXEC     0x00000010
+#define PTRACE_O_TRACEVFORKDONE        0x00000020
+#define PTRACE_O_TRACEEXIT     0x00000040
+
+#define PTRACE_O_MASK          0x0000007f
+
+/* Wait extended result codes for the above trace options.  */
+#define PTRACE_EVENT_FORK      1
+#define PTRACE_EVENT_VFORK     2
+#define PTRACE_EVENT_CLONE     3
+#define PTRACE_EVENT_EXEC      4
+#define PTRACE_EVENT_VFORK_DONE        5
+#define PTRACE_EVENT_EXIT      6
+
+#include <arch/ptrace.h>
+
+#ifdef __KERNEL__
+/*
+ * Ptrace flags
+ */
+
+#define PT_PTRACED     0x00000001
+#define PT_DTRACE      0x00000002      /* delayed trace (used on m68k, i386) */
+#define PT_TRACESYSGOOD        0x00000004
+#define PT_PTRACE_CAP  0x00000008      /* ptracer can follow suid-exec */
+#define PT_TRACE_FORK  0x00000010
+#define PT_TRACE_VFORK 0x00000020
+#define PT_TRACE_CLONE 0x00000040
+#define PT_TRACE_EXEC  0x00000080
+#define PT_TRACE_VFORK_DONE    0x00000100
+#define PT_TRACE_EXIT  0x00000200
+#define PT_ATTACHED    0x00000400      /* parent != real_parent */
+
+#define PT_TRACE_MASK  0x000003f4
+
+/* single stepping state bits (used on ARM and PA-RISC) */
+#define PT_SINGLESTEP_BIT      31
+#define PT_SINGLESTEP          (1<<PT_SINGLESTEP_BIT)
+#define PT_BLOCKSTEP_BIT       30
+#define PT_BLOCKSTEP           (1<<PT_BLOCKSTEP_BIT)
+
+#include <lwk/compiler.h>      /* For unlikely.  */
+#include <lwk/task.h>
+
+
+extern long arch_ptrace(struct task_struct *child, long request, long addr, long data);
+extern struct task_struct *ptrace_get_task(pid_t pid);
+extern int ptrace_traceme(void);
+extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
+extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
+extern int ptrace_attach(struct task_struct *tsk);
+extern int ptrace_detach(struct task_struct *, unsigned int);
+extern void __ptrace_detach(struct task_struct *, unsigned int);
+extern void ptrace_disable(struct task_struct *);
+extern int ptrace_check_attach(struct task_struct *task, int kill);
+extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
+extern void ptrace_notify(int exit_code);
+extern void __ptrace_link(struct task_struct *child,
+                         struct task_struct *new_parent);
+extern void __ptrace_unlink(struct task_struct *child);
+extern void ptrace_untrace(struct task_struct *child);
+extern int ptrace_may_attach(struct task_struct *task);
+
+static inline void ptrace_link(struct task_struct *child,
+                              struct task_struct *new_parent)
+{
+       if (unlikely(child->ptrace))
+               __ptrace_link(child, new_parent);
+}
+static inline void ptrace_unlink(struct task_struct *child)
+{
+       if (unlikely(child->ptrace))
+               __ptrace_unlink(child);
+}
+
+
+#ifndef force_successful_syscall_return
+/*
+ * System call handlers that, upon successful completion, need to return a
+ * negative value should call force_successful_syscall_return() right before
+ * returning.  On architectures where the syscall convention provides for a
+ * separate error flag (e.g., alpha, ia64, ppc{,64}, sparc{,64}, possibly
+ * others), this macro can be used to ensure that the error flag will not get
+ * set.  On architectures which do not support a separate error flag, the macro
+ * is a no-op and the spurious error condition needs to be filtered out by some
+ * other means (e.g., in user-level, by passing an extra argument to the
+ * syscall handler, or something along those lines).
+ */
+#define force_successful_syscall_return() do { } while (0)
+#endif
+
+#endif
+
+#endif
diff --git a/kitten/include/lwk/resource.h b/kitten/include/lwk/resource.h
new file mode 100644 (file)
index 0000000..740e230
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * Derived from Linux include/linux/ioport.h. 
+ * Original comment at head of ioport.h:
+ *
+ * ioport.h    Definitions of routines for detecting, reserving and
+ *             allocating system resources.
+ *
+ * Authors:    Linus Torvalds
+ */
+
+#ifndef _LWK_RESOURCE_H
+#define _LWK_RESOURCE_H
+
+/**
+ * Resources are tree-like, allowing
+ * nesting etc..
+ */
+struct resource {
+       const char *name;
+       unsigned long start, end;
+       unsigned long flags;
+       struct resource *parent, *sibling, *child;
+};
+
+/**
+ * PC/ISA/whatever - the normal PC address spaces: IO and memory
+ */
+extern struct resource ioport_resource;
+extern struct resource iomem_resource;
+
+/**
+ * IO resources have these defined flags.
+ */
+#define IORESOURCE_BITS                0x000000ff      /* Bus-specific bits */
+
+#define IORESOURCE_IO          0x00000100      /* Resource type */
+#define IORESOURCE_MEM         0x00000200
+#define IORESOURCE_IRQ         0x00000400
+#define IORESOURCE_DMA         0x00000800
+
+#define IORESOURCE_PREFETCH    0x00001000      /* No side effects */
+#define IORESOURCE_READONLY    0x00002000
+#define IORESOURCE_CACHEABLE   0x00004000
+#define IORESOURCE_RANGELENGTH 0x00008000
+#define IORESOURCE_SHADOWABLE  0x00010000
+#define IORESOURCE_BUS_HAS_VGA 0x00080000
+
+#define IORESOURCE_DISABLED    0x10000000
+#define IORESOURCE_UNSET       0x20000000
+#define IORESOURCE_AUTO                0x40000000
+#define IORESOURCE_BUSY                0x80000000      /* Driver has marked this resource busy */
+
+/* ISA PnP IRQ specific bits (IORESOURCE_BITS) */
+#define IORESOURCE_IRQ_HIGHEDGE                (1<<0)
+#define IORESOURCE_IRQ_LOWEDGE         (1<<1)
+#define IORESOURCE_IRQ_HIGHLEVEL       (1<<2)
+#define IORESOURCE_IRQ_LOWLEVEL                (1<<3)
+
+/* ISA PnP DMA specific bits (IORESOURCE_BITS) */
+#define IORESOURCE_DMA_TYPE_MASK       (3<<0)
+#define IORESOURCE_DMA_8BIT            (0<<0)
+#define IORESOURCE_DMA_8AND16BIT       (1<<0)
+#define IORESOURCE_DMA_16BIT           (2<<0)
+
+#define IORESOURCE_DMA_MASTER          (1<<2)
+#define IORESOURCE_DMA_BYTE            (1<<3)
+#define IORESOURCE_DMA_WORD            (1<<4)
+
+#define IORESOURCE_DMA_SPEED_MASK      (3<<6)
+#define IORESOURCE_DMA_COMPATIBLE      (0<<6)
+#define IORESOURCE_DMA_TYPEA           (1<<6)
+#define IORESOURCE_DMA_TYPEB           (2<<6)
+#define IORESOURCE_DMA_TYPEF           (3<<6)
+
+/* ISA PnP memory I/O specific bits (IORESOURCE_BITS) */
+#define IORESOURCE_MEM_WRITEABLE       (1<<0)  /* dup: IORESOURCE_READONLY */
+#define IORESOURCE_MEM_CACHEABLE       (1<<1)  /* dup: IORESOURCE_CACHEABLE */
+#define IORESOURCE_MEM_RANGELENGTH     (1<<2)  /* dup: IORESOURCE_RANGELENGTH */
+#define IORESOURCE_MEM_TYPE_MASK       (3<<3)
+#define IORESOURCE_MEM_8BIT            (0<<3)
+#define IORESOURCE_MEM_16BIT           (1<<3)
+#define IORESOURCE_MEM_8AND16BIT       (2<<3)
+#define IORESOURCE_MEM_32BIT           (3<<3)
+#define IORESOURCE_MEM_SHADOWABLE      (1<<5)  /* dup: IORESOURCE_SHADOWABLE */
+#define IORESOURCE_MEM_EXPANSIONROM    (1<<6)
+
+/* PCI ROM control bits (IORESOURCE_BITS) */
+#define IORESOURCE_ROM_ENABLE          (1<<0)  /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
+#define IORESOURCE_ROM_SHADOW          (1<<1)  /* ROM is copy at C000:0 */
+#define IORESOURCE_ROM_COPY            (1<<2)  /* ROM is alloc'd copy, resource field overlaid */
+
+extern int request_resource(struct resource *root, struct resource *new);
+extern struct resource * ____request_resource(struct resource *root, struct resource *new);
+extern int release_resource(struct resource *new);
+extern int insert_resource(struct resource *parent, struct resource *new);
+extern int allocate_resource(struct resource *root, struct resource *new,
+                            unsigned long size,
+                            unsigned long min, unsigned long max,
+                            unsigned long align,
+                            void (*alignf)(void *, struct resource *,
+                                           unsigned long, unsigned long),
+                            void *alignf_data);
+extern int adjust_resource(struct resource *res, unsigned long start,
+                          unsigned long size);
+
+#endif
diff --git a/kitten/include/lwk/sched.h b/kitten/include/lwk/sched.h
new file mode 100644 (file)
index 0000000..9a05f7c
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _LWK_SCHED_H
+#define _LWK_SCHED_H
+
+#include <lwk/task.h>
+#include <lwk/init.h>
+
+extern int __init sched_subsys_init(void);
+extern void sched_add_task(struct task_struct *task);
+extern void sched_del_task(struct task_struct *task);
+extern int sched_wakeup_task(struct task_struct *task,
+                             taskstate_t valid_states);
+extern void schedule(void); 
+
+extern struct task_struct *arch_context_switch(struct task_struct *prev,
+                                               struct task_struct *next);
+extern void arch_idle_task_loop_body(void);
+
+#endif
diff --git a/kitten/include/lwk/screen_info.h b/kitten/include/lwk/screen_info.h
new file mode 100644 (file)
index 0000000..bb9bdc4
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _SCREEN_INFO_H
+#define _SCREEN_INFO_H
+
+#include <lwk/types.h>
+
+/*
+ * These are set up by the setup-routine at boot-time:
+ */
+
+struct screen_info {
+       u8  orig_x;             /* 0x00 */
+       u8  orig_y;             /* 0x01 */
+       u16 dontuse1;           /* 0x02 -- EXT_MEM_K sits here */
+       u16 orig_video_page;    /* 0x04 */
+       u8  orig_video_mode;    /* 0x06 */
+       u8  orig_video_cols;    /* 0x07 */
+       u16 unused2;            /* 0x08 */
+       u16 orig_video_ega_bx;  /* 0x0a */
+       u16 unused3;            /* 0x0c */
+       u8  orig_video_lines;   /* 0x0e */
+       u8  orig_video_isVGA;   /* 0x0f */
+       u16 orig_video_points;  /* 0x10 */
+
+       /* VESA graphic mode -- linear frame buffer */
+       u16 lfb_width;          /* 0x12 */
+       u16 lfb_height;         /* 0x14 */
+       u16 lfb_depth;          /* 0x16 */
+       u32 lfb_base;           /* 0x18 */
+       u32 lfb_size;           /* 0x1c */
+       u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
+       u16 lfb_linelength;     /* 0x24 */
+       u8  red_size;           /* 0x26 */
+       u8  red_pos;            /* 0x27 */
+       u8  green_size;         /* 0x28 */
+       u8  green_pos;          /* 0x29 */
+       u8  blue_size;          /* 0x2a */
+       u8  blue_pos;           /* 0x2b */
+       u8  rsvd_size;          /* 0x2c */
+       u8  rsvd_pos;           /* 0x2d */
+       u16 vesapm_seg;         /* 0x2e */
+       u16 vesapm_off;         /* 0x30 */
+       u16 pages;              /* 0x32 */
+       u16 vesa_attributes;    /* 0x34 */
+       u32 capabilities;       /* 0x36 */
+                               /* 0x3a -- 0x3f reserved for future expansion */
+};
+
+extern struct screen_info screen_info;
+
+#define ORIG_X                 (screen_info.orig_x)
+#define ORIG_Y                 (screen_info.orig_y)
+#define ORIG_VIDEO_MODE                (screen_info.orig_video_mode)
+#define ORIG_VIDEO_COLS        (screen_info.orig_video_cols)
+#define ORIG_VIDEO_EGA_BX      (screen_info.orig_video_ega_bx)
+#define ORIG_VIDEO_LINES       (screen_info.orig_video_lines)
+#define ORIG_VIDEO_ISVGA       (screen_info.orig_video_isVGA)
+#define ORIG_VIDEO_POINTS       (screen_info.orig_video_points)
+
+#define VIDEO_TYPE_MDA         0x10    /* Monochrome Text Display      */
+#define VIDEO_TYPE_CGA         0x11    /* CGA Display                  */
+#define VIDEO_TYPE_EGAM                0x20    /* EGA/VGA in Monochrome Mode   */
+#define VIDEO_TYPE_EGAC                0x21    /* EGA in Color Mode            */
+#define VIDEO_TYPE_VGAC                0x22    /* VGA+ in Color Mode           */
+#define VIDEO_TYPE_VLFB                0x23    /* VESA VGA in graphic mode     */
+
+#define VIDEO_TYPE_PICA_S3     0x30    /* ACER PICA-61 local S3 video  */
+#define VIDEO_TYPE_MIPS_G364   0x31    /* MIPS Magnum 4000 G364 video  */
+#define VIDEO_TYPE_SGI          0x33    /* Various SGI graphics hardware */
+
+#define VIDEO_TYPE_TGAC                0x40    /* DEC TGA */
+
+#define VIDEO_TYPE_SUN          0x50    /* Sun frame buffer. */
+#define VIDEO_TYPE_SUNPCI       0x51    /* Sun PCI based frame buffer. */
+
+#define VIDEO_TYPE_PMAC                0x60    /* PowerMacintosh frame buffer. */
+
+#endif /* _SCREEN_INFO_H */
diff --git a/kitten/include/lwk/seqlock.h b/kitten/include/lwk/seqlock.h
new file mode 100644 (file)
index 0000000..11ba4ce
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef _LWK_SEQLOCK_H
+#define _LWK_SEQLOCK_H
+/*
+ * Reader/writer consistent mechanism without starving writers. This type of
+ * lock for data where the reader wants a consitent set of information
+ * and is willing to retry if the information changes.  Readers never
+ * block but they may have to retry if a writer is in
+ * progress. Writers do not wait for readers. 
+ *
+ * This is not as cache friendly as brlock. Also, this will not work
+ * for data that contains pointers, because any writer could
+ * invalidate a pointer that a reader was following.
+ *
+ * Expected reader usage:
+ *     do {
+ *         seq = read_seqbegin(&foo);
+ *     ...
+ *      } while (read_seqretry(&foo, seq));
+ *
+ *
+ * On non-SMP the spin locks disappear but the writer still needs
+ * to increment the sequence variables because an interrupt routine could
+ * change the state of the data.
+ *
+ * Based on x86_64 vsyscall gettimeofday 
+ * by Keith Owens and Andrea Arcangeli
+ */
+
+#include <lwk/spinlock.h>
+
+typedef struct {
+       unsigned sequence;
+       spinlock_t lock;
+} seqlock_t;
+
+/*
+ * These macros triggered gcc-3.x compile-time problems.  We think these are
+ * OK now.  Be cautious.
+ */
+#define SEQLOCK_UNLOCKED { 0, SPIN_LOCK_UNLOCKED }
+#define seqlock_init(x)        do { *(x) = (seqlock_t) SEQLOCK_UNLOCKED; } while (0)
+
+
+/* Lock out other writers and update the count.
+ * Acts like a normal spin_lock/unlock.
+ */
+static inline void write_seqlock(seqlock_t *sl)
+{
+       spin_lock(&sl->lock);
+       ++sl->sequence;
+       smp_wmb();                      
+}      
+
+static inline void write_sequnlock(seqlock_t *sl) 
+{
+       smp_wmb();
+       sl->sequence++;
+       spin_unlock(&sl->lock);
+}
+
+static inline int write_tryseqlock(seqlock_t *sl)
+{
+       int ret = spin_trylock(&sl->lock);
+
+       if (ret) {
+               ++sl->sequence;
+               smp_wmb();                      
+       }
+       return ret;
+}
+
+/* Start of read calculation -- fetch last complete writer token */
+static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
+{
+       unsigned ret = sl->sequence;
+       smp_rmb();
+       return ret;
+}
+
+/* Test if reader processed invalid data.
+ * If initial values is odd, 
+ *     then writer had already started when section was entered
+ * If sequence value changed
+ *     then writer changed data while in section
+ *    
+ * Using xor saves one conditional branch.
+ */
+static __always_inline int read_seqretry(const seqlock_t *sl, unsigned iv)
+{
+       smp_rmb();
+       return (iv & 1) | (sl->sequence ^ iv);
+}
+
+
+/*
+ * Version using sequence counter only.
+ * This can be used when code has its own mutex protecting the
+ * updating starting before the write_seqcountbeqin() and ending
+ * after the write_seqcount_end().
+ */
+
+typedef struct seqcount {
+       unsigned sequence;
+} seqcount_t;
+
+#define SEQCNT_ZERO { 0 }
+#define seqcount_init(x)       do { *(x) = (seqcount_t) SEQCNT_ZERO; } while (0)
+
+/* Start of read using pointer to a sequence counter only.  */
+static inline unsigned read_seqcount_begin(const seqcount_t *s)
+{
+       unsigned ret = s->sequence;
+       smp_rmb();
+       return ret;
+}
+
+/* Test if reader processed invalid data.
+ * Equivalent to: iv is odd or sequence number has changed.
+ *                (iv & 1) || (*s != iv)
+ * Using xor saves one conditional branch.
+ */
+static inline int read_seqcount_retry(const seqcount_t *s, unsigned iv)
+{
+       smp_rmb();
+       return (iv & 1) | (s->sequence ^ iv);
+}
+
+
+/*
+ * Sequence counter only version assumes that callers are using their
+ * own mutexing.
+ */
+static inline void write_seqcount_begin(seqcount_t *s)
+{
+       s->sequence++;
+       smp_wmb();
+}
+
+static inline void write_seqcount_end(seqcount_t *s)
+{
+       smp_wmb();
+       s->sequence++;
+}
+
+/*
+ * Possible sw/hw IRQ protected versions of the interfaces.
+ */
+#define write_seqlock_irqsave(lock, flags)                             \
+       do { local_irq_save(flags); write_seqlock(lock); } while (0)
+#define write_seqlock_irq(lock)                                                \
+       do { local_irq_disable();   write_seqlock(lock); } while (0)
+#define write_seqlock_bh(lock)                                         \
+        do { local_bh_disable();    write_seqlock(lock); } while (0)
+
+#define write_sequnlock_irqrestore(lock, flags)                                \
+       do { write_sequnlock(lock); local_irq_restore(flags); } while(0)
+#define write_sequnlock_irq(lock)                                      \
+       do { write_sequnlock(lock); local_irq_enable(); } while(0)
+#define write_sequnlock_bh(lock)                                       \
+       do { write_sequnlock(lock); local_bh_enable(); } while(0)
+
+#define read_seqbegin_irqsave(lock, flags)                             \
+       ({ local_irq_save(flags);   read_seqbegin(lock); })
+
+#define read_seqretry_irqrestore(lock, iv, flags)                      \
+       ({                                                              \
+               int ret = read_seqretry(lock, iv);                      \
+               local_irq_restore(flags);                               \
+               ret;                                                    \
+       })
+
+#endif /* _LWK_SEQLOCK_H */
diff --git a/kitten/include/lwk/show.h b/kitten/include/lwk/show.h
new file mode 100644 (file)
index 0000000..6ff1d43
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _LWK_SHOW_H
+#define _LWK_SHOW_H
+
+#include <arch/show.h>
+
+extern void show_memory(unsigned long vaddr, size_t n);
+
+#endif
diff --git a/kitten/include/lwk/signal.h b/kitten/include/lwk/signal.h
new file mode 100644 (file)
index 0000000..642d400
--- /dev/null
@@ -0,0 +1,374 @@
+#ifndef _LWK_SIGNAL_H
+#define _LWK_SIGNAL_H
+
+#include <arch/signal.h>
+#include <arch/siginfo.h>
+
+#ifdef __KERNEL__
+#include <lwk/list.h>
+#include <lwk/spinlock.h>
+
+/*
+ * Real Time signals may be queued.
+ */
+
+struct sigqueue {
+       struct list_head list;
+       int flags;
+       siginfo_t info;
+       struct user_struct *user;
+};
+
+/* flags values. */
+#define SIGQUEUE_PREALLOC      1
+
+struct sigpending {
+       struct list_head list;
+       sigset_t signal;
+};
+
+/*
+ * Define some primitives to manipulate sigset_t.
+ */
+
+#ifndef __HAVE_ARCH_SIG_BITOPS
+#include <lwk/bitops.h>
+
+/* We don't use <lwk/bitops.h> for these because there is no need to
+   be atomic.  */
+static inline void sigaddset(sigset_t *set, int _sig)
+{
+       unsigned long sig = _sig - 1;
+       if (_NSIG_WORDS == 1)
+               set->sig[0] |= 1UL << sig;
+       else
+               set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW);
+}
+
+static inline void sigdelset(sigset_t *set, int _sig)
+{
+       unsigned long sig = _sig - 1;
+       if (_NSIG_WORDS == 1)
+               set->sig[0] &= ~(1UL << sig);
+       else
+               set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW));
+}
+
+static inline int sigismember(sigset_t *set, int _sig)
+{
+       unsigned long sig = _sig - 1;
+       if (_NSIG_WORDS == 1)
+               return 1 & (set->sig[0] >> sig);
+       else
+               return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
+}
+
+static inline int sigfindinword(unsigned long word)
+{
+       return ffz(~word);
+}
+
+#endif /* __HAVE_ARCH_SIG_BITOPS */
+
+static inline int sigisemptyset(sigset_t *set)
+{
+       extern void _NSIG_WORDS_is_unsupported_size(void);
+       switch (_NSIG_WORDS) {
+       case 4:
+               return (set->sig[3] | set->sig[2] |
+                       set->sig[1] | set->sig[0]) == 0;
+       case 2:
+               return (set->sig[1] | set->sig[0]) == 0;
+       case 1:
+               return set->sig[0] == 0;
+       default:
+               _NSIG_WORDS_is_unsupported_size();
+               return 0;
+       }
+}
+
+#define sigmask(sig)   (1UL << ((sig) - 1))
+
+#ifndef __HAVE_ARCH_SIG_SETOPS
+#include <lwk/string.h>
+
+#define _SIG_SET_BINOP(name, op)                                       \
+static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \
+{                                                                      \
+       extern void _NSIG_WORDS_is_unsupported_size(void);              \
+       unsigned long a0, a1, a2, a3, b0, b1, b2, b3;                   \
+                                                                       \
+       switch (_NSIG_WORDS) {                                          \
+           case 4:                                                     \
+               a3 = a->sig[3]; a2 = a->sig[2];                         \
+               b3 = b->sig[3]; b2 = b->sig[2];                         \
+               r->sig[3] = op(a3, b3);                                 \
+               r->sig[2] = op(a2, b2);                                 \
+           case 2:                                                     \
+               a1 = a->sig[1]; b1 = b->sig[1];                         \
+               r->sig[1] = op(a1, b1);                                 \
+           case 1:                                                     \
+               a0 = a->sig[0]; b0 = b->sig[0];                         \
+               r->sig[0] = op(a0, b0);                                 \
+               break;                                                  \
+           default:                                                    \
+               _NSIG_WORDS_is_unsupported_size();                      \
+       }                                                               \
+}
+
+#define _sig_or(x,y)   ((x) | (y))
+_SIG_SET_BINOP(sigorsets, _sig_or)
+
+#define _sig_and(x,y)  ((x) & (y))
+_SIG_SET_BINOP(sigandsets, _sig_and)
+
+#define _sig_nand(x,y) ((x) & ~(y))
+_SIG_SET_BINOP(signandsets, _sig_nand)
+
+#undef _SIG_SET_BINOP
+#undef _sig_or
+#undef _sig_and
+#undef _sig_nand
+
+#define _SIG_SET_OP(name, op)                                          \
+static inline void name(sigset_t *set)                                 \
+{                                                                      \
+       extern void _NSIG_WORDS_is_unsupported_size(void);              \
+                                                                       \
+       switch (_NSIG_WORDS) {                                          \
+           case 4: set->sig[3] = op(set->sig[3]);                      \
+                   set->sig[2] = op(set->sig[2]);                      \
+           case 2: set->sig[1] = op(set->sig[1]);                      \
+           case 1: set->sig[0] = op(set->sig[0]);                      \
+                   break;                                              \
+           default:                                                    \
+               _NSIG_WORDS_is_unsupported_size();                      \
+       }                                                               \
+}
+
+#define _sig_not(x)    (~(x))
+_SIG_SET_OP(signotset, _sig_not)
+
+#undef _SIG_SET_OP
+#undef _sig_not
+
+static inline void sigemptyset(sigset_t *set)
+{
+       switch (_NSIG_WORDS) {
+       default:
+               memset(set, 0, sizeof(sigset_t));
+               break;
+       case 2: set->sig[1] = 0;
+       case 1: set->sig[0] = 0;
+               break;
+       }
+}
+
+static inline void sigfillset(sigset_t *set)
+{
+       switch (_NSIG_WORDS) {
+       default:
+               memset(set, -1, sizeof(sigset_t));
+               break;
+       case 2: set->sig[1] = -1;
+       case 1: set->sig[0] = -1;
+               break;
+       }
+}
+
+/* Some extensions for manipulating the low 32 signals in particular.  */
+
+static inline void sigaddsetmask(sigset_t *set, unsigned long mask)
+{
+       set->sig[0] |= mask;
+}
+
+static inline void sigdelsetmask(sigset_t *set, unsigned long mask)
+{
+       set->sig[0] &= ~mask;
+}
+
+static inline int sigtestsetmask(sigset_t *set, unsigned long mask)
+{
+       return (set->sig[0] & mask) != 0;
+}
+
+static inline void siginitset(sigset_t *set, unsigned long mask)
+{
+       set->sig[0] = mask;
+       switch (_NSIG_WORDS) {
+       default:
+               memset(&set->sig[1], 0, sizeof(long)*(_NSIG_WORDS-1));
+               break;
+       case 2: set->sig[1] = 0;
+       case 1: ;
+       }
+}
+
+static inline void siginitsetinv(sigset_t *set, unsigned long mask)
+{
+       set->sig[0] = ~mask;
+       switch (_NSIG_WORDS) {
+       default:
+               memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1));
+               break;
+       case 2: set->sig[1] = -1;
+       case 1: ;
+       }
+}
+
+#endif /* __HAVE_ARCH_SIG_SETOPS */
+
+static inline void init_sigpending(struct sigpending *sig)
+{
+       sigemptyset(&sig->signal);
+       INIT_LIST_HEAD(&sig->list);
+}
+
+extern void flush_sigqueue(struct sigpending *queue);
+
+/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
+static inline int valid_signal(unsigned long sig)
+{
+       return sig <= _NSIG ? 1 : 0;
+}
+
+extern int next_signal(struct sigpending *pending, sigset_t *mask);
+extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
+extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
+extern long do_sigpending(void __user *, unsigned long);
+extern int sigprocmask(int, sigset_t *, sigset_t *);
+
+struct pt_regs;
+extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
+
+extern struct kmem_cache *sighand_cachep;
+
+/*
+ * In POSIX a signal is sent either to a specific thread (LWK task)
+ * or to the process as a whole (LWK thread group).  How the signal
+ * is sent determines whether it's to one thread or the whole group,
+ * which determines which signal mask(s) are involved in blocking it
+ * from being delivered until later.  When the signal is delivered,
+ * either it's caught or ignored by a user handler or it has a default
+ * effect that applies to the whole thread group (POSIX process).
+ *
+ * The possible effects an unblocked signal set to SIG_DFL can have are:
+ *   ignore    - Nothing Happens
+ *   terminate - kill the process, i.e. all threads in the group,
+ *               similar to exit_group.  The group leader (only) reports
+ *               WIFSIGNALED status to its parent.
+ *   coredump  - write a core dump file describing all threads using
+ *               the same mm and then kill all those threads
+ *   stop      - stop all the threads in the group, i.e. TASK_STOPPED state
+ *
+ * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
+ * Other signals when not blocked and set to SIG_DFL behaves as follows.
+ * The job control signals also have other special effects.
+ *
+ *     +--------------------+------------------+
+ *     |  POSIX signal      |  default action  |
+ *     +--------------------+------------------+
+ *     |  SIGHUP            |  terminate       |
+ *     |  SIGINT            |  terminate       |
+ *     |  SIGQUIT           |  coredump        |
+ *     |  SIGILL            |  coredump        |
+ *     |  SIGTRAP           |  coredump        |
+ *     |  SIGABRT/SIGIOT    |  coredump        |
+ *     |  SIGBUS            |  coredump        |
+ *     |  SIGFPE            |  coredump        |
+ *     |  SIGKILL           |  terminate(+)    |
+ *     |  SIGUSR1           |  terminate       |
+ *     |  SIGSEGV           |  coredump        |
+ *     |  SIGUSR2           |  terminate       |
+ *     |  SIGPIPE           |  terminate       |
+ *     |  SIGALRM           |  terminate       |
+ *     |  SIGTERM           |  terminate       |
+ *     |  SIGCHLD           |  ignore          |
+ *     |  SIGCONT           |  ignore(*)       |
+ *     |  SIGSTOP           |  stop(*)(+)      |
+ *     |  SIGTSTP           |  stop(*)         |
+ *     |  SIGTTIN           |  stop(*)         |
+ *     |  SIGTTOU           |  stop(*)         |
+ *     |  SIGURG            |  ignore          |
+ *     |  SIGXCPU           |  coredump        |
+ *     |  SIGXFSZ           |  coredump        |
+ *     |  SIGVTALRM         |  terminate       |
+ *     |  SIGPROF           |  terminate       |
+ *     |  SIGPOLL/SIGIO     |  terminate       |
+ *     |  SIGSYS/SIGUNUSED  |  coredump        |
+ *     |  SIGSTKFLT         |  terminate       |
+ *     |  SIGWINCH          |  ignore          |
+ *     |  SIGPWR            |  terminate       |
+ *     |  SIGRTMIN-SIGRTMAX |  terminate       |
+ *     +--------------------+------------------+
+ *     |  non-POSIX signal  |  default action  |
+ *     +--------------------+------------------+
+ *     |  SIGEMT            |  coredump        |
+ *     +--------------------+------------------+
+ *
+ * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
+ * (*) Special job control effects:
+ * When SIGCONT is sent, it resumes the process (all threads in the group)
+ * from TASK_STOPPED state and also clears any pending/queued stop signals
+ * (any of those marked with "stop(*)").  This happens regardless of blocking,
+ * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
+ * any pending/queued SIGCONT signals; this happens regardless of blocking,
+ * catching, or ignored the stop signal, though (except for SIGSTOP) the
+ * default action of stopping the process may happen later or never.
+ */
+
+#ifdef SIGEMT
+#define SIGEMT_MASK    rt_sigmask(SIGEMT)
+#else
+#define SIGEMT_MASK    0
+#endif
+
+#if SIGRTMIN > BITS_PER_LONG
+#define rt_sigmask(sig)        (1ULL << ((sig)-1))
+#else
+#define rt_sigmask(sig)        sigmask(sig)
+#endif
+#define siginmask(sig, mask) (rt_sigmask(sig) & (mask))
+
+#define SIG_KERNEL_ONLY_MASK (\
+       rt_sigmask(SIGKILL)   |  rt_sigmask(SIGSTOP))
+
+#define SIG_KERNEL_STOP_MASK (\
+       rt_sigmask(SIGSTOP)   |  rt_sigmask(SIGTSTP)   | \
+       rt_sigmask(SIGTTIN)   |  rt_sigmask(SIGTTOU)   )
+
+#define SIG_KERNEL_COREDUMP_MASK (\
+        rt_sigmask(SIGQUIT)   |  rt_sigmask(SIGILL)    | \
+       rt_sigmask(SIGTRAP)   |  rt_sigmask(SIGABRT)   | \
+        rt_sigmask(SIGFPE)    |  rt_sigmask(SIGSEGV)   | \
+       rt_sigmask(SIGBUS)    |  rt_sigmask(SIGSYS)    | \
+        rt_sigmask(SIGXCPU)   |  rt_sigmask(SIGXFSZ)   | \
+       SIGEMT_MASK                                    )
+
+#define SIG_KERNEL_IGNORE_MASK (\
+        rt_sigmask(SIGCONT)   |  rt_sigmask(SIGCHLD)   | \
+       rt_sigmask(SIGWINCH)  |  rt_sigmask(SIGURG)    )
+
+#define sig_kernel_only(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_COREDUMP_MASK))
+#define sig_kernel_ignore(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_IGNORE_MASK))
+#define sig_kernel_stop(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_STOP_MASK))
+
+#define sig_needs_tasklist(sig)        ((sig) == SIGCONT)
+
+#define sig_user_defined(t, signr) \
+       (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&  \
+        ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
+
+#define sig_fatal(t, signr) \
+       (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
+        (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
+
+#endif /* __KERNEL__ */
+
+#endif /* _LWK_SIGNAL_H */
diff --git a/kitten/include/lwk/smp.h b/kitten/include/lwk/smp.h
new file mode 100644 (file)
index 0000000..8846424
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __LINUX_SMP_H
+#define __LINUX_SMP_H
+
+/*
+ *     Generic SMP support
+ *             Alan Cox. <alan@redhat.com>
+ */
+
+#include <lwk/kernel.h>
+#include <lwk/compiler.h>
+#include <arch/smp.h>
+
+/*
+ * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc.
+ * (defined in asm header):
+ */ 
+
+/*
+ * stops all CPUs but the current one:
+ */
+extern void smp_send_stop(void);
+
+/*
+ * sends a 'reschedule' event to another CPU:
+ */
+extern void smp_send_reschedule(int cpu);
+
+
+/*
+ * Prepare machine for booting other CPUs.
+ */
+extern void smp_prepare_cpus(unsigned int max_cpus);
+
+/*
+ * Bring a CPU up
+ */
+extern int __cpu_up(unsigned int cpunum);
+
+/*
+ * Final polishing of CPUs
+ */
+extern void smp_cpus_done(unsigned int max_cpus);
+
+/*
+ * Call a function on all other processors
+ */
+int smp_call_function(void(*func)(void *info), void *info, int retry, int wait);
+
+/*
+ * Call a function on all processors
+ */
+int on_each_cpu(void (*func) (void *info), void *info, int retry, int wait);
+
+#define MSG_ALL_BUT_SELF       0x8000  /* Assume <32768 CPU's */
+#define MSG_ALL                        0x8001
+
+#define MSG_INVALIDATE_TLB     0x0001  /* Remote processor TLB invalidate */
+#define MSG_STOP_CPU           0x0002  /* Sent to shut down slave CPU's
+                                        * when rebooting
+                                        */
+#define MSG_RESCHEDULE         0x0003  /* Reschedule request from master CPU*/
+#define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
+
+/*
+ * Mark the boot cpu "online" so that it can call console drivers in
+ * printk() and can access its per-cpu storage.
+ */
+void smp_prepare_boot_cpu(void);
+
+#define smp_processor_id() raw_smp_processor_id()
+#define get_cpu()              smp_processor_id()
+#define put_cpu()              do { } while (0)
+#define put_cpu_no_resched()   do { } while (0)
+
+/**
+ * Returns the current CPU's logical ID.
+ */
+#define this_cpu smp_processor_id()
+
+void __init arch_boot_cpu(unsigned int cpu);
+void __init cpu_init(void);
+
+#endif /* _LWK_SMP_H */
diff --git a/kitten/include/lwk/sort.h b/kitten/include/lwk/sort.h
new file mode 100644 (file)
index 0000000..367d494
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _LWK_SORT_H
+#define _LWK_SORT_H
+
+#include <lwk/types.h>
+
+void sort(void *base, size_t num, size_t size,
+         int (*cmp)(const void *, const void *),
+         void (*swap)(void *, void *, int));
+
+#endif
diff --git a/kitten/include/lwk/spinlock.h b/kitten/include/lwk/spinlock.h
new file mode 100644 (file)
index 0000000..9d84465
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef _LWK_SPINLOCK_H
+#define _LWK_SPINLOCK_H
+
+/*
+ * include/lwk/spinlock.h - generic spinlock/rwlock declarations
+ *
+ * here's the role of the various spinlock/rwlock related include files:
+ *
+ *  arch/spinlock_types.h: contains the raw_spinlock_t/raw_rwlock_t and the
+ *                         initializers
+ *
+ *  lwk/spinlock_types.h:
+ *                         defines the generic type and initializers
+ *
+ *  arch/spinlock.h:       contains the __raw_spin_*()/etc. lowlevel
+ *                         implementations, mostly inline assembly code
+ *
+ *  lwk/spinlock_api_smp.h:
+ *                         contains the prototypes for the _spin_*() APIs.
+ *
+ *  lwk/spinlock.h:        builds the final spin_*() APIs.
+ *
+ *  lwk/spinlock.h:        builds the final spin_*() APIs.
+ */
+
+#include <lwk/kernel.h>
+#include <lwk/linkage.h>
+#include <lwk/compiler.h>
+#include <lwk/stringify.h>
+#include <arch/system.h>
+
+/*
+ * Must define these before including other files, inline functions need them
+ */
+#define LOCK_SECTION_NAME ".text.lock."KBUILD_BASENAME
+
+#define LOCK_SECTION_START(extra)               \
+        ".subsection 1\n\t"                     \
+        extra                                   \
+        ".ifndef " LOCK_SECTION_NAME "\n\t"     \
+        LOCK_SECTION_NAME ":\n\t"               \
+        ".endif\n"
+
+#define LOCK_SECTION_END                        \
+        ".previous\n\t"
+
+#define __lockfunc fastcall __attribute__((section(".spinlock.text")))
+
+/*
+ * Pull the raw_spinlock_t and raw_rwlock_t definitions:
+ */
+#include <lwk/spinlock_types.h>
+
+extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock);
+
+/*
+ * Pull the __raw*() functions/declarations:
+ */
+# include <arch/spinlock.h>
+
+#define spin_lock_init(lock)   do { *(lock) = (spinlock_t)SPIN_LOCK_UNLOCKED; } while (0)
+#define rwlock_init(lock)      do { *(lock) = (rwlock_t)RW_LOCK_UNLOCKED; } while (0)
+
+#define spin_is_locked(lock)   __raw_spin_is_locked(&(lock)->raw_lock)
+
+/**
+ * spin_unlock_wait - wait until the spinlock gets unlocked
+ * @lock: the spinlock in question.
+ */
+#define spin_unlock_wait(lock) __raw_spin_unlock_wait(&(lock)->raw_lock)
+
+/*
+ * Pull the _spin_*()/_read_*()/_write_*() functions/declarations:
+ */
+#include <lwk/spinlock_api_smp.h>
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+ extern void _raw_spin_lock(spinlock_t *lock);
+#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
+ extern int _raw_spin_trylock(spinlock_t *lock);
+ extern void _raw_spin_unlock(spinlock_t *lock);
+
+ extern void _raw_read_lock(rwlock_t *lock);
+ extern int _raw_read_trylock(rwlock_t *lock);
+ extern void _raw_read_unlock(rwlock_t *lock);
+ extern void _raw_write_lock(rwlock_t *lock);
+ extern int _raw_write_trylock(rwlock_t *lock);
+ extern void _raw_write_unlock(rwlock_t *lock);
+#else
+# define _raw_spin_unlock(lock)                __raw_spin_unlock(&(lock)->raw_lock)
+# define _raw_spin_trylock(lock)       __raw_spin_trylock(&(lock)->raw_lock)
+# define _raw_spin_lock(lock)          __raw_spin_lock(&(lock)->raw_lock)
+# define _raw_spin_lock_flags(lock, flags) \
+               __raw_spin_lock_flags(&(lock)->raw_lock, *(flags))
+# define _raw_read_lock(rwlock)                __raw_read_lock(&(rwlock)->raw_lock)
+# define _raw_write_lock(rwlock)       __raw_write_lock(&(rwlock)->raw_lock)
+# define _raw_read_unlock(rwlock)      __raw_read_unlock(&(rwlock)->raw_lock)
+# define _raw_write_unlock(rwlock)     __raw_write_unlock(&(rwlock)->raw_lock)
+# define _raw_read_trylock(rwlock)     __raw_read_trylock(&(rwlock)->raw_lock)
+# define _raw_write_trylock(rwlock)    __raw_write_trylock(&(rwlock)->raw_lock)
+#endif
+
+#define read_can_lock(rwlock)          __raw_read_can_lock(&(rwlock)->raw_lock)
+#define write_can_lock(rwlock)         __raw_write_can_lock(&(rwlock)->raw_lock)
+
+/*
+ * Define the various spin_lock and rw_lock methods.  
+ */
+#define spin_trylock(lock)             __cond_lock(_spin_trylock(lock))
+#define read_trylock(lock)             __cond_lock(_read_trylock(lock))
+#define write_trylock(lock)            __cond_lock(_write_trylock(lock))
+
+#define spin_lock(lock)                        _spin_lock(lock)
+#define write_lock(lock)               _write_lock(lock)
+#define read_lock(lock)                        _read_lock(lock)
+
+#define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock)
+#define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock)
+#define write_lock_irqsave(lock, flags)        flags = _write_lock_irqsave(lock)
+
+#define spin_lock_irq(lock)            _spin_lock_irq(lock)
+#define spin_lock_bh(lock)             _spin_lock_bh(lock)
+
+#define read_lock_irq(lock)            _read_lock_irq(lock)
+#define read_lock_bh(lock)             _read_lock_bh(lock)
+
+#define write_lock_irq(lock)           _write_lock_irq(lock)
+#define write_lock_bh(lock)            _write_lock_bh(lock)
+
+/*
+ * We inline the unlock functions in the nondebug case:
+ */
+#if defined(CONFIG_DEBUG_SPINLOCK)
+# define spin_unlock(lock)             _spin_unlock(lock)
+# define read_unlock(lock)             _read_unlock(lock)
+# define write_unlock(lock)            _write_unlock(lock)
+#else
+# define spin_unlock(lock)             __raw_spin_unlock(&(lock)->raw_lock)
+# define read_unlock(lock)             __raw_read_unlock(&(lock)->raw_lock)
+# define write_unlock(lock)            __raw_write_unlock(&(lock)->raw_lock)
+#endif
+
+#if defined(CONFIG_DEBUG_SPINLOCK)
+# define spin_unlock_irq(lock)         _spin_unlock_irq(lock)
+# define read_unlock_irq(lock)         _read_unlock_irq(lock)
+# define write_unlock_irq(lock)                _write_unlock_irq(lock)
+#else
+# define spin_unlock_irq(lock) \
+    do { __raw_spin_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
+# define read_unlock_irq(lock) \
+    do { __raw_read_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
+# define write_unlock_irq(lock) \
+    do { __raw_write_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
+#endif
+
+#define spin_unlock_irqrestore(lock, flags) \
+                                       _spin_unlock_irqrestore(lock, flags)
+#define spin_unlock_bh(lock)           _spin_unlock_bh(lock)
+
+#define read_unlock_irqrestore(lock, flags) \
+                                       _read_unlock_irqrestore(lock, flags)
+#define read_unlock_bh(lock)           _read_unlock_bh(lock)
+
+#define write_unlock_irqrestore(lock, flags) \
+                                       _write_unlock_irqrestore(lock, flags)
+#define write_unlock_bh(lock)          _write_unlock_bh(lock)
+
+#define spin_trylock_bh(lock)          __cond_lock(_spin_trylock_bh(lock))
+
+#define spin_trylock_irq(lock) \
+({ \
+       local_irq_disable(); \
+       _spin_trylock(lock) ? \
+       1 : ({ local_irq_enable(); 0;  }); \
+})
+
+#define spin_trylock_irqsave(lock, flags) \
+({ \
+       local_irq_save(flags); \
+       _spin_trylock(lock) ? \
+       1 : ({ local_irq_restore(flags); 0; }); \
+})
+
+/*
+ * Pull the atomic_t declaration:
+ * (asm-mips/atomic.h needs above definitions)
+ */
+#include <arch/atomic.h>
+/**
+ * atomic_dec_and_lock - lock on reaching reference count zero
+ * @atomic: the atomic counter
+ * @lock: the spinlock in question
+ */
+extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
+#define atomic_dec_and_lock(atomic, lock) \
+               __cond_lock(_atomic_dec_and_lock(atomic, lock))
+
+/**
+ * spin_can_lock - would spin_trylock() succeed?
+ * @lock: the spinlock in question.
+ */
+#define spin_can_lock(lock)    (!spin_is_locked(lock))
+
+#endif /* _LWK_SPINLOCK_H */
diff --git a/kitten/include/lwk/spinlock_api_smp.h b/kitten/include/lwk/spinlock_api_smp.h
new file mode 100644 (file)
index 0000000..b63d7b4
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _LWK_SPINLOCK_API_SMP_H
+#define _LWK_SPINLOCK_API_SMP_H
+
+#ifndef _LWK_SPINLOCK_H
+# error "please don't include this file directly"
+#endif
+
+/*
+ * include/lwk/spinlock_api_smp.h
+ *
+ * spinlock API declarations on SMP (and debug)
+ * (implemented in kernel/spinlock.c)
+ *
+ * portions Copyright 2005, Red Hat, Inc., Ingo Molnar
+ * Released under the General Public License (GPL).
+ */
+
+int in_lock_functions(unsigned long addr);
+
+#define assert_spin_locked(x)  BUG_ON(!spin_is_locked(x))
+
+void __lockfunc _spin_lock(spinlock_t *lock)           __acquires(spinlock_t);
+void __lockfunc _read_lock(rwlock_t *lock)             __acquires(rwlock_t);
+void __lockfunc _write_lock(rwlock_t *lock)            __acquires(rwlock_t);
+void __lockfunc _spin_lock_bh(spinlock_t *lock)                __acquires(spinlock_t);
+void __lockfunc _read_lock_bh(rwlock_t *lock)          __acquires(rwlock_t);
+void __lockfunc _write_lock_bh(rwlock_t *lock)         __acquires(rwlock_t);
+void __lockfunc _spin_lock_irq(spinlock_t *lock)       __acquires(spinlock_t);
+void __lockfunc _read_lock_irq(rwlock_t *lock)         __acquires(rwlock_t);
+void __lockfunc _write_lock_irq(rwlock_t *lock)                __acquires(rwlock_t);
+unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
+                                                       __acquires(spinlock_t);
+unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
+                                                       __acquires(rwlock_t);
+unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
+                                                       __acquires(rwlock_t);
+int __lockfunc _spin_trylock(spinlock_t *lock);
+int __lockfunc _read_trylock(rwlock_t *lock);
+int __lockfunc _write_trylock(rwlock_t *lock);
+int __lockfunc _spin_trylock_bh(spinlock_t *lock);
+void __lockfunc _spin_unlock(spinlock_t *lock)         __releases(spinlock_t);
+void __lockfunc _read_unlock(rwlock_t *lock)           __releases(rwlock_t);
+void __lockfunc _write_unlock(rwlock_t *lock)          __releases(rwlock_t);
+void __lockfunc _spin_unlock_bh(spinlock_t *lock)      __releases(spinlock_t);
+void __lockfunc _read_unlock_bh(rwlock_t *lock)                __releases(rwlock_t);
+void __lockfunc _write_unlock_bh(rwlock_t *lock)       __releases(rwlock_t);
+void __lockfunc _spin_unlock_irq(spinlock_t *lock)     __releases(spinlock_t);
+void __lockfunc _read_unlock_irq(rwlock_t *lock)       __releases(rwlock_t);
+void __lockfunc _write_unlock_irq(rwlock_t *lock)      __releases(rwlock_t);
+void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+                                                       __releases(spinlock_t);
+void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+                                                       __releases(rwlock_t);
+void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+                                                       __releases(rwlock_t);
+
+#endif /* _LWK_SPINLOCK_API_SMP_H */
diff --git a/kitten/include/lwk/spinlock_types.h b/kitten/include/lwk/spinlock_types.h
new file mode 100644 (file)
index 0000000..08e82c4
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _LWK_SPINLOCK_TYPES_H
+#define _LWK_SPINLOCK_TYPES_H
+
+/*
+ * include/lwk/spinlock_types.h - generic spinlock type definitions
+ *                                and initializers
+ *
+ * portions Copyright 2005, Red Hat, Inc., Ingo Molnar
+ * Released under the General Public License (GPL).
+ */
+
+#include <arch/spinlock_types.h>
+
+typedef struct {
+       raw_spinlock_t raw_lock;
+#ifdef CONFIG_DEBUG_SPINLOCK
+       unsigned int magic, owner_cpu;
+       void *owner;
+#endif
+} spinlock_t;
+
+#define SPINLOCK_MAGIC         0xdead4ead
+
+typedef struct {
+       raw_rwlock_t raw_lock;
+#ifdef CONFIG_DEBUG_SPINLOCK
+       unsigned int magic, owner_cpu;
+       void *owner;
+#endif
+} rwlock_t;
+
+#define RWLOCK_MAGIC           0xdeaf1eed
+
+#define SPINLOCK_OWNER_INIT    ((void *)-1L)
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+# define SPIN_LOCK_UNLOCKED                                            \
+                       {       .raw_lock = __RAW_SPIN_LOCK_UNLOCKED,   \
+                               .magic = SPINLOCK_MAGIC,                \
+                               .owner = SPINLOCK_OWNER_INIT,           \
+                               .owner_cpu = -1 }
+#define RW_LOCK_UNLOCKED                                               \
+                       {       .raw_lock = __RAW_RW_LOCK_UNLOCKED,     \
+                               .magic = RWLOCK_MAGIC,                  \
+                               .owner = SPINLOCK_OWNER_INIT,           \
+                               .owner_cpu = -1 }
+#else
+# define SPIN_LOCK_UNLOCKED \
+                       {       .raw_lock = __RAW_SPIN_LOCK_UNLOCKED }
+#define RW_LOCK_UNLOCKED \
+                       {       .raw_lock = __RAW_RW_LOCK_UNLOCKED }
+#endif
+
+#define DEFINE_SPINLOCK(x)     spinlock_t x = SPIN_LOCK_UNLOCKED
+#define DEFINE_RWLOCK(x)       rwlock_t x = RW_LOCK_UNLOCKED
+
+#endif /* _LWK_SPINLOCK_TYPES_H */
diff --git a/kitten/include/lwk/stat.h b/kitten/include/lwk/stat.h
new file mode 100644 (file)
index 0000000..5a2dfc3
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _LWK_STAT_H
+#define _LWK_STAT_H
+
+#include <arch/stat.h>
+
+#endif
diff --git a/kitten/include/lwk/stddef.h b/kitten/include/lwk/stddef.h
new file mode 100644 (file)
index 0000000..66551f3
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _LWK_STDDEF_H
+#define _LWK_STDDEF_H
+
+#include <lwk/compiler.h>
+
+#undef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+
+#ifdef __KERNEL__
+#define false 0
+#define true  1
+#endif
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#endif
diff --git a/kitten/include/lwk/string.h b/kitten/include/lwk/string.h
new file mode 100644 (file)
index 0000000..36e6eed
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef _LWK_STRING_H
+#define _LWK_STRING_H
+
+/* We don't want strings.h stuff being used by user stuff by accident */
+
+#ifndef __KERNEL__
+#include <string.h>
+#endif
+
+#ifdef __KERNEL__
+
+#include <lwk/compiler.h>      /* for inline */
+#include <lwk/types.h>         /* for size_t */
+#include <lwk/stddef.h>                /* for NULL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *strndup_user(const char __user *, long);
+
+/*
+ * Include machine specific inline routines
+ */
+#include <arch/string.h>
+
+#ifndef __HAVE_ARCH_STRCPY
+extern char * strcpy(char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCPY
+extern char * strncpy(char *,const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCAT
+extern char * strcat(char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCAT
+extern char * strncat(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRLCAT
+extern size_t strlcat(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCMP
+extern int strcmp(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCMP
+extern int strncmp(const char *,const char *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRNICMP
+extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCHR
+extern char * strchr(const char *,int);
+#endif
+#ifndef __HAVE_ARCH_STRNCHR
+extern char * strnchr(const char *, size_t, int);
+#endif
+#ifndef __HAVE_ARCH_STRRCHR
+extern char * strrchr(const char *,int);
+#endif
+#ifndef __HAVE_ARCH_STRSTR
+extern char * strstr(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRLEN
+extern __kernel_size_t strlen(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNLEN
+extern __kernel_size_t strnlen(const char *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRPBRK
+extern char * strpbrk(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRSEP
+extern char * strsep(char **,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRSPN
+extern __kernel_size_t strspn(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRCSPN
+extern __kernel_size_t strcspn(const char *,const char *);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+extern void * memset(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCPY
+extern void * memcpy(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMMOVE
+extern void * memmove(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMSCAN
+extern void * memscan(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCHR
+extern void * memchr(const void *,int,__kernel_size_t);
+#endif
+
+extern char *kstrdup(const char *s, gfp_t gfp);
+
+extern char *strerror(int errnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif /* _LWK_STRING_H */
diff --git a/kitten/include/lwk/stringify.h b/kitten/include/lwk/stringify.h
new file mode 100644 (file)
index 0000000..faad2a0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __LWK_STRINGIFY_H
+#define __LWK_STRINGIFY_H
+
+/* Indirect stringification.  Doing two levels allows the parameter to be a
+ * macro itself.  For example, compile with -DFOO=bar, __stringify(FOO)
+ * converts to "bar".
+ */
+
+#define __stringify_1(x)       #x
+#define __stringify(x)         __stringify_1(x)
+
+#endif /* !__LWK_STRINGIFY_H */
diff --git a/kitten/include/lwk/task.h b/kitten/include/lwk/task.h
new file mode 100644 (file)
index 0000000..c88e10c
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef _LWK_TASK_H
+#define _LWK_TASK_H
+
+#include <lwk/types.h>
+#include <lwk/idspace.h>
+#include <lwk/cpumask.h>
+
+/**
+ * Valid user-space created task IDs are in interval
+ * [TASK_MIN_ID, TASK_MAX_ID].
+ */
+#define TASK_MIN_ID                    0
+#define TASK_MAX_ID                    4094
+
+/**
+ * The task ID to use for the init_task.
+ * Put it at the top of the space to keep it out of the way.
+ */
+#define INIT_TASK_ID                   TASK_MAX_ID
+
+/**
+ * Task states
+ */
+#define TASKSTATE_READY                (1 << 0)
+#define TASKSTATE_UNINTERRUPTIBLE      (1 << 1)
+#define TASKSTATE_INTERRUPTIBLE        (1 << 2)
+#define TASKSTATE_EXIT_ZOMBIE          (1 << 3)
+typedef unsigned int taskstate_t;
+
+/**
+ * Events that tasks may wait for and be sent.
+ */
+#define LWKEVENT_CHILD_TASK_EXITED     (1 << 0)
+#define LWKEVENT_PORTALS_EVENT_POSTED  (1 << 1)
+typedef unsigned long event_t;
+
+/**
+ * Initial conditions to use for new task.
+ */
+typedef struct {
+       uid_t                  uid;
+       uid_t                  gid;
+       id_t                   aspace_id;
+       vaddr_t                entry_point;
+       vaddr_t                stack_ptr;
+       id_t                   cpu_id;
+       const user_cpumask_t * cpumask;
+} start_state_t;
+
+/**
+ * Core task management API.
+ * These are accessible from both kernel-space and user-space (via syscalls).
+ */
+extern int task_get_myid(id_t *id);
+extern int task_create(id_t id_request, const char *name,
+                       const start_state_t *start_state, id_t *id);
+extern int task_exit(int status);
+extern int task_yield(void);
+
+#ifdef __KERNEL__
+
+#include <lwk/types.h>
+#include <lwk/init.h>
+#include <lwk/spinlock.h>
+#include <lwk/list.h>
+#include <lwk/seqlock.h>
+#include <lwk/signal.h>
+#include <lwk/idspace.h>
+#include <arch/atomic.h>
+#include <arch/page.h>
+#include <arch/processor.h>
+#include <arch/task.h>
+#include <arch/current.h>
+#include <arch/mmu.h>
+
+/**
+ * Flags for task_struct.flags field.
+ */
+#define PF_USED_MATH    0x00002000      /* if unset the fpu must be initialized before use */
+
+/**
+ * Signal handler structure.
+ */
+struct sighand_struct {
+       atomic_t                count;
+       struct k_sigaction      action[_NSIG];
+       spinlock_t              siglock;
+       struct list_head        signalfd_list;
+};
+
+/**
+ * Task structure (aka Process Control Block).
+ * There is one of these for each OS-managed thread of execution in the
+ * system.  A task is a generic "context of execution"... it either
+ * represents a user-level process, user-level thread, or kernel thread.
+ */
+struct task_struct {
+       id_t                    id;              /* The task's ID */
+       char                    name[16];        /* The task's name */
+       struct hlist_node       ht_link;         /* Task hash table linkage */
+
+       taskstate_t             state;           /* The task's current state */
+
+       uid_t                   uid;             /* user ID */
+       gid_t                   gid;             /* group ID */
+
+       struct aspace *         aspace;          /* Address space task is in */
+       struct sighand_struct * sighand;         /* signal handler info */
+
+       cpumask_t               cpumask;         /* CPUs this task may migrate
+                                                   to and create tasks on */
+       id_t                    cpu_id;          /* CPU this task is bound to */
+
+       struct list_head        sched_link;      /* For per-CPU scheduling lists */
+
+       unsigned long           ptrace;
+       uint32_t                flags;
+
+       int                     exit_status;     /* Reason the task exited */
+
+       struct arch_task        arch;            /* arch specific task info */
+};
+
+union task_union {
+       struct task_struct      task_info;
+       unsigned long           stack[TASK_SIZE/sizeof(long)];
+};
+
+extern union task_union bootstrap_task_union;
+extern struct aspace bootstrap_aspace;
+
+/**
+ * Valid task IDs are in interval [__TASK_MIN_ID, __TASK_MAX_ID].
+ */
+#define __TASK_MIN_ID   TASK_MIN_ID
+#define __TASK_MAX_ID   TASK_MAX_ID+1  /* +1 for IDLE_TASK_ID */
+
+/**
+ * ID of the idle task.
+ */
+#define IDLE_TASK_ID    TASK_MAX_ID+1
+
+/**
+ * Checks to see if a task structure is the init task.
+ * The init task is the first user-space task created by the kernel.
+ */
+static inline int
+is_init(struct task_struct *tsk)
+{
+       return (tsk->id == 1);
+}
+
+#define clear_stopped_child_used_math(child) do { (child)->flags &= ~PF_USED_MATH; } while (0)
+#define set_stopped_child_used_math(child) do { (child)->flags |= PF_USED_MATH; } while (0)
+#define clear_used_math() clear_stopped_child_used_math(current)
+#define set_used_math() set_stopped_child_used_math(current)
+#define conditional_stopped_child_used_math(condition, child) \
+        do { (child)->flags &= ~PF_USED_MATH, (child)->flags |= (condition) ? PF_USED_MATH : 0; } while (0)
+#define conditional_used_math(condition) \
+        conditional_stopped_child_used_math(condition, current)
+#define copy_to_stopped_child_used_math(child) \
+        do { (child)->flags &= ~PF_USED_MATH, (child)->flags |= current->flags & PF_USED_MATH; } while (0)
+/* NOTE: this will return 0 or PF_USED_MATH, it will never return 1 */
+#define tsk_used_math(p) ((p)->flags & PF_USED_MATH)
+#define used_math() tsk_used_math(current)
+
+extern int __init task_subsys_init(void);
+
+extern int arch_task_create(struct task_struct *task,
+                            const start_state_t *start_state);
+
+extern int sys_task_get_myid(id_t __user *id);
+extern int sys_task_create(id_t id_request, const char __user *name,
+                           const start_state_t __user *start_state,
+                           id_t __user *id);
+extern int sys_task_exit(int status);
+extern int sys_task_yield(void);
+
+extern int __task_reserve_id(id_t id);
+extern int __task_create(id_t id, const char *name,
+                         const start_state_t *start_state,
+                         struct task_struct **task);
+
+#endif
+#endif
diff --git a/kitten/include/lwk/time.h b/kitten/include/lwk/time.h
new file mode 100644 (file)
index 0000000..dd39b33
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _LWK_TIME_H
+#define _LWK_TIME_H
+
+#include <lwk/types.h>
+#include <lwk/init.h>
+#include <arch/time.h>
+
+#define NSEC_PER_SEC  1000000000L
+#define NSEC_PER_USEC 1000L
+#define USEC_PER_NSEC 1000L
+
+struct timeval {
+       time_t          tv_sec;         /* seconds */
+       suseconds_t     tv_usec;        /* microseconds */
+};
+
+struct timezone {
+       int             tz_minuteswest; /* minutes west of Greenwich */
+       int             tz_dsttime;     /* type of dst correction */
+};
+
+struct timespec {
+       time_t          tv_sec;         /* seconds */
+       long            tv_nsec;        /* nanoseconds */
+};
+
+void __init time_init(void);
+void init_cycles2ns(uint32_t khz);
+uint64_t cycles2ns(uint64_t cycles);
+uint64_t get_time(void);
+void set_time(uint64_t ns);
+
+#define timespec_is_valid(ts) \
+(((ts)->tv_sec >= 0) && (((unsigned long)(ts)->tv_nsec) < NSEC_PER_SEC))
+
+#endif
diff --git a/kitten/include/lwk/timer.h b/kitten/include/lwk/timer.h
new file mode 100644 (file)
index 0000000..64333bc
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _LWK_TIMER_H
+#define _LWK_TIMER_H
+
+#include <lwk/idspace.h>
+#include <lwk/list.h>
+
+/**
+ * This structure defines a timer, including when the timer should expire
+ * and the callback function to call when it expires. The callback function
+ * runs in interrupt context with interrupts disabled.
+ */
+struct timer {
+       struct list_head link;
+       id_t             cpu;            /* CPU this timer is installed on */
+       uint64_t         expires;        /* Time when this timer expires */
+       uintptr_t        data;           /* arg to pass to function */
+       void (*function)(uintptr_t);     /* executed when timer expires */
+};
+
+/**
+ * Core timer API.
+ */
+void timer_add(struct timer *timer);
+void timer_del(struct timer *timer);
+uint64_t timer_sleep_until(uint64_t when);
+
+/**
+ * Internal timer-subsystem functions.
+ * Normal kernel code and drivers should not call these.
+ */
+int timer_subsys_init(void);
+void expire_timers(void);
+void schedule_next_wakeup(void);
+
+/**
+ * Architecture-dependent timer functions.
+ */
+void arch_schedule_next_wakeup(uint64_t when);
+
+#endif
diff --git a/kitten/include/lwk/types.h b/kitten/include/lwk/types.h
new file mode 100644 (file)
index 0000000..897e747
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef _LWK_TYPES_H
+#define _LWK_TYPES_H
+
+#ifdef __KERNEL__
+
+#define BITS_TO_LONGS(bits) \
+       (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+       unsigned long name[BITS_TO_LONGS(bits)]
+
+#define BITS_PER_BYTE 8
+#endif
+
+#include <lwk/posix_types.h>
+#include <arch/types.h>
+
+#ifndef __KERNEL_STRICT_NAMES
+
+typedef __u32 __kernel_dev_t;
+
+typedef __kernel_fd_set                fd_set;
+typedef __kernel_dev_t         dev_t;
+typedef __kernel_ino_t         ino_t;
+typedef __kernel_mode_t                mode_t;
+typedef __kernel_nlink_t       nlink_t;
+typedef __kernel_off_t         off_t;
+typedef __kernel_pid_t         pid_t;
+typedef __kernel_daddr_t       daddr_t;
+typedef __kernel_key_t         key_t;
+typedef __kernel_suseconds_t   suseconds_t;
+typedef __kernel_timer_t       timer_t;
+typedef __kernel_clockid_t     clockid_t;
+typedef __kernel_mqd_t         mqd_t;
+typedef __kernel_uid_t         uid_t;
+typedef __kernel_gid_t         gid_t;
+typedef __kernel_loff_t                loff_t;
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t                size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t       ssize_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t     ptrdiff_t;
+#endif
+
+#ifndef _UINTPTR_T
+#define _UINTPTR_T
+typedef __kernel_uintptr_t     uintptr_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time_t                time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t       clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t       caddr_t;
+#endif
+
+/* bsd */
+typedef unsigned char          u_char;
+typedef unsigned short         u_short;
+typedef unsigned int           u_int;
+typedef unsigned long          u_long;
+
+/* sysv */
+typedef unsigned char          unchar;
+typedef unsigned short         ushort;
+typedef unsigned int           uint;
+typedef unsigned long          ulong;
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef                __u8            u_int8_t;
+typedef                __s8            int8_t;
+typedef                __u16           u_int16_t;
+typedef                __s16           int16_t;
+typedef                __u32           u_int32_t;
+typedef                __s32           int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+/* user-space uses stdint.h for these */
+#ifdef __KERNEL__
+
+typedef                __u8            uint8_t;
+typedef                __u16           uint16_t;
+typedef                __u32           uint32_t;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef                __u64           uint64_t;
+typedef                __u64           u_int64_t;
+typedef                __s64           int64_t;
+#endif
+
+#endif /* __KERNEL_ */
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+
+#endif /* __KERNEL_STRICT_NAMES */
+
+#ifdef __KERNEL__
+/* _Bool is a base type in C99... what a bad name! */
+typedef _Bool                  bool;
+#else
+#include <stdbool.h>
+#include <stdint.h>
+#endif
+
+/*
+ * Below are truly LWK-specific types that should never collide with
+ * any application/library that wants lwk/types.h.
+ */
+
+/* Address types */
+typedef        __kernel_uintptr_t      paddr_t;        /* physical address */
+typedef        __kernel_uintptr_t      vaddr_t;        /* virtual address */
+typedef        __kernel_uintptr_t      kaddr_t;        /* kernel virtual address */
+typedef        __kernel_uintptr_t      uaddr_t;        /* user virtual address */
+
+/* Locality group ID */
+typedef unsigned int           lgroup_t;
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+
+#ifdef __KERNEL__
+typedef unsigned __bitwise__ gfp_t;
+#endif
+
+struct ustat {
+       __kernel_daddr_t        f_tfree;
+       __kernel_ino_t          f_tinode;
+       char                    f_fname[6];
+       char                    f_fpack[6];
+};
+
+#endif /* _LWK_TYPES_H */
diff --git a/kitten/include/lwk/unistd.h b/kitten/include/lwk/unistd.h
new file mode 100644 (file)
index 0000000..65b2eb5
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _LWK_UNISTD_H
+#define _LWK_UNISTD_H
+
+/*
+ * Include machine specific syscall numbers
+ */
+#include <arch/unistd.h>
+
+#endif /* _LWK_UNISTD_H */
diff --git a/kitten/include/lwk/uts.h b/kitten/include/lwk/uts.h
new file mode 100644 (file)
index 0000000..79ddbf5
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _LWK_UTS_H
+#define _LWK_UTS_H
+
+#include <lwk/compile.h>  /* for UTS_MACHINE and UTS_VERSION */
+
+/*
+ * Defines for what uname() should return 
+ * We trick user-level into thinking we are Linux for compatibility purposes.
+ */
+#ifndef UTS_LINUX_SYSNAME
+#define UTS_LINUX_SYSNAME "Linux"
+#endif
+
+#ifndef UTS_LINUX_RELEASE
+#define UTS_LINUX_RELEASE "2.6.23"
+#endif
+
+#ifndef UTS_NODENAME
+#define UTS_NODENAME "(none)"  /* set by sethostname() */
+#endif
+
+#ifndef UTS_DOMAINNAME
+#define UTS_DOMAINNAME "(none)"        /* set by setdomainname() */
+#endif
+
+#endif
diff --git a/kitten/include/lwk/utsname.h b/kitten/include/lwk/utsname.h
new file mode 100644 (file)
index 0000000..76c9d65
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _LWK_UTSNAME_H
+#define _LWK_UTSNAME_H
+
+#define __UTS_LEN 64
+
+struct utsname {
+       char sysname[65];
+       char nodename[65];
+       char release[65];
+       char version[65];
+       char machine[65];
+       char domainname[65];
+};
+
+#endif /* _LWK_UTSNAME_H */
diff --git a/kitten/include/lwk/waitq.h b/kitten/include/lwk/waitq.h
new file mode 100644 (file)
index 0000000..f77c7e8
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _LWK_WAITQ_H
+#define _LWK_WAITQ_H
+
+#include <lwk/spinlock.h>
+#include <lwk/list.h>
+#include <lwk/task.h>
+
+typedef struct waitq {
+       spinlock_t           lock;
+       struct list_head     waitq;
+} waitq_t;
+
+typedef struct waitq_entry {
+       struct task_struct * task;
+       struct list_head     link;
+} waitq_entry_t;
+
+#define DECLARE_WAITQ(name)                             \
+       waitq_t name = {                                \
+           .lock  = SPIN_LOCK_UNLOCKED,                \
+           .waitq = { &(name).waitq, &(name).waitq }   \
+       }
+
+#define DECLARE_WAITQ_ENTRY(name, tsk)                  \
+       waitq_entry_t name = {                          \
+           .task  = tsk,                               \
+           .link  = { &(name).link, &(name).link }     \
+       }
+
+extern void waitq_init(waitq_t *waitq);
+extern void waitq_init_entry(waitq_entry_t *entry, struct task_struct *task);
+extern bool waitq_active(waitq_t *waitq);
+extern void waitq_add_entry(waitq_t *waitq, waitq_entry_t *entry);
+extern void waitq_prepare_to_wait(waitq_t *waitq, waitq_entry_t *entry,
+                                  taskstate_t state);
+extern void waitq_finish_wait(waitq_t *waitq, waitq_entry_t *entry);
+extern void waitq_wakeup(waitq_t *waitq);
+
+/**
+ * This puts the task to sleep until condition becomes true.
+ * This must be a macro because condition is tested repeatedly, not just
+ * when wait_event() is first called.
+ */
+#define wait_event(waitq, condition)                               \
+do {                                                               \
+       DECLARE_WAITQ_ENTRY(__entry, current);                     \
+       for (;;) {                                                 \
+               waitq_prepare_to_wait(&waitq, &__entry,            \
+                                     TASKSTATE_UNINTERRUPTIBLE);  \
+               if (condition)                                     \
+                       break;                                     \
+               schedule();                                        \
+       }                                                          \
+       waitq_finish_wait(&waitq, &__entry);                       \
+} while (0)
+
+#endif
diff --git a/kitten/include/lwk/xcall.h b/kitten/include/lwk/xcall.h
new file mode 100644 (file)
index 0000000..ce8ea7c
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _LWK_XCALL_H
+#define _LWK_XCALL_H
+
+#include <lwk/cpumask.h>
+#include <lwk/idspace.h>
+#include <arch/xcall.h>
+
+int
+xcall_function(
+       cpumask_t       cpu_mask,
+       void            (*func)(void *info),
+       void *          info,
+       bool            wait
+);
+
+int
+arch_xcall_function(
+       cpumask_t       cpu_mask,
+       void            (*func)(void *info),
+       void *          info,
+       bool            wait
+);
+
+void
+xcall_reschedule(
+       id_t            cpu
+);
+
+void
+arch_xcall_reschedule(
+       id_t            cpu
+);
+
+#endif
diff --git a/kitten/include/rca/cray_event_def.h b/kitten/include/rca/cray_event_def.h
new file mode 100644 (file)
index 0000000..b4de9f1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2003 Cray, Inc.
+ *
+ * The contents of this file are proprietary information of Cray Inc. 
+ * and may not be disclosed without prior written consent.
+ */
+/*
+ *
+ * This code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+
+#ifndef __CRAY_EVENT_DEF_H__
+#define __CRAY_EVENT_DEF_H__
+
+
+#include <lwk/types.h>
+#include <lwk/time.h>
+#include <rca/rca_defs.h>
+
+typedef union rs_node_u {
+    /* Little Endian */
+    struct {
+        uint32_t _node_arch     : 2;    /* System architecture      */
+        uint32_t _node_type     : 6;    /* Component type           */
+        uint32_t _node_state    : 7;    /* Component state from SM  */
+        uint32_t _node_is_svc   : 1;    /* Service node bit         */
+
+        uint32_t _node_id       : 16;   /* Node and Seastar NID     */
+
+        uint32_t                : 2;    /* Unused                   */
+        uint32_t _node_x        : 6;    /* What position in the row */
+        uint32_t _node_subtype  : 4;    /* Component subtype        */
+        uint32_t _node_row      : 4;    /* Which row of cabinets    */
+
+        uint32_t _node_cage     : 4;    /* Cage in the cabinet      */
+        uint32_t _node_slot     : 4;    /* Slot in the cage         */
+        uint32_t _node_modcomp  : 4;    /* Component on a module    */
+        uint32_t _node_link     : 4;    /* Link on seastar          */
+    } __attribute__((packed)) rs_node_s;
+    struct {
+        uint32_t :2, :6, :7, :1, :16, :2, :6, :4, :4; /* Unused fields */
+        uint32_t _node_startx   : 8;    /* What position in the row */
+        uint32_t _node_endx     : 8;    /* Which row of cabinets */
+    } __attribute__((packed)) rs_node_s1;
+    uint64_t rs_node_flat;
+} __attribute__((packed)) rs_node_t;
+
+/* TODO: this and RCA RS_MSG_LEN define needs to be taken out soon. */
+#ifndef RS_MSG_LEN 
+#define RS_MSG_LEN 1
+#endif
+
+typedef uint32_t rs_error_code_t;
+typedef int32_t rs_event_code_t;
+
+
+// from rs_svc_id.h
+
+/* NOTE for the following event related structures:
+ * ###################################################################
+ * There are following restrictions for the L0 Opteron communication
+ * related structures.
+ * The elements must be aligned on 4-byte boundaries.  The structure
+ * size must be a multiple of 4 bytes. Structures should be packed so
+ * that the compiler will not insert padding.
+ * ###################################################################
+ */
+typedef uint32_t rs_service_t;
+typedef uint32_t rs_instance_t;
+typedef uint32_t  rs_priority_t;
+typedef uint32_t  rs_flag_t;
+
+/*
+ * NOTE: This rs_service_id_t is packed.  If we update this structure,
+ *  we need to make sure that each element is 4-byte aligned,
+ *  otherwise it might break the L0 Opteron communication (size
+ *  of rs_service_id_t must be a multiple of 4bytes).
+ */
+typedef struct rs_service_id_s {
+    rs_instance_t svid_inst;    /* a sequence identifier */
+    rs_service_t  svid_type;    /* the kind of service */
+    rs_node_t     svid_node;    /* the x.y.z coordinates */
+} __attribute__((packed)) rs_service_id_t;
+
+
+/* time structure
+ * rt_tv1 and rt_tv2 are hedges against field size inflation.
+ */
+typedef union rs_time_u {
+    struct timeval _rt_tv;
+    struct {
+           uint64_t _rt_tv1;
+           uint64_t _rt_tv2;
+    } rs_evtime_s;      /* timeval needs to be adjusted for 32/64 bits */
+} rs_time_t;
+
+/*
+ * NOTE: This rs_event_t is packed.  If we update this structure, we need to
+ *      make sure that each element is 4-byte aligned, otherwise it might
+ *      break the L0 Opteron communication (size of rs_event_t must be a
+ *      multiple of 4bytes).
+ *
+ * event structure:
+ * may be used as a fixed or variable length event.
+ * In RCA's case, ev_data is fixed length and RS_MSG_LEN should be defined
+ * before inclusion of this file.  ev_len here signifies the length in
+ * bytes of significant data in ev_data.  The SMW, in contrast, treats events
+ * as variable length;  RS_MSG_LEN is 1 and the actual length of the data is
+ * determined when the object is allocated. In this case the real length
+ * of ev_data is stored in ev_len.  RCA related events has fixed length
+ * ev_data and RS_MSG_LEN is 256 (multiple of 4bytes).  Same as the SMW
+ * events, real length of ev_data needs to be stored in ev_len.
+ */
+typedef struct rs_event_s {
+    rs_event_code_t    ev_id;               /* type of event */
+    uint32_t           ev_seqnum;           /* req/rsp sequence number */
+    rs_service_id_t    ev_gen;              /* what this event pertains to */
+    rs_service_id_t    ev_src;              /* creator of this event */
+    rs_flag_t          ev_flag;             /* any bit flags */
+    rs_time_t          _ev_stp;             /* time of event creation */
+    rs_priority_t      ev_priority;         /* priority [0 low, 9 high] */
+    int32_t            ev_len;              /* length of data */
+    char               ev_data[RS_MSG_LEN]; /* payload (must be last) */
+} __attribute__((packed)) rs_event_t;
+
+#define rs_sizeof_event(data_length) \
+    (((int)(&((rs_event_t*)0)->ev_data)) + (data_length)) 
+
+#endif /* __CRAY_EVENT_DEF_H__ */
diff --git a/kitten/include/rca/l0rca_config.h b/kitten/include/rca/l0rca_config.h
new file mode 100644 (file)
index 0000000..ae6be7a
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2006 Cray, Inc.
+ *
+ * The contents of this file is proprietary information of Cray Inc. 
+ * and may not be disclosed without prior written consent.
+ */
+/*
+ *
+ * This code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+
+#ifndef __L0RCA_CONFIG_H__
+#define __L0RCA_CONFIG_H__
+
+
+#include <rca/cray_event_def.h>                /* rca_types.h includes rs_event.h */
+
+/*
+ * PKT_MODE* Registers:
+ *
+ * Writing a "0" to a bit in pkt_mode0 will atomically clear that bit
+ * in pkt_mode.  Writing a "1" to a bit in pkt_mode1 will atomically
+ * set that bit in pkt_mode.  Reading any of these will return the
+ * instantanious contents of pkt_mode.  Writing pkt_mode replaces the
+ * contents non-atomically.
+ */
+typedef struct {
+    uint32_t    pkt_mode;
+    uint32_t    _pad1;
+    uint32_t    pkt_mode0;  /* atomically clear bits */
+    uint32_t    _pad2;
+    uint32_t    pkt_mode1;  /* atomically set bits */
+} l0ssi_pkt_mode_t;
+
+#define phy_pkt_mode    (*(l0ssi_pkt_mode_t *)PKT_MODE)
+
+#define PKT_MODE0   (uint32_t)&phy_pkt_mode.pkt_mode0
+#define PKT_MODE1   (uint32_t)&phy_pkt_mode.pkt_mode1
+
+/*
+ * How the RCA interrupts the L0.
+ *
+ * Writing a "0" to a bit in pkt_mode0 will atomically CLEAR that bit
+ * in pkt_mode.  Writing a "1" to a bit in pkt_mode1 will atomically
+ * SET that bit in pkt_mode.  Normally, pkt_mode should never be
+ * written directly.  It can be read to get the current state of bits.
+ * In general, any set bits in pkt_mode will cause an interrupt to
+ * be raised to the L0, via the SSI and L0_FPGA.
+ *
+ * CAUTION: pkt_mode0 must only be written with "0"(s) in the
+ * position(s) to be cleared and "1"s everywhere else.  I.e. it
+ * must be written with the value one would use to AND-out the
+ * bits.  This is contrary to most SET/CLEAR register implementations.
+ *
+ * Bits in pkt_mode are assigned in l0ssi_intr.h
+ */
+typedef l0ssi_pkt_mode_t l0rca_intr_t;
+#define l0r_intr_get   pkt_mode
+#define l0r_intr_clr   pkt_mode0
+#define l0r_intr_set   pkt_mode1
+
+/* Should be removed... */
+#define L0RCA_CONFIG L0RCA_CFG
+
+/* defined channel id */
+#define L0RCA_CH_EV_UP        0
+#define L0RCA_CH_EV_DOWN      1
+#define L0RCA_CH_CON_UP       2
+#define L0RCA_CH_CON_DOWN     3
+#define L0RCA_CH_KGDB_UP      4
+#define L0RCA_CH_KGDB_DOWN    5
+#define NUM_L0RCA_CHANNELS    6
+
+/* NOTE for the following L0 Opteron communication related structures:
+ * ###################################################################
+ * There are following restrictions for the L0 Opteron communication
+ * related structures.
+ * The elements must be aligned on 4-byte boundaries.  The structure
+ * size must be a multiple of 4 bytes. Structures should be packed so
+ * that the compiler will not insert padding.  
+ * ###################################################################
+ */
+
+/* 
+ * l0rca_ch_data_t: channel buffer data structure
+ * NOTE: This l0rca_ch_data_t is packed.  If we update this structure,
+ *     we need to make sure that each element is 4-byte aligned,
+ *     otherwise it might break the L0 Opteron communication (size of
+ *     l0rca_ch_data_t must be a multiple of 4bytes).
+ *     All communication channel uses rs_event_t so, the size of object
+ *     in buffer is sizeof(rs_event_t).  RCA events has fixed ev_data
+ *     length (256) and num_obj is the number of events can be stored
+ *     in the buffer.
+ *
+ * The *_intr_bit fields declare which bit in the PKT_MODE register
+ * is used for the channel interrupt.  l0_intr_bit is for interrupts
+ * sent *to* the L0, while proc_intr_bit is for interrupts sent *to*
+ * the Opteron processor.
+ */
+typedef struct l0rca_ch_data_s {
+       uint32_t num_obj;        /* number of objects    */
+       uint32_t ridx;           /* read index           */
+       uint32_t widx;           /* write index          */
+       uint32_t l0_intr_bit;    /* Opteron -> L0 intr assignment */
+       uint32_t proc_intr_bit;  /* L0 -> Opteron intr assignment */
+} __attribute__((packed)) l0rca_ch_data_t;
+
+#define L0RCA_CONF_VERSION     2
+
+/*
+ * Circular Buffer Usage:
+ *
+ * When (widx == ridx), buffer is empty;
+ * ELSE When (widx - ridx < num_obj)), there are one or more 
+ * available buffers.
+ *
+ * ridx and widx reflect the object index, not byte index.
+ *
+ * Restrictions:
+ *
+ * num_obj must be a power of 2 (i.e. (num_obj & (num_obj - 1)) == 0).
+ * Therefore indices are normalized with AND: idx = ridx & (num_obj - 1).
+ *
+ */
+
+/*
+ * NOTE: This l0rca_config_t is packed.  If we update this sturcture,
+ *     we need to make sure that each element is 4-byte aligned,
+ *     otherwise it might break the L0 Opteron communication (size
+ *     of l0rca_config_t must be a multiple of 4bytes).
+ *
+ * configuration data structure */
+typedef struct l0rca_config_s {
+       uint64_t        l0rca_buf_addr;         /* ch buffer addr */
+       uint64_t        l0rca_l0_intr_addr;     /* interrupt to L0 */
+       uint32_t                version;                                /* config version */
+       rs_node_t               proc_id;                         /* node id */
+       int32_t         proc_num;                         /* proc number (0-3) */
+       int32_t         reserved_1;                       /* reserved for future use */
+       int32_t         reserved_2;                      /* reserved for future use */
+       /* channel data */
+       l0rca_ch_data_t chnl_data[NUM_L0RCA_CHANNELS];
+} __attribute__((packed)) l0rca_config_t;
+
+
+/*
+ * Definitions in the L0-reserved area of SIC RAM
+ */
+#define L0_SIC_RAM  0xfffff000
+#define L0_SIC_RAM_LEN  4096
+
+#define COLDSPIN    0xfffffe80
+#define L0RCA_CFG   L0_SIC_RAM
+#define L0RCA_CFG_LEN   (COLDSPIN - L0RCA_CFG)
+
+/*
+ * The following provides an abstraction for accessing the RAM
+ * location of the config structure.  It set phy_l0r_cfg to the
+ * l0rca_config_t physical address defined as L0RCA_CONFIG.
+ * To use it, include this header file and then access the
+ * config area as &phy_l0r_cfg.<element>.
+ */
+#define phy_l0r_cfg    (*(l0rca_config_t *)L0RCA_CFG)
+
+
+#endif /* !__L0RCA_CONFIG_H__ */
diff --git a/kitten/include/rca/rca_defs.h b/kitten/include/rca/rca_defs.h
new file mode 100644 (file)
index 0000000..cae15ec
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003 Cray, Inc.
+ *
+ * The contents of this file are proprietary information of Cray Inc. 
+ * and may not be disclosed without prior written consent.
+ */
+/*
+ * This code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+
+
+#ifndef __RCA_DEFS_H__
+#define __RCA_DEFS_H__
+
+
+// Definitions moved from rs_event_name.h
+/* Console log */
+#define RS_CONSOLE_LOG                          (28)
+/* Debug */
+#define RS_CONSOLE_INPUT                        (51)
+#define RS_KGDB_INPUT                           (52)
+#define RS_KGDB_OUTPUT                          (53)
+
+#define RS_DBG_CLASS           0x00010000
+#define RS_LOG_CLASS           0x00001000
+
+/* Console log */
+#define ec_console_log         (RS_LOG_CLASS | RS_CONSOLE_LOG)
+
+/* Debug */
+#define ec_console_input       (RS_DBG_CLASS | RS_CONSOLE_INPUT)
+#define ec_kgdb_input          (RS_DBG_CLASS | RS_KGDB_INPUT)
+#define ec_kgdb_output         (RS_DBG_CLASS | RS_KGDB_OUTPUT)
+
+#define RS_RCA_SVC_CLASS       7       /* RCA service class */
+/* service type class bits */
+#define RS_CLASS_BITS          8
+#define RS_CLASS_MASK          ((1 << RS_CLASS_BITS) - 1)
+
+#define RS_SUBCLASS_BITS       24
+#define RS_SUBCLASS_MASK       ((1 << RS_SUBCLASS_BITS) -1)
+
+/* generate service type */
+#define RCA_MAKE_SERVICE_INDEX(class, subclass)                \
+     ( (((class)&RS_CLASS_MASK) << RS_SUBCLASS_BITS) | \
+              ((subclass) & RS_SUBCLASS_MASK) )
+
+
+/* macro for setting up service id */
+#define RS_MKSVC(i, t, n)      (rs_service_id_t){(i), (t), (n)}
+
+
+/* need to set RS_MSG_LEN before including rs_event.h */
+#define RS_MSG_LEN 256 
+
+#define RCA_SVC_CLASS     RS_RCA_SVC_CLASS     /* 7 */
+
+#define RCA_CLASS_BITS         RS_CLASS_BITS
+#define RCA_CLASS_MASK         RS_CLASS_MASK
+
+/* number of bits client may use in subclass */
+#define RCA_SUBCLASS_BITS      RS_SUBCLASS_BITS
+#define RCA_SUBCLASS_MASK      RS_SUBCLASS_MASK
+
+#define RCA_INST_ANY   0xffffffffUL
+
+/* system console log */
+#define RCA_SVCTYPE_CONS       RCA_MAKE_SERVICE_INDEX(RCA_SVC_CLASS, 6)
+#define RCA_SVCTYPE_TEST0      RCA_MAKE_SERVICE_INDEX(RCA_SVC_CLASS, 10)
+
+/* rs_service_id_t constants and helpers */
+#define RCA_MKSVC(i, t, n)     RS_MKSVC((i), (t), (n))
+
+#define RCA_LOG_DEBUG  7
+
+#endif /* !_RCA_TYPES_H_ */
diff --git a/kitten/include/rca/rca_l0.h b/kitten/include/rca/rca_l0.h
new file mode 100644 (file)
index 0000000..ce7cb05
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2003 Cray Inc.
+ *
+ * The contents of this file is proprietary information of Cray Inc.
+ * and may not be disclosed without prior written consent.
+ *
+ */
+/*
+ * This code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#ifndef        __RCA_L0_H__
+#define        __RCA_L0_H__
+
+#include <rca/l0rca_config.h>
+
+
+/*
+ * Macros to read/write Seastar Scratch RAM for everyone else.
+ */
+#define SSMEMPUT(dest,src,nb)  memcpy((void *)dest,(void *)src,nb)
+#define SSMEMGET(dest,src,nb)  memcpy((void *)dest,(void *)src,nb)
+
+#define SSPUT64(to_ptr,value) (*(to_ptr) = (value))
+#define SSPUT32(to_ptr,value) (*(to_ptr) = (value))
+
+#define SSGET64(from_ptr,to_var) ((to_var) = *(from_ptr))
+#define SSGET32(from_ptr,to_var) ((to_var) = *(from_ptr))
+
+/* TODO - Revisit these later */
+#define        LOCK_CHANNEL(chn_num)
+#define        UNLOCK_CHANNEL(chn_num)
+
+typedef int (*l0rca_down_handle_t)(int chn_num, rs_event_t* buf, int32_t num);
+typedef int (*l0rca_up_handle_t)(int chn_num);
+
+typedef struct l0rca_ch_status {
+       uint32_t        num_obj;                /* number of objects    */
+       uint32_t        ridx;                   /* read index           */
+       uint32_t        widx;                   /* write index */
+       uint32_t        reg_count;
+       rs_event_t*     ch_buf_ptr;
+} l0rca_ch_status_t;
+
+/* 
+ * API defines 
+ * TODO - All API calls defined here may not be implemented in l0rca.c.
+ * These are to be implemented as needed.
+ */
+
+/* NOTE
+ * download means data transfer from the L0 to the Opteron
+ * upload means data transfer from the Opteron to the LO; 
+ */
+
+#ifdef STANDALONE_DIAGS
+/* 
+ * Checks if the channel is ready or not (full).
+ * Argument:   int     channel
+ * Returns:
+ *   1 if ready (not_full)
+ *   0 if not ready
+ */
+int l0rca_ch_send_ready(int ch_num);
+
+/*
+ * Clears l0rca_early_cfg.initialized.
+ * This function is required for memtest. Memtest has to move the location
+ * of the storage area for the config in order to move on to the next
+ * region to do the memory test.
+ */
+void l0rca_clear_initialized(void);
+#endif
+
+/*
+ * Function:   l0rca_init_config
+ *
+ * Description: Read L0 - RCA communication config structure and populate 
+ *              our personal copy. If there is any error, the OS panics
+ *              as not being able to communicate with L0 is a total disaster.
+ *              If already initialized then returns siliently.
+ *
+ * Arguments: None.
+ *
+ * Returns: None
+ */
+void l0rca_init_config(void);
+
+/* 
+ * Function:   register_ch_down
+ * 
+ * Description: Register function for the download channel. It is expected that
+ * there be at most one registered user for a download channel. This user 
+ * provides a callback to be invoked when data from L0 arrives on the channel.
+ * 
+ * Arguments: int ch_num IN: channel number to register on
+ *           l0rca_down_handle_t handler IN: callback routine
+ *           int poll IN: if > zero - duration in ms to check for event
+ *                        if = zero - event arrival is interrupt driven.
+ *                        if < zero - do nothing. It is assumed that the user
+ *                        has her own means to check for event arrival.
+ *
+ * Returns: EBUSY - If another user is already registered.
+ *          zero (SUCCESS) otherwise.
+ */
+int register_ch_down(int ch_num, l0rca_down_handle_t handler, int poll);
+
+/* 
+ * Function:   unregister_ch_down
+ * 
+ * Description: Unregister function for the download channel. Use to indicate
+ * that the channel is no longer to be used.
+ * 
+ * Arguments: int ch_num IN: channel number to unregister
+ *
+ * Returns: zero (SUCCESS)
+ */
+int unregister_ch_down(int ch_num);
+
+/* 
+ * Function:   register_ch_up
+ * 
+ * Description: Register function for the upload channel. It is expected that
+ * there be at most one registered user for an upload channel. This user 
+ * provides a callback to be invoked when the buffer drains below tshhld
+ * (only if the buffer became full last time the tshhld was crossed)
+ * 
+ * Arguments: int ch_num IN: channel number to register on
+ *           l0rca_up_handle_t handler IN: callback routine
+ *            int tshhld IN: buffer to drain before invoking callback; ignored
+ *                          if poll is negative.
+ *           int poll IN: if > zero - duration in ms to check for buffer drain
+ *                        if = zero - tx done interrupt invokes callback
+ *                        if < zero - do nothing. It is assumed that the user
+ *                        has her own means to check for buffer drain
+ *
+ * Returns: -EBUSY - If another user is already registered.
+ *          -EINVAL - if ch_num is not in range.
+ *          zero (SUCCESS) otherwise.
+ */
+int register_ch_up(int ch_num, l0rca_up_handle_t handler, int tshhld, int poll);
+
+/* 
+ * Function:   unregister_ch_up
+ * 
+ * Description: Unregister function for the download channel. Use to indicate
+ * that the channel is no longer to be used.
+ * 
+ * Arguments: int ch_num IN: channel number to unregister
+ *
+ * Returns: zero (SUCCESS)
+ */
+int unregister_ch_up(int ch_num);
+
+/* 
+ * Function:   ch_send_data
+ * 
+ * Description: Sends data towards the L0. 
+ * The data that buf points to is sent as the payload in an rs_event structure.
+ * The header is a separate parameter and the send routine directly copies
+ * the header and the data into the circular buffer, thus avoiding a copy.
+ * 
+ * Arguments: int ch_num IN: channel number on which to send data
+ *           rs_event_t *ev_hdr  IN: Header without len & timestamp
+ *           void* buf  IN: Buffer with data
+ *           unsigned int len IN: length of data to transfer
+ *
+ * Returns: EBUSY - If the circular channel buffer is full.
+ *          EINVAL - if no user registered on the channel (Debug only)
+ *          EFAULT - if buf or ev_hdr is NULL (Debug only)
+ *          E2BIG -  if len exceeds max event payload (RS_MSG_LEN) (Debug only)
+ *          zero (SUCCESS) otherwise.
+ *
+ * Notes: data in buf will be copied to the channel buffer, therfore, upon
+ *       return, user can free the buf.
+ */
+int ch_send_data(int ch_num, const rs_event_t *ev_hdr, 
+                void* buf, unsigned int len);
+
+/* 
+ * Function:   ch_send_event
+ * 
+ * Description: Sends an event to L0. 
+ * 
+ * Arguments: int ch_num IN: channel number on which to send the event
+ *           const rs_event_t *evp  IN: EVent to send
+ *
+ * Returns: -EINVAL - if no user registered on the channel (Debug only)
+ *          -EFAULT - if ev_hdr is NULL (Debug only)
+ *          zero -    SUCCESS, event sent.
+ *          +EBUSY -  Event not sent. Sender should retry.
+ *
+ * Notes: The event will be copied to the channel buffer, therfore, upon
+ *       return, user may free the space associated with the event
+ */
+int ch_send_event(int ch_num, const rs_event_t *evp);
+
+/* 
+ * Function:   ch_status
+ * 
+ * Description: Obtain status on the channel 
+ * 
+ * Arguments: int ch_num IN: channel number for which to obtain status
+ * Arguments: l0rca_ch_status_t *st OUT: status of the channel.
+ *
+ * Returns: zero (SUCCESS).
+ *
+ * Notes: The status represents the snapshot at the time of invocation.
+ */
+int ch_status(int ch_num, l0rca_ch_status_t *st);
+
+/* 
+ * Function:   l0rca_ch_get_event
+ * 
+ * Description: Read the next available event (if any). This allows the caller
+ *             to check for incoming events. It is usefult for those callers
+ *             that do not have a receive callback.
+ * 
+ * Arguments: int ch_num IN: channel number from which to return event
+ * Arguments:  rs_event_t *evp: Pointer where the event may be placed
+ *
+ * Returns: 0 or 1 - No of events returned (0 ==> No event otherwise always 1)
+ *          < 0   - errors such as channel not registered etc.
+ *          
+ * Note: The receive callback is the preferred way to handle incoming events. 
+ *      This API call should only be used in cases where a receive callback 
+ *      mechanism is not feasible. For example, when interupts are disabled and
+ *      incoming events need to be serviced. An example user is a kernel 
+ *      debugger.
+ */
+int l0rca_ch_get_event(int ch_num, rs_event_t *evp);
+
+/* 
+ * Function:   l0rca_poll_callback
+ * 
+ * Description: Scan the incoming channels and call the receive callback
+ *             (if any) in case an event is pending to be processed.
+ *             Update the read pointer. Next scan the outgoing channels
+ *             and if the channel was full, call the transmit done callback
+ *             so that events may be sent.
+ * 
+ * Arguments: None
+ *
+ * Returns: 0 if no events were processed, else 1.
+ *
+ * Note: It is possible that this routine is called from interrupt
+ *      context. The callbacks invoked *must* not block.
+ */
+int l0rca_poll_callback(void);
+
+/* 
+ * Function:   l0rca_get_proc_id
+ * 
+ * Description: Return the node/processor id.
+ * 
+ * Arguments: None
+ *
+ * Returns: The proc id.
+ */
+rs_node_t l0rca_get_proc_id(void);
+
+/* 
+ * Function:   l0rca_get_max_xyz
+ * 
+ * Description: Returns the current system dimensions. This information
+ *             can be used find the coordinates of the node in the system.
+ * 
+ * Arguments: int32_t *mx OUT: The x value is stored here after return
+ *           int32_t *my OUT: The y value is stored here after return
+ *           int32_t *mz OUT: The z value is stored here after return
+ * 
+ * Returns: No return value.
+ */
+void l0rca_get_max_xyz(int32_t *mx, int32_t *my, int32_t *mz);
+
+/* 
+ * Function:   l0rca_event_data
+ * 
+ * Description: Return a pointer to the data portion and length of the
+ *             data portion of the event.
+ * 
+ * Arguments: rs_event_t *evp IN: Event whose data is of interest
+ *           void **data OUT: Upon return will point to data portion of event
+ *           int32_t *len OUT: Upon return will have the length of the data
+ *                             portion of the event
+ *
+ * Returns: No Return Value.
+ */
+void l0rca_event_data(rs_event_t *evp, void **data, int32_t *len);
+
+
+#ifdef __KERNEL__
+extern int l0_gdb_init(void);
+extern int l0rca_kgdb_down_getc(void);
+extern int gdb_hook(void);
+extern int gdb_getc(int wait);
+extern int gdb_putc(char chr);
+extern int putDebugPacket(char *buf, int n);
+#endif
+
+#endif /* __RCA_L0_H__ */
diff --git a/kitten/include/rca/rca_l0_linux.h b/kitten/include/rca/rca_l0_linux.h
new file mode 100644 (file)
index 0000000..017b051
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2004 Cray Inc.
+ *
+ * The contents of this file is proprietary information of Cray Inc. 
+ * and may not be disclosed without prior written consent.
+ *
+ */
+/*
+ * This code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+
+#ifndef        __RCA_L0_LINUX_H__
+#define        __RCA_L0_LINUX_H__
+
+#include <lwk/version.h>
+
+/* 
+ * LINUX:
+ * This works as long as the physical address is below 4GB and a static 
+ * page table mapping has been setup for this address. This macro is 
+ * intended to be used before ioremap() is available for e.g in the case
+ * of early_printk.
+ */
+#define rca_l0_comm_va(addr) \
+       (void*)(((unsigned long)0xFFFFFFFF << 32) | (unsigned long)(addr))
+
+extern int l0rca_os_init(void);
+
+#endif /* __RCA_L0_LINUX_H__ */
diff --git a/kitten/init/Kconfig b/kitten/init/Kconfig
new file mode 100644 (file)
index 0000000..2375aa2
--- /dev/null
@@ -0,0 +1,17 @@
+config KALLSYMS
+       bool
+       default "y"
+       help
+          Say Y here to let the kernel print out symbolic crash information and
+          symbolic stack backtraces. This increases the size of the kernel
+          somewhat, as all symbols have to be loaded into the kernel image.
+
+config KALLSYSM_ALL
+       bool
+       default "y"
+       help
+          Normally kallsyms only contains the symbols of functions, for nicer
+          OOPS messages.  Some debuggers can use kallsyms for other
+          symbols too: say Y here to include all symbols, if you need them
+          and you don't care about adding to the size of your kernel.
+
diff --git a/kitten/init/Makefile b/kitten/init/Makefile
new file mode 100644 (file)
index 0000000..ac410b3
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Makefile for the LWK.
+#
+
+obj-y                          := main.o version.o
+
+# files to be removed upon make clean
+clean-files := ../include/lwk/compile.h
+
+# dependencies on generated files need to be listed explicitly
+
+$(obj)/version.o: include/lwk/compile.h
+
+
+# compile.h changes depending on hostname, generation number, etc,
+# so we regenerate it always.
+# mkcompile_h will make sure to only update the
+# actual file if its content has changed.
+
+include/lwk/compile.h: FORCE
+       @echo '  CHK     $@'
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
+       "$(UTS_MACHINE)" "$(CC) $(CFLAGS)"
diff --git a/kitten/init/main.c b/kitten/init/main.c
new file mode 100644 (file)
index 0000000..9b8c086
--- /dev/null
@@ -0,0 +1,135 @@
+#include <lwk/init.h>
+#include <lwk/kernel.h>
+#include <lwk/params.h>
+#include <lwk/console.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/percpu.h>
+#include <lwk/smp.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/delay.h>
+#include <lwk/bootmem.h>
+#include <lwk/aspace.h>
+#include <lwk/task.h>
+#include <lwk/sched.h>
+#include <lwk/timer.h>
+#include <lwk/palacios.h>
+
+/**
+ * Pristine copy of the LWK boot command line.
+ */
+char lwk_command_line[COMMAND_LINE_SIZE];
+
+
+/**
+ * This is the architecture-independent kernel entry point. Before it is
+ * called, architecture-specific code has done the bare minimum initialization
+ * necessary. This function initializes the kernel and its various subsystems.
+ * It calls back to architecture-specific code at several well defined points,
+ * which all architectures must implement (e.g., setup_arch()).
+ */
+void
+start_kernel()
+{
+       unsigned int cpu;
+       unsigned int timeout;
+
+       /*
+        * Parse the kernel boot command line.
+        * This is where boot-time configurable variables get set,
+        * e.g., the ones with param() and driver_param() specifiers.
+        */
+       parse_params(lwk_command_line);
+
+       /*
+        * Initialize the console subsystem.
+        * printk()'s will be visible after this.
+        */
+       console_init();
+
+       /*
+        * Hello, Dave.
+        */
+       printk(lwk_banner);
+       printk(KERN_DEBUG "%s\n", lwk_command_line);
+
+       /*
+        * Do architecture specific initialization.
+        * This detects memory, CPUs, etc.
+        */
+       setup_arch();
+
+       /*
+        * Initialize the kernel memory subsystem. Up until now, the simple
+        * boot-time memory allocator (bootmem) has been used for all dynamic
+        * memory allocation. Here, the bootmem allocator is destroyed and all
+        * of the free pages it was managing are added to the kernel memory
+        * pool (kmem) or the user memory pool (umem).
+        *
+        * After this point, any use of the bootmem allocator will cause a
+        * kernel panic. The normal kernel memory subsystem API should be used
+        * instead (e.g., kmem_alloc() and kmem_free()).
+        */
+       mem_subsys_init();
+
+       /*
+        * Initialize the address space management subsystem.
+        */
+       aspace_subsys_init();
+
+       /*
+        * Initialize the task management subsystem.
+        */
+       task_subsys_init();
+
+       /*
+        * Initialize the task scheduling subsystem.
+        */
+       sched_subsys_init();
+
+       /*
+        * Initialize the task scheduling subsystem.
+        */
+       timer_subsys_init();
+
+       /*
+        * Boot all of the other CPUs in the system, one at a time.
+        */
+       printk(KERN_INFO "Number of CPUs detected: %d\n", num_cpus());
+       for_each_cpu_mask(cpu, cpu_present_map) {
+               /* The bootstrap CPU (that's us) is already booted. */
+               if (cpu == 0) {
+                       cpu_set(cpu, cpu_online_map);
+                       continue;
+               }
+
+               printk(KERN_DEBUG "Booting CPU %u.\n", cpu);
+               arch_boot_cpu(cpu);
+
+               /* Wait for ACK that CPU has booted (5 seconds max). */
+               for (timeout = 0; timeout < 50000; timeout++) {
+                       if (cpu_isset(cpu, cpu_online_map))
+                               break;
+                       udelay(100);
+               }
+
+               if (!cpu_isset(cpu, cpu_online_map))
+                       panic("Failed to boot CPU %d.\n", cpu);
+       }
+
+#ifdef CONFIG_V3VEE
+       v3vee_run_vmm();
+       printk( "%s: VMM returned.  We're spinning\n", __func__ );
+       while(1) { asm( "hlt" ); }
+#else
+       /*
+        * Start up user-space...
+        */
+       printk(KERN_INFO "Loading initial user-level task (init_task)...\n");
+       int status;
+       if ((status = create_init_task()) != 0)
+               panic("Failed to create init_task (status=%d).", status);
+
+       schedule();  /* This should not return */
+       BUG();
+#endif
+}
diff --git a/kitten/init/version.c b/kitten/init/version.c
new file mode 100644 (file)
index 0000000..e96f09a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  linux/init/version.c
+ *
+ *  Copyright (C) 1992  Theodore Ts'o
+ *
+ *  May be freely distributed as part of Linux.
+ */
+
+#include <lwk/compile.h>
+#include <lwk/version.h>
+#include <lwk/uts.h>
+#include <lwk/utsname.h>
+
+const char lwk_banner[] =
+       "LWK version " UTS_RELEASE " (" LWK_COMPILE_BY "@"
+       LWK_COMPILE_HOST ") (" LWK_COMPILER ") " UTS_VERSION
+       "\n";
+
+/**
+ * User-level apps call the uname() system call to figure out basic
+ * information about the system they are running on, as indicated
+ * by this structure.  We report back that we are Linux since that
+ * is what standard Linux executables expect (UTS_LINUX_SYSNAME and
+ * UTS_LINUX_RELEASE).
+ */
+struct utsname linux_utsname = {
+       .sysname        =       UTS_LINUX_SYSNAME,
+       .nodename       =       UTS_NODENAME,
+       .release        =       UTS_LINUX_RELEASE,
+       .version        =       UTS_VERSION,
+       .machine        =       UTS_MACHINE,
+       .domainname     =       UTS_DOMAINNAME
+};
+
diff --git a/kitten/kernel/Makefile b/kitten/kernel/Makefile
new file mode 100644 (file)
index 0000000..259abdf
--- /dev/null
@@ -0,0 +1,5 @@
+obj-y := console.o printk.o spinlock.o params.o driver.o cpuinfo.o panic.o \
+               resource.o kallsyms.o extable.o show.o elf.o time.o xcall.o \
+               idspace.o htable.o elf_liblwk.o task.o sched.o waitq.o \
+               timer.o init_task.o
+obj-y += linux_syscalls/
diff --git a/kitten/kernel/console.c b/kitten/kernel/console.c
new file mode 100644 (file)
index 0000000..e6f3dad
--- /dev/null
@@ -0,0 +1,76 @@
+#include <lwk/kernel.h>
+#include <lwk/console.h>
+#include <lwk/spinlock.h>
+#include <lwk/params.h>
+#include <lwk/driver.h>
+#include <lwk/errno.h>
+#include <arch/uaccess.h>
+
+/**
+ * List of all registered consoles in the system.
+ *
+ * Kernel messages output via printk() will be written to
+ * all consoles in this list.
+ */
+static LIST_HEAD(console_list);
+
+/**
+ * Serializes access to the console.
+ */
+static DEFINE_SPINLOCK(console_lock);
+
+/**
+ * Holds a comma separated list of consoles to configure.
+ */
+static char console_str[128];
+param_string(console, console_str, sizeof(console_str));
+
+/**
+ * Registers a new console.
+ */
+void console_register(struct console *con)
+{
+       list_add(&con->next, &console_list);
+}
+
+/**
+ * Writes a string to all registered consoles.
+ */
+void console_write(const char *str)
+{
+       struct console *con;
+       unsigned long flags;
+
+       spin_lock_irqsave(&console_lock, flags);
+       list_for_each_entry(con, &console_list, next)
+               con->write(con, str);
+       spin_unlock_irqrestore(&console_lock, flags);
+}
+
+/**
+ * Initializes the console subsystem; called once at boot.
+ */
+void console_init(void)
+{
+       char *p, *con;
+       
+       // console_str contains comma separated list of console
+       // driver names.  Try to install a driver for each
+       // console name con.
+       p = con = console_str;
+       while (*p != '\0') {
+               if (*p == ',') {
+                       *p = '\0'; // null terminate con
+                       if (driver_init_by_name(con))
+                               printk(KERN_WARNING
+                                      "failed to install console=%s\n", con);
+                       con = p + 1;
+               }
+               ++p;
+       }
+
+       // Catch the last one
+       if (p != console_str)
+               driver_init_by_name(con);
+}
+
diff --git a/kitten/kernel/cpuinfo.c b/kitten/kernel/cpuinfo.c
new file mode 100644 (file)
index 0000000..fe775a1
--- /dev/null
@@ -0,0 +1,31 @@
+#include <lwk/kernel.h>
+#include <lwk/cpuinfo.h>
+
+/**
+ * Info structure for each CPU in the system.
+ * Array is indexed by logical CPU ID.
+ */
+struct cpuinfo cpu_info[NR_CPUS];
+
+/**
+ * Map of all available CPUs.
+ * This map represents logical CPU IDs.
+ */
+cpumask_t cpu_present_map;
+
+/**
+ * Map of all booted CPUs.
+ * This map represents logical CPU IDs.
+ * It will be a subset of cpu_present_map (usually identical after boot).
+ */
+cpumask_t cpu_online_map;
+
+/**
+ * Prints the input cpuinfo structure to the console.
+ */
+void print_cpuinfo(struct cpuinfo *c)
+{
+       printk("logical cpu id\t: %u\n", c->logical_id);
+       print_arch_cpuinfo(c);
+}
+
diff --git a/kitten/kernel/driver.c b/kitten/kernel/driver.c
new file mode 100644 (file)
index 0000000..a1c53e8
--- /dev/null
@@ -0,0 +1,27 @@
+#include <lwk/driver.h>
+#include <lwk/string.h>
+
+/**
+ * Searches for the specified driver name and calls its init() function.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int driver_init_by_name(const char *name)
+{
+       unsigned int i;
+       struct driver_info * drvs       =       __start___driver_table;
+       unsigned int         num_drvs   =       __stop___driver_table
+                                                 - __start___driver_table;
+
+       for (i = 0; i < num_drvs; i++) {
+               if (strcmp(name, drvs[i].name) == 0) {
+                       if (drvs[i].init_called)
+                               return -1;
+                       drvs[i].init_called = 1;
+                       drvs[i].init();
+                       return 0;
+               }
+       }
+       return -1;
+}
+
diff --git a/kitten/kernel/elf.c b/kitten/kernel/elf.c
new file mode 100644 (file)
index 0000000..99e57ac
--- /dev/null
@@ -0,0 +1,28 @@
+#include <lwk/kernel.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/elf.h>
+#include <arch/uaccess.h>
+
+int
+elf_hwcap(id_t cpu, uint32_t *hwcap)
+{
+       if (!cpu_isset(cpu, cpu_online_map))
+               return -ENOENT;
+       *hwcap = ELF_HWCAP(cpu);
+       return 0;
+}
+
+int
+sys_elf_hwcap(id_t cpu, uint32_t __user *hwcap)
+{
+       int status;
+       uint32_t _hwcap;
+       
+       if ((status = elf_hwcap(cpu, &_hwcap)) != 0)
+               return status;
+
+       if (hwcap && copy_to_user(hwcap, &_hwcap, sizeof(_hwcap)))
+               return -EINVAL;
+
+       return 0;
+}
diff --git a/kitten/kernel/elf_liblwk.c b/kitten/kernel/elf_liblwk.c
new file mode 120000 (symlink)
index 0000000..0918860
--- /dev/null
@@ -0,0 +1 @@
+../user/liblwk/elf.c
\ No newline at end of file
diff --git a/kitten/kernel/extable.c b/kitten/kernel/extable.c
new file mode 100644 (file)
index 0000000..53bf98a
--- /dev/null
@@ -0,0 +1,65 @@
+/* Rewritten by Rusty Russell, on the backs of many others...
+   Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
+
+    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.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include <lwk/init.h>
+#include <lwk/extable.h>
+#include <arch/uaccess.h>
+#include <arch/sections.h>
+
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/* Sort the kernel's built-in exception table */
+void __init sort_exception_table(void)
+{
+       sort_extable(__start___ex_table, __stop___ex_table);
+}
+
+/* Given an address, look for it in the exception table. */
+const struct exception_table_entry *search_exception_table(unsigned long addr)
+{
+       const struct exception_table_entry *e;
+
+       e = search_extable(__start___ex_table, __stop___ex_table-1, addr);
+       return e;
+}
+
+int core_kernel_text(unsigned long addr)
+{
+       if (addr >= (unsigned long)_stext &&
+           addr <= (unsigned long)_etext)
+               return 1;
+
+       if (addr >= (unsigned long)_sinittext &&
+           addr <= (unsigned long)_einittext)
+               return 1;
+       return 0;
+}
+
+int __kernel_text_address(unsigned long addr)
+{
+       if (core_kernel_text(addr))
+               return 1;
+       return 0;
+}
+
+int kernel_text_address(unsigned long addr)
+{
+       if (core_kernel_text(addr))
+               return 1;
+       return 0;
+}
diff --git a/kitten/kernel/htable.c b/kitten/kernel/htable.c
new file mode 100644 (file)
index 0000000..7820060
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/list.h>
+#include <lwk/htable.h>
+#include <lwk/hash.h>
+
+struct htable {
+       size_t              tbl_order;
+       struct hlist_head * tbl;
+       size_t              obj_key_offset;
+       size_t              obj_link_offset;
+       size_t              num_entries;
+};
+
+static id_t
+obj2key(const struct htable *ht, const void *obj)
+{
+       return *((id_t *)((uintptr_t)obj + ht->obj_key_offset));
+}
+
+static struct hlist_node *
+obj2node(const struct htable *ht, const void *obj)
+{
+       return (struct hlist_node *)((uintptr_t)obj + ht->obj_link_offset);
+}
+
+static void *
+node2obj(const struct htable *ht, const struct hlist_node *node)
+{
+       return (void *)((uintptr_t)node - ht->obj_link_offset);
+}
+
+static id_t
+node2key(const struct htable *ht, const struct hlist_node *node)
+{
+       return obj2key(ht, node2obj(ht, node));
+}
+
+static struct hlist_head *
+key2head(const struct htable *ht, id_t key)
+{
+       return &ht->tbl[hash_long(key, ht->tbl_order)];
+}
+
+static struct hlist_head *
+obj2head(const struct htable *ht, const void *obj)
+{
+       return &ht->tbl[hash_long(obj2key(ht, obj), ht->tbl_order)];
+}
+
+int
+htable_create(size_t tbl_order,
+              size_t obj_key_offset, size_t obj_link_offset, htable_t *tbl)
+{
+       struct htable *ht;
+       size_t tbl_size;
+
+       if (!(ht = kmem_alloc(sizeof(*ht))))
+               return -ENOMEM;
+
+       ht->tbl_order = tbl_order;
+       tbl_size = (1 << tbl_order);
+
+       if (!(ht->tbl = kmem_alloc(tbl_size * sizeof(struct hlist_head))))
+               return -ENOMEM;
+
+       ht->obj_key_offset  = obj_key_offset;
+       ht->obj_link_offset = obj_link_offset;
+       ht->num_entries     = 0;
+
+       *tbl = ht;
+       return 0;
+}
+
+int
+htable_destroy(htable_t tbl)
+{
+       struct htable *ht = tbl;
+       if (ht->num_entries)
+               return -EEXIST;
+       kmem_free(ht->tbl);
+       kmem_free(ht);
+       return 0;
+}
+
+int
+htable_add(htable_t tbl, void *obj)
+{
+       struct htable *ht = tbl;
+       hlist_add_head(obj2node(ht, obj), obj2head(ht, obj));
+       ++ht->num_entries;
+       return 0;
+}
+
+int
+htable_del(htable_t tbl, void *obj)
+{
+       struct htable *ht = tbl;
+       struct hlist_node *node;
+       hlist_for_each(node, obj2head(ht, obj)) {
+               if (obj == node2obj(ht, node)) {
+                       hlist_del(node);
+                       --ht->num_entries;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+void *
+htable_lookup(htable_t tbl, id_t key)
+{
+       struct htable *ht = tbl;
+       struct hlist_node *node;
+       hlist_for_each(node, key2head(ht, key)) {
+               if (key == node2key(ht, node))
+                       return node2obj(ht, node);
+       }
+       return NULL;
+}
diff --git a/kitten/kernel/idspace.c b/kitten/kernel/idspace.c
new file mode 100644 (file)
index 0000000..92b57b3
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/idspace.h>
+#include <lwk/log2.h>
+#include <arch/page.h>
+
+struct idspace {
+       id_t   min_id;
+       id_t   max_id;
+       size_t size;
+       size_t ids_in_use;
+       size_t offset;
+       void * bitmap;
+};
+
+static size_t
+calc_order(struct idspace *idspace)
+{
+       size_t pages = DIV_ROUND_UP(idspace->size, PAGE_SIZE * 8);
+       return roundup_pow_of_two(pages);
+}
+
+int
+idspace_create(id_t min_id, id_t max_id, idspace_t *idspace)
+{
+       struct idspace *spc;
+
+       if ((min_id == ANY_ID) || (max_id == ANY_ID))
+               return -EINVAL;
+
+       if (min_id > max_id)
+               return -EINVAL;
+
+       if (!idspace)
+               return -EINVAL;
+
+       if (!(spc = kmem_alloc(sizeof(*spc))))
+               return -ENOMEM;
+
+       spc->min_id     = min_id;
+       spc->max_id     = max_id;
+       spc->size       = max_id - min_id + 1;
+       spc->ids_in_use = 0;
+       spc->offset     = 0;
+
+       if (!(spc->bitmap = kmem_get_pages(calc_order(spc)))) {
+               kmem_free(spc);
+               return -ENOMEM;
+       }
+
+       *idspace = spc;
+
+       return 0;
+}
+
+int
+idspace_destroy(idspace_t idspace)
+{
+       struct idspace *spc = idspace;
+
+       if (!spc)
+               return -EINVAL;
+
+       kmem_free_pages(spc->bitmap, calc_order(spc));
+       kmem_free(spc);
+
+       return 0;
+}
+
+int
+idspace_alloc_id(idspace_t idspace, id_t request, id_t *id)
+{
+       struct idspace *spc = idspace;
+       unsigned int bit;
+
+       if (!spc)
+               return -EINVAL;
+
+       if ((request != ANY_ID) &&
+           ((request < spc->min_id) || (request > spc->max_id)))
+               return -EINVAL;
+
+       if (spc->size == spc->ids_in_use)
+               return -ENOENT;
+
+       if (request == ANY_ID) {
+               /* Allocate any available id */
+               bit = find_next_zero_bit(spc->bitmap, spc->size, spc->offset);
+               /* Handle wrap-around */
+               if (bit == spc->size)
+                       bit = find_next_zero_bit(spc->bitmap, spc->offset, 0);
+               /* Next time start looking at the next id */
+               spc->offset = bit + 1;
+               if (spc->offset == spc->size)
+                       spc->offset = 0;
+       } else {
+               /* Allocate a specific ID */
+               bit = request - spc->min_id;
+       }
+
+       if (test_and_set_bit(bit, spc->bitmap))
+               return -EBUSY;
+
+       ++spc->ids_in_use;
+       if (id)
+               *id = bit + spc->min_id;
+
+       return 0;
+}
+
+int
+idspace_free_id(idspace_t idspace, id_t id)
+{
+       struct idspace *spc = idspace;
+       unsigned int bit;
+
+       if (!spc)
+               return -EINVAL;
+
+       if ((id == ANY_ID) || (id < spc->min_id) || (id > spc->max_id))
+               return -EINVAL;
+
+       bit = id - spc->min_id;
+       if (test_and_clear_bit(bit, spc->bitmap) == 0)
+               return -ENOENT;
+
+       --spc->ids_in_use;
+
+       return 0;
+}
diff --git a/kitten/kernel/init_task.c b/kitten/kernel/init_task.c
new file mode 100644 (file)
index 0000000..b8913ae
--- /dev/null
@@ -0,0 +1,94 @@
+#include <lwk/kernel.h>
+#include <lwk/smp.h>
+#include <lwk/params.h>
+#include <lwk/init.h>
+#include <lwk/elf.h>
+
+/**
+ * Maximum number of arguments and environment variables that may
+ * be passed to the init_task.
+ */
+#define INIT_MAX_ARGC 32
+#define INIT_MAX_ENVC 32
+
+/**
+ * Maximum length of the init_argv= and init_envp= strings on the
+ * kernel boot command line.
+ */
+#define INIT_ARGV_LEN 1024
+#define INIT_ENVP_LEN 1024
+
+/**
+ * Amount of memory to reserve for the init_task's heap.
+ */
+unsigned long init_heap_size = (1024 * 1024 * 4);  /* 4 MB */
+param(init_heap_size, ulong);
+
+/**
+ * Amount of memory to reserve for the init_task's stack.
+ */
+unsigned long init_stack_size = (1024 * 256);  /* 256 KB */
+param(init_stack_size, ulong);
+
+/**
+ * Arguments to pass to the init_task.
+ */
+static char init_argv_str[INIT_ARGV_LEN] = { 0 };
+param_string(init_argv, init_argv_str, sizeof(init_argv_str));
+
+/**
+ * Environment to pass to the init_task.
+ */
+static char init_envp_str[INIT_ENVP_LEN] = { 0 };
+param_string(init_envp, init_envp_str, sizeof(init_envp_str));
+
+/**
+ * Creates the init_task.
+ */
+int
+create_init_task(void)
+{
+       int status;
+       start_state_t start_state;
+
+       if (!init_elf_image) {
+               printk("No init_elf_image found.\n");
+               return -EINVAL;
+       }
+       
+       /* Initialize the start_state fields that we know up-front */
+       start_state.uid     = 0;
+       start_state.gid     = 0;
+       start_state.cpu_id  = this_cpu;
+       start_state.cpumask = NULL;
+
+       /* This initializes start_state aspace_id, entry_point, and stack_ptr */
+       status =
+       elf_load(
+               __va(init_elf_image),
+               init_elf_image,
+               "init_task",
+               INIT_ASPACE_ID,
+               PAGE_SIZE,
+               init_heap_size,
+               init_stack_size,
+               init_argv_str,
+               init_envp_str,
+               &start_state,
+               0,
+               &elf_dflt_alloc_pmem
+       );
+       if (status) {
+               printk("Failed to load init_task (status=%d).\n", status);
+               return status;
+       }
+
+       /* This prevents the address space from being deleted by
+        * user-space, since the kernel never releases this reference */
+       if (!aspace_acquire(INIT_ASPACE_ID)) {
+               printk("Failed to acquire INIT_ASPACE_ID.\n");
+               return status;
+       }
+
+       return task_create(INIT_TASK_ID, "init_task", &start_state, NULL);
+}
diff --git a/kitten/kernel/kallsyms.c b/kitten/kernel/kallsyms.c
new file mode 100644 (file)
index 0000000..97860b1
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
+ *
+ * Rewritten and vastly simplified by Rusty Russell for in-kernel
+ * module loader:
+ *   Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * ChangeLog:
+ *
+ * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
+ *      Changed the compression method from stem compression to "table lookup"
+ *      compression (see scripts/kallsyms.c for a more complete description)
+ */
+#include <lwk/kernel.h>
+#include <lwk/kallsyms.h>
+#include <lwk/init.h>
+#include <lwk/string.h>
+#include <arch/sections.h>
+
+#ifdef CONFIG_KALLSYMS_ALL
+#define all_var 1
+#else
+#define all_var 0
+#endif
+
+/**
+ * These will be re-linked against their
+ * real values during the second link stage
+ */
+extern unsigned long kallsyms_addresses[] __attribute__((weak));
+extern unsigned long kallsyms_num_syms __attribute__((weak,section("data")));
+extern u8 kallsyms_names[] __attribute__((weak));
+
+extern u8 kallsyms_token_table[] __attribute__((weak));
+extern u16 kallsyms_token_index[] __attribute__((weak));
+
+extern unsigned long kallsyms_markers[] __attribute__((weak));
+
+static inline int is_kernel_inittext(unsigned long addr)
+{
+       if (addr >= (unsigned long)_sinittext
+           && addr <= (unsigned long)_einittext)
+               return 1;
+       return 0;
+}
+
+static inline int is_kernel_extratext(unsigned long addr)
+{
+       if (addr >= (unsigned long)_sextratext
+           && addr <= (unsigned long)_eextratext)
+               return 1;
+       return 0;
+}
+
+static inline int is_kernel_text(unsigned long addr)
+{
+       if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
+               return 1;
+       return 0;
+}
+
+static inline int is_kernel(unsigned long addr)
+{
+       if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
+               return 1;
+       return 0;
+}
+
+/**
+ * Expand a compressed symbol data into the resulting uncompressed string,
+ * given the offset to where the symbol is in the compressed stream.
+ */
+static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
+{
+       int len, skipped_first = 0;
+       u8 *tptr, *data;
+
+       /* get the compressed symbol length from the first symbol byte */
+       data = &kallsyms_names[off];
+       len = *data;
+       data++;
+
+       /* update the offset to return the offset for the next symbol on
+        * the compressed stream */
+       off += len + 1;
+
+       /* for every byte on the compressed symbol data, copy the table
+          entry for that byte */
+       while(len) {
+               tptr = &kallsyms_token_table[ kallsyms_token_index[*data] ];
+               data++;
+               len--;
+
+               while (*tptr) {
+                       if(skipped_first) {
+                               *result = *tptr;
+                               result++;
+                       } else
+                               skipped_first = 1;
+                       tptr++;
+               }
+       }
+
+       *result = '\0';
+
+       /* return to offset to the next symbol */
+       return off;
+}
+
+/**
+ * Find the offset on the compressed stream given and index in the
+ * kallsyms array.
+ */
+static unsigned int get_symbol_offset(unsigned long pos)
+{
+       u8 *name;
+       int i;
+
+       /* use the closest marker we have. We have markers every 256 positions,
+        * so that should be close enough */
+       name = &kallsyms_names[ kallsyms_markers[pos>>8] ];
+
+       /* sequentially scan all the symbols up to the point we're searching
+        * for. Every symbol is stored in a [<len>][<len> bytes of data]
+        * format, so we just need to add the len to the current pointer for
+        * every symbol we wish to skip */
+       for(i = 0; i < (pos&0xFF); i++)
+               name = name + (*name) + 1;
+
+       return name - kallsyms_names;
+}
+
+/**
+ *  Lookup the address for this symbol. Returns 0 if not found.
+ */
+unsigned long kallsyms_lookup_name(const char *name)
+{
+       char namebuf[KSYM_NAME_LEN+1];
+       unsigned long i;
+       unsigned int off;
+
+       for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
+               off = kallsyms_expand_symbol(off, namebuf);
+
+               if (strcmp(namebuf, name) == 0)
+                       return kallsyms_addresses[i];
+       }
+       return 0;
+}
+
+/**
+ * Lookup the symbol name corresponding to a kernel address
+ */
+const char *kallsyms_lookup(unsigned long addr,
+                           unsigned long *symbolsize,
+                           unsigned long *offset,
+                           char *namebuf)
+{
+       unsigned long i, low, high, mid;
+
+       /* This kernel should never had been booted. */
+       BUG_ON(!kallsyms_addresses);
+
+       namebuf[KSYM_NAME_LEN] = 0;
+       namebuf[0] = 0;
+
+       if ((all_var && is_kernel(addr)) ||
+           (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
+                               is_kernel_extratext(addr)))) {
+               unsigned long symbol_end = 0;
+
+               /* do a binary search on the sorted kallsyms_addresses array */
+               low = 0;
+               high = kallsyms_num_syms;
+
+               while (high-low > 1) {
+                       mid = (low + high) / 2;
+                       if (kallsyms_addresses[mid] <= addr) low = mid;
+                       else high = mid;
+               }
+
+               /* search for the first aliased symbol. Aliased symbols are
+                  symbols with the same address */
+               while (low && kallsyms_addresses[low - 1] ==
+                               kallsyms_addresses[low])
+                       --low;
+
+               /* Grab name */
+               kallsyms_expand_symbol(get_symbol_offset(low), namebuf);
+
+               /* Search for next non-aliased symbol */
+               for (i = low + 1; i < kallsyms_num_syms; i++) {
+                       if (kallsyms_addresses[i] > kallsyms_addresses[low]) {
+                               symbol_end = kallsyms_addresses[i];
+                               break;
+                       }
+               }
+
+               /* if we found no next symbol, we use the end of the section */
+               if (!symbol_end) {
+                       if (is_kernel_inittext(addr))
+                               symbol_end = (unsigned long)_einittext;
+                       else
+                               symbol_end = (all_var) ? (unsigned long)_end
+                                                      : (unsigned long)_etext;
+               }
+
+               if (symbolsize)
+                       *symbolsize = symbol_end - kallsyms_addresses[low];
+               if (offset)
+                       *offset = addr - kallsyms_addresses[low];
+               return namebuf;
+       }
+
+       return NULL;
+}
+
diff --git a/kitten/kernel/linux_syscalls/Makefile b/kitten/kernel/linux_syscalls/Makefile
new file mode 100644 (file)
index 0000000..fc1f0f6
--- /dev/null
@@ -0,0 +1,3 @@
+obj-y := uname.o brk.o write.o id.o fstat.o mmap.o \
+               gettimeofday.o settimeofday.o nanosleep.o sched_yield.o \
+               time.o
diff --git a/kitten/kernel/linux_syscalls/brk.c b/kitten/kernel/linux_syscalls/brk.c
new file mode 100644 (file)
index 0000000..304b4ea
--- /dev/null
@@ -0,0 +1,15 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+#include <lwk/aspace.h>
+
+unsigned long
+sys_brk(unsigned long brk)
+{
+       struct aspace *as = current->aspace;
+
+       if ((brk >= as->heap_start) && (brk < as->mmap_brk))
+               as->brk = brk;
+
+       return as->brk;
+}
+
diff --git a/kitten/kernel/linux_syscalls/fstat.c b/kitten/kernel/linux_syscalls/fstat.c
new file mode 100644 (file)
index 0000000..9a6301c
--- /dev/null
@@ -0,0 +1,31 @@
+#include <lwk/kernel.h>
+#include <lwk/stat.h>
+#include <arch/uaccess.h>
+
+long
+sys_fstat(unsigned int fd, struct stat __user *statbuf)
+{
+       struct stat tmp;
+
+       /* For now only allow stat()'ing stdio */
+       if (fd != 1)
+               return -EBADF;
+
+       /* TODO: Fix this! */
+       tmp.st_dev     = 11;
+       tmp.st_ino     = 9;
+       tmp.st_mode    = 0x2190;
+       tmp.st_nlink   = 1;
+       tmp.st_uid     = 0;
+       tmp.st_gid     = 0;
+       tmp.st_rdev    = 34823;
+       tmp.st_size    = 0;
+       tmp.st_blksize = 1024;
+       tmp.st_blocks  = 0;
+       tmp.st_atime   = 1204772189;
+       tmp.st_mtime   = 1204772189;
+       tmp.st_ctime   = 1204769465;
+       
+       return copy_to_user(statbuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
diff --git a/kitten/kernel/linux_syscalls/gettimeofday.c b/kitten/kernel/linux_syscalls/gettimeofday.c
new file mode 100644 (file)
index 0000000..064c003
--- /dev/null
@@ -0,0 +1,34 @@
+#include <lwk/kernel.h>
+#include <lwk/time.h>
+#include <arch/uaccess.h>
+
+int
+sys_gettimeofday(
+       struct timeval  __user * tv,
+       struct timezone __user * tz
+)
+{
+       struct timeval  _tv;
+       struct timezone _tz;
+
+       if (tv != NULL) {
+               uint64_t now = get_time(); /* nanoseconds */
+
+               _tv.tv_sec  = now / NSEC_PER_SEC;
+               _tv.tv_usec = (now % NSEC_PER_SEC) / USEC_PER_NSEC;
+
+               if (copy_to_user(tv, &_tv, sizeof(_tv)))
+                       return -EFAULT;
+       }
+
+       if (tz != NULL) {
+               _tz.tz_minuteswest = 0;
+               _tz.tz_dsttime     = 0;
+
+               if (copy_to_user(tz, &_tz, sizeof(_tz)))
+                       return -EFAULT;
+       }
+       
+       return 0;
+}
+
diff --git a/kitten/kernel/linux_syscalls/id.c b/kitten/kernel/linux_syscalls/id.c
new file mode 100644 (file)
index 0000000..01d7a6c
--- /dev/null
@@ -0,0 +1,15 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+
+long
+sys_getuid(void)
+{
+       return current->uid;
+}
+
+long
+sys_getgid(void)
+{
+       return current->gid;
+}
+
diff --git a/kitten/kernel/linux_syscalls/mmap.c b/kitten/kernel/linux_syscalls/mmap.c
new file mode 100644 (file)
index 0000000..b8ca8c3
--- /dev/null
@@ -0,0 +1,35 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+#include <lwk/aspace.h>
+#include <arch/mman.h>
+
+long
+sys_mmap(
+       unsigned long addr,
+       unsigned long len,
+       unsigned long prot,
+       unsigned long flags,
+       unsigned long fd,
+       unsigned long off
+)
+{
+       unsigned long mmap_brk;
+
+       /* For now we only support private/anonymous mappings */
+       if (!(flags & MAP_PRIVATE) || !(flags & MAP_ANONYMOUS))
+               return -EINVAL;
+
+       if (len != round_up(len, PAGE_SIZE))
+               return -EINVAL;
+
+       mmap_brk = current->aspace->mmap_brk;
+       mmap_brk = round_down(mmap_brk - len, PAGE_SIZE);
+
+       /* Protect against extending into the UNIX data segment */
+       if (mmap_brk <= current->aspace->brk)
+               return -ENOMEM;
+
+       current->aspace->mmap_brk = mmap_brk;
+       return mmap_brk;
+}
+
diff --git a/kitten/kernel/linux_syscalls/nanosleep.c b/kitten/kernel/linux_syscalls/nanosleep.c
new file mode 100644 (file)
index 0000000..39c7a83
--- /dev/null
@@ -0,0 +1,30 @@
+#include <lwk/kernel.h>
+#include <lwk/time.h>
+#include <lwk/timer.h>
+#include <arch/uaccess.h>
+
+int
+sys_nanosleep(const struct timespec __user *req, struct timespec __user *rem)
+{
+       struct timespec _req, _rem;
+       uint64_t when, remain;
+
+       if (copy_from_user(&_req, req, sizeof(_req)))
+               return -EFAULT;
+
+       if (!timespec_is_valid(&_req))
+               return -EINVAL;
+
+       when = get_time() + (_req.tv_sec * NSEC_PER_SEC) + _req.tv_nsec;
+       remain = timer_sleep_until(when);
+
+       if (remain && rem) {
+               _rem.tv_sec  = remain / NSEC_PER_SEC;
+               _rem.tv_nsec = remain % NSEC_PER_SEC;
+
+               if (copy_to_user(rem, &_rem, sizeof(_rem)))
+                       return -EFAULT;
+       }
+
+       return (remain) ? -ERESTART_RESTARTBLOCK : 0;
+}
diff --git a/kitten/kernel/linux_syscalls/sched_yield.c b/kitten/kernel/linux_syscalls/sched_yield.c
new file mode 100644 (file)
index 0000000..651fbe3
--- /dev/null
@@ -0,0 +1,8 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+
+int
+sys_sched_yield(void)
+{
+       return task_yield();
+}
diff --git a/kitten/kernel/linux_syscalls/settimeofday.c b/kitten/kernel/linux_syscalls/settimeofday.c
new file mode 100644 (file)
index 0000000..748e059
--- /dev/null
@@ -0,0 +1,34 @@
+#include <lwk/kernel.h>
+#include <lwk/time.h>
+#include <arch/uaccess.h>
+
+int
+sys_settimeofday(
+       struct timeval  __user * tv,
+       struct timezone __user * tz
+)
+{
+       struct timeval  _tv;
+       struct timezone _tz;
+
+       if (tv != NULL) {
+               if (copy_from_user(&_tv, tv, sizeof(_tv)))
+                       return -EFAULT;
+
+               set_time(
+                 (_tv.tv_sec * NSEC_PER_SEC) + (_tv.tv_usec * NSEC_PER_USEC)
+               );
+       }
+
+       if (tz != NULL) {
+               if (copy_from_user(&_tz, tz, sizeof(_tz)))
+                       return -EFAULT;
+
+               /* Only support setting timezone to 0 */
+               if ((_tz.tz_minuteswest != 0) || (_tz.tz_dsttime != 0))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
diff --git a/kitten/kernel/linux_syscalls/time.c b/kitten/kernel/linux_syscalls/time.c
new file mode 100644 (file)
index 0000000..fca2d04
--- /dev/null
@@ -0,0 +1,14 @@
+#include <lwk/kernel.h>
+#include <lwk/time.h>
+#include <arch/uaccess.h>
+
+time_t
+sys_time(time_t __user *t)
+{
+       time_t now_sec = (time_t)(get_time() / NSEC_PER_SEC);
+
+       if (t && copy_to_user(t, &now_sec, sizeof(now_sec)))
+               return -EFAULT;
+
+       return now_sec;
+}
diff --git a/kitten/kernel/linux_syscalls/uname.c b/kitten/kernel/linux_syscalls/uname.c
new file mode 100644 (file)
index 0000000..4ea1496
--- /dev/null
@@ -0,0 +1,10 @@
+#include <lwk/kernel.h>
+#include <arch/uaccess.h>
+
+long
+sys_uname(struct utsname __user *name)
+{
+       int err = copy_to_user(name, &linux_utsname, sizeof(*name));
+       return err ? -EFAULT : 0;
+}
+
diff --git a/kitten/kernel/linux_syscalls/write.c b/kitten/kernel/linux_syscalls/write.c
new file mode 100644 (file)
index 0000000..b37bee5
--- /dev/null
@@ -0,0 +1,35 @@
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+#include <arch/uaccess.h>
+
+ssize_t
+sys_write(unsigned int fd, const char __user * buf, size_t count)
+{
+       char    kbuf[512];
+       size_t  kcount = count;
+
+       /* For now we only support stdout console output */
+       if (fd != 1)
+               return -EBADF;
+
+       /* Protect against overflowing the kernel buffer */
+       if (kcount >= sizeof(kbuf))
+               kcount = sizeof(kbuf) - 1;
+
+       /* Copy the user-level string to a kernel buffer */
+       if (copy_from_user(kbuf, buf, kcount))
+               return -EFAULT;
+       kbuf[kcount] = '\0';
+
+       /* Write the string to the local console */
+       printk(KERN_USERMSG
+               "(%s) %s%s",
+               current->name,
+               kbuf,
+               (kcount != count) ? " <TRUNCATED>" : ""
+       );
+
+       /* Return number of characters actually printed */
+       return kcount;
+}
+
diff --git a/kitten/kernel/panic.c b/kitten/kernel/panic.c
new file mode 100644 (file)
index 0000000..8d8cad6
--- /dev/null
@@ -0,0 +1,17 @@
+#include <lwk/kernel.h>
+
+/**
+ * Scream and die.
+ */
+void panic(const char * fmt, ...)
+{
+        static char buf[1024];
+        va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+       printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
+
+       while (1) {}
+}
diff --git a/kitten/kernel/params.c b/kitten/kernel/params.c
new file mode 100644 (file)
index 0000000..b513601
--- /dev/null
@@ -0,0 +1,397 @@
+/* Helpers for initial module or kernel cmdline parsing
+   Copyright (C) 2001 Rusty Russell.
+
+    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.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include <lwk/kernel.h>
+#include <lwk/string.h>
+#include <lwk/errno.h>
+#include <lwk/params.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt, a...)
+#endif
+
+static inline char dash2underscore(char c)
+{
+       if (c == '-')
+               return '_';
+       return c;
+}
+
+static inline int parameq(const char *input, const char *paramname)
+{
+       unsigned int i;
+       for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
+               if (input[i] == '\0')
+                       return 1;
+       return 0;
+}
+
+static int parse_one(char *param,
+                    char *val,
+                    struct kernel_param *params, 
+                    unsigned num_params,
+                    int (*handle_unknown)(char *param, char *val))
+{
+       unsigned int i;
+printk("in parse_one(%s, %s)\n", param, val);
+
+       /* Find parameter */
+       for (i = 0; i < num_params; i++) {
+               if (parameq(param, params[i].name)) {
+                       DEBUGP("They are equal!  Calling %p\n",
+                              params[i].set);
+                       return params[i].set(val, &params[i]);
+               }
+       }
+
+       if (handle_unknown) {
+               DEBUGP("Unknown argument: calling %p\n", handle_unknown);
+               return handle_unknown(param, val);
+       }
+
+       /* Ignore unknown args if no handle_unknown function specified */
+       printk("Unknown argument `%s'\n", param);
+       return 0;
+}
+
+/* You can use " around spaces, but can't escape ". */
+/* Hyphens and underscores equivalent in parameter names. */
+static char *next_arg(char *args, char **param, char **val)
+{
+       unsigned int i, equals = 0;
+       int in_quote = 0, quoted = 0;
+       char *next;
+
+       if (*args == '"') {
+               args++;
+               in_quote = 1;
+               quoted = 1;
+       }
+
+       for (i = 0; args[i]; i++) {
+               if (args[i] == ' ' && !in_quote)
+                       break;
+               if (equals == 0) {
+                       if (args[i] == '=')
+                               equals = i;
+               }
+               if (args[i] == '"')
+                       in_quote = !in_quote;
+       }
+
+       *param = args;
+       if (!equals)
+               *val = NULL;
+       else {
+               args[equals] = '\0';
+               *val = args + equals + 1;
+
+               /* Don't include quotes in value. */
+               if (**val == '"') {
+                       (*val)++;
+                       if (args[i-1] == '"')
+                               args[i-1] = '\0';
+               }
+               if (quoted && args[i-1] == '"')
+                       args[i-1] = '\0';
+       }
+
+       if (args[i]) {
+               args[i] = '\0';
+               next = args + i + 1;
+       } else
+               next = args + i;
+
+       /* Chew up trailing spaces. */
+       while (*next == ' ')
+               next++;
+       return next;
+}
+
+/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
+int parse_args(const char *name,
+              char *args,
+              struct kernel_param *params,
+              unsigned num,
+              int (*unknown)(char *param, char *val))
+{
+       char *param, *val;
+
+       DEBUGP("Parsing ARGS: %s\n", args);
+
+       /* Chew leading spaces */
+       while (*args == ' ')
+               args++;
+
+       while (*args) {
+               int ret;
+
+               args = next_arg(args, &param, &val);
+               ret = parse_one(param, val, params, num, unknown);
+               switch (ret) {
+               case -ENOENT:
+                       printk(KERN_ERR "%s: Unknown parameter `%s'\n",
+                              name, param);
+                       return ret;
+               case -ENOSPC:
+                       printk(KERN_ERR
+                              "%s: `%s' too large for parameter `%s'\n",
+                              name, val ?: "", param);
+                       return ret;
+               case 0:
+                       break;
+               default:
+                       printk(KERN_ERR
+                              "%s: `%s' invalid for parameter `%s'\n",
+                              name, val ?: "", param);
+                       return ret;
+               }
+       }
+
+       /* All parsed OK. */
+       return 0;
+}
+
+/* Lazy bastard, eh? */
+#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)              \
+       int param_set_##name(const char *val, struct kernel_param *kp)  \
+       {                                                               \
+               char *endp;                                             \
+               tmptype l;                                              \
+                                                                       \
+               if (!val) return -EINVAL;                               \
+               l = strtolfn(val, &endp, 0);                            \
+               if (endp == val || ((type)l != l))                      \
+                       return -EINVAL;                                 \
+               *((type *)kp->arg) = l;                                 \
+               return 0;                                               \
+       }                                                               \
+       int param_get_##name(char *buffer, struct kernel_param *kp)     \
+       {                                                               \
+               return sprintf(buffer, format, *((type *)kp->arg));     \
+       }
+
+STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, simple_strtoul);
+STANDARD_PARAM_DEF(short, short, "%hi", long, simple_strtol);
+STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, simple_strtoul);
+STANDARD_PARAM_DEF(int, int, "%i", long, simple_strtol);
+STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, simple_strtoul);
+STANDARD_PARAM_DEF(long, long, "%li", long, simple_strtol);
+STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, simple_strtoul);
+
+int param_set_charp(const char *val, struct kernel_param *kp)
+{
+       if (!val) {
+               printk(KERN_ERR "%s: string parameter expected\n",
+                      kp->name);
+               return -EINVAL;
+       }
+
+       if (strlen(val) > 1024) {
+               printk(KERN_ERR "%s: string parameter too long\n",
+                      kp->name);
+               return -ENOSPC;
+       }
+
+       *(char **)kp->arg = (char *)val;
+       return 0;
+}
+
+int param_get_charp(char *buffer, struct kernel_param *kp)
+{
+       return sprintf(buffer, "%s", *((char **)kp->arg));
+}
+
+int param_set_bool(const char *val, struct kernel_param *kp)
+{
+       /* No equals means "set"... */
+       if (!val) val = "1";
+
+       /* One of =[yYnN01] */
+       switch (val[0]) {
+       case 'y': case 'Y': case '1':
+               *(int *)kp->arg = 1;
+               return 0;
+       case 'n': case 'N': case '0':
+               *(int *)kp->arg = 0;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+int param_get_bool(char *buffer, struct kernel_param *kp)
+{
+       /* Y and N chosen as being relatively non-coder friendly */
+       return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N');
+}
+
+int param_set_invbool(const char *val, struct kernel_param *kp)
+{
+       int boolval, ret;
+       struct kernel_param dummy = { .arg = &boolval };
+
+       ret = param_set_bool(val, &dummy);
+       if (ret == 0)
+               *(int *)kp->arg = !boolval;
+       return ret;
+}
+
+int param_get_invbool(char *buffer, struct kernel_param *kp)
+{
+       int val;
+       struct kernel_param dummy = { .arg = &val };
+
+       val = !*(int *)kp->arg;
+       return param_get_bool(buffer, &dummy);
+}
+
+/* We cheat here and temporarily mangle the string. */
+static int _param_array(const char *name,
+                      const char *val,
+                      unsigned int min, unsigned int max,
+                      void *elem, int elemsize,
+                      int (*set)(const char *, struct kernel_param *kp),
+                      int *num)
+{
+       int ret;
+       struct kernel_param kp;
+       char save;
+
+       /* Get the name right for errors. */
+       kp.name = name;
+       kp.arg = elem;
+
+       /* No equals sign? */
+       if (!val) {
+               printk(KERN_ERR "%s: expects arguments\n", name);
+               return -EINVAL;
+       }
+
+       *num = 0;
+       /* We expect a comma-separated list of values. */
+       do {
+               int len;
+
+               if (*num == max) {
+                       printk(KERN_ERR "%s: can only take %i arguments\n",
+                              name, max);
+                       return -EINVAL;
+               }
+               len = strcspn(val, ",");
+
+               /* nul-terminate and parse */
+               save = val[len];
+               ((char *)val)[len] = '\0';
+               ret = set(val, &kp);
+
+               if (ret != 0)
+                       return ret;
+               kp.arg += elemsize;
+               val += len+1;
+               (*num)++;
+       } while (save == ',');
+
+       if (*num < min) {
+               printk(KERN_ERR "%s: needs at least %i arguments\n",
+                      name, min);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int param_array_set(const char *val, struct kernel_param *kp)
+{
+       struct kparam_array *arr = kp->arg;
+       unsigned int temp_num;
+
+       return _param_array(kp->name, val, 1, arr->max, arr->elem,
+                          arr->elemsize, arr->set, arr->num ?: &temp_num);
+}
+
+int param_array_get(char *buffer, struct kernel_param *kp)
+{
+       int i, off, ret;
+       struct kparam_array *arr = kp->arg;
+       struct kernel_param p;
+
+       p = *kp;
+       for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
+               if (i)
+                       buffer[off++] = ',';
+               p.arg = arr->elem + arr->elemsize * i;
+               ret = arr->get(buffer + off, &p);
+               if (ret < 0)
+                       return ret;
+               off += ret;
+       }
+       buffer[off] = '\0';
+       return off;
+}
+
+int param_set_copystring(const char *val, struct kernel_param *kp)
+{
+       struct kparam_string *kps = kp->arg;
+
+       if (strlen(val)+1 > kps->maxlen) {
+               printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
+                      kp->name, kps->maxlen-1);
+               return -ENOSPC;
+       }
+       strcpy(kps->string, val);
+       return 0;
+}
+
+int param_get_string(char *buffer, struct kernel_param *kp)
+{
+       struct kparam_string *kps = kp->arg;
+       return strlcpy(buffer, kps->string, kps->maxlen);
+}
+
+/**
+ * Parses all parameters from the input string.
+ */
+int parse_params(const char *str)
+{
+       struct kernel_param * params     = __start___param;
+       unsigned int          num_params = __stop___param - __start___param;
+       char tmp[2048];
+
+       // Make a temporary copy of the string since parse_args modifies it
+       if (strlen(str)+1 > sizeof(tmp)) {
+               printk(KERN_ERR "parse_params: input string too large");
+               return -ENOSPC;
+       }
+       
+       strcpy(tmp, str);
+       return parse_args("Parsing Arguments", tmp, params, num_params, NULL);
+}
+
+/**
+ * Manually sets the specified parameter.
+ */
+int param_set_by_name_int(char *param, int val)
+{
+       struct kernel_param * params     = __start___param;
+       unsigned int          num_params = __stop___param - __start___param;
+       char valstr[128];
+
+       sprintf(valstr, "%d", val);
+       return parse_one(param, valstr, params, num_params, NULL);
+}
+
diff --git a/kitten/kernel/printk.c b/kitten/kernel/printk.c
new file mode 100644 (file)
index 0000000..772c872
--- /dev/null
@@ -0,0 +1,52 @@
+#include <lwk/kernel.h>
+#include <lwk/console.h>
+#include <lwk/smp.h>
+
+/**
+ * Prints a message to the console.
+ */
+int printk(const char *fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+       int rc = vprintk( fmt, args );
+       va_end(args);
+       return rc;
+}
+
+
+int printk_print_cpu_number;
+
+
+int
+vprintk(
+       const char *            fmt,
+       va_list                 args
+)
+{
+       int len;
+       char buf[1024];
+       char *p = buf;
+       int remain = sizeof(buf);
+
+       /* Start with a NULL terminated string */
+       *p = '\0';
+
+       /* Tack on the logical CPU ID */
+       if( printk_print_cpu_number )
+       {
+               len = sprintf(p, "[%u]:", this_cpu);
+               p      += len;
+               remain -= len;
+       }
+
+       /* Construct the string... */
+       len = vscnprintf(p, remain, fmt, args);
+
+       /* Pass the string to the console subsystem */
+       console_write(buf);
+
+       /* Return number of characters printed */
+       return len;
+}
+
diff --git a/kitten/kernel/resource.c b/kitten/kernel/resource.c
new file mode 100644 (file)
index 0000000..a8bcd7e
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ *     linux/kernel/resource.c
+ *
+ * Copyright (C) 1999  Linus Torvalds
+ * Copyright (C) 1999  Martin Mares <mj@ucw.cz>
+ *
+ * Arbitrary resource management.
+ */
+
+#include <lwk/errno.h>
+#include <lwk/resource.h>
+#include <lwk/init.h>
+#include <lwk/spinlock.h>
+#include <arch/io.h>
+
+struct resource ioport_resource = {
+       .name   = "PCI IO",
+       .start  = 0x0000,
+       .end    = IO_SPACE_LIMIT,
+       .flags  = IORESOURCE_IO,
+};
+
+struct resource iomem_resource = {
+       .name   = "PCI mem",
+       .start  = 0UL,
+       .end    = ~0UL,
+       .flags  = IORESOURCE_MEM,
+};
+
+static DEFINE_RWLOCK(resource_lock);
+
+/* Return the conflict entry if you can't request it */
+static struct resource * __request_resource(struct resource *root, struct resource *new)
+{
+       unsigned long start = new->start;
+       unsigned long end = new->end;
+       struct resource *tmp, **p;
+
+       if (end < start)
+               return root;
+       if (start < root->start)
+               return root;
+       if (end > root->end)
+               return root;
+       p = &root->child;
+       for (;;) {
+               tmp = *p;
+               if (!tmp || tmp->start > end) {
+                       new->sibling = tmp;
+                       *p = new;
+                       new->parent = root;
+                       return NULL;
+               }
+               p = &tmp->sibling;
+               if (tmp->end < start)
+                       continue;
+               return tmp;
+       }
+}
+
+static int __release_resource(struct resource *old)
+{
+       struct resource *tmp, **p;
+
+       BUG_ON(old->child);
+
+       p = &old->parent->child;
+       for (;;) {
+               tmp = *p;
+               if (!tmp)
+                       break;
+               if (tmp == old) {
+                       *p = tmp->sibling;
+                       old->parent = NULL;
+                       return 0;
+               }
+               p = &tmp->sibling;
+       }
+       return -EINVAL;
+}
+
+int request_resource(struct resource *root, struct resource *new)
+{
+       struct resource *conflict;
+
+       write_lock(&resource_lock);
+       conflict = __request_resource(root, new);
+       write_unlock(&resource_lock);
+       return conflict ? -EBUSY : 0;
+}
+
+struct resource *____request_resource(struct resource *root, struct resource *new)
+{
+       struct resource *conflict;
+
+       write_lock(&resource_lock);
+       conflict = __request_resource(root, new);
+       write_unlock(&resource_lock);
+       return conflict;
+}
+
+int release_resource(struct resource *old)
+{
+       int retval;
+
+       write_lock(&resource_lock);
+       retval = __release_resource(old);
+       write_unlock(&resource_lock);
+       return retval;
+}
+
+/*
+ * Find empty slot in the resource tree given range and alignment.
+ */
+static int find_resource(struct resource *root, struct resource *new,
+                        unsigned long size,
+                        unsigned long min, unsigned long max,
+                        unsigned long align,
+                        void (*alignf)(void *, struct resource *,
+                                       unsigned long, unsigned long),
+                        void *alignf_data)
+{
+       struct resource *this = root->child;
+
+       new->start = root->start;
+       /*
+        * Skip past an allocated resource that starts at 0, since the assignment
+        * of this->start - 1 to new->end below would cause an underflow.
+        */
+       if (this && this->start == 0) {
+               new->start = this->end + 1;
+               this = this->sibling;
+       }
+       for(;;) {
+               if (this)
+                       new->end = this->start - 1;
+               else
+                       new->end = root->end;
+               if (new->start < min)
+                       new->start = min;
+               if (new->end > max)
+                       new->end = max;
+               new->start = ALIGN(new->start, align);
+               if (alignf)
+                       alignf(alignf_data, new, size, align);
+               if (new->start < new->end && new->end - new->start >= size - 1) {
+                       new->end = new->start + size - 1;
+                       return 0;
+               }
+               if (!this)
+                       break;
+               new->start = this->end + 1;
+               this = this->sibling;
+       }
+       return -EBUSY;
+}
+
+/*
+ * Allocate empty slot in the resource tree given range and alignment.
+ */
+int allocate_resource(struct resource *root, struct resource *new,
+                     unsigned long size,
+                     unsigned long min, unsigned long max,
+                     unsigned long align,
+                     void (*alignf)(void *, struct resource *,
+                                    unsigned long, unsigned long),
+                     void *alignf_data)
+{
+       int err;
+
+       write_lock(&resource_lock);
+       err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
+       if (err >= 0 && __request_resource(root, new))
+               err = -EBUSY;
+       write_unlock(&resource_lock);
+       return err;
+}
+
+/**
+ * insert_resource - Inserts a resource in the resource tree
+ * @parent: parent of the new resource
+ * @new: new resource to insert
+ *
+ * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+ * This function is equivalent to request_resource when no conflict
+ * happens. If a conflict happens, and the conflicting resources
+ * entirely fit within the range of the new resource, then the new
+ * resource is inserted and the conflicting resources become children of
+ * the new resource.
+ */
+int insert_resource(struct resource *parent, struct resource *new)
+{
+       int result;
+       struct resource *first, *next;
+
+       write_lock(&resource_lock);
+
+       for (;; parent = first) {
+               result = 0;
+               first = __request_resource(parent, new);
+               if (!first)
+                       goto out;
+
+               result = -EBUSY;
+               if (first == parent)
+                       goto out;
+
+               if ((first->start > new->start) || (first->end < new->end))
+                       break;
+               if ((first->start == new->start) && (first->end == new->end))
+                       break;
+       }
+
+       for (next = first; ; next = next->sibling) {
+               /* Partial overlap? Bad, and unfixable */
+               if (next->start < new->start || next->end > new->end)
+                       goto out;
+               if (!next->sibling)
+                       break;
+               if (next->sibling->start > new->end)
+                       break;
+       }
+
+       result = 0;
+
+       new->parent = parent;
+       new->sibling = next->sibling;
+       new->child = first;
+
+       next->sibling = NULL;
+       for (next = first; next; next = next->sibling)
+               next->parent = new;
+
+       if (parent->child == first) {
+               parent->child = new;
+       } else {
+               next = parent->child;
+               while (next->sibling != first)
+                       next = next->sibling;
+               next->sibling = new;
+       }
+
+ out:
+       write_unlock(&resource_lock);
+       return result;
+}
+
+/*
+ * Given an existing resource, change its start and size to match the
+ * arguments.  Returns -EBUSY if it can't fit.  Existing children of
+ * the resource are assumed to be immutable.
+ */
+int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
+{
+       struct resource *tmp, *parent = res->parent;
+       unsigned long end = start + size - 1;
+       int result = -EBUSY;
+
+       write_lock(&resource_lock);
+
+       if ((start < parent->start) || (end > parent->end))
+               goto out;
+
+       for (tmp = res->child; tmp; tmp = tmp->sibling) {
+               if ((tmp->start < start) || (tmp->end > end))
+                       goto out;
+       }
+
+       if (res->sibling && (res->sibling->start <= end))
+               goto out;
+
+       tmp = parent->child;
+       if (tmp != res) {
+               while (tmp->sibling != res)
+                       tmp = tmp->sibling;
+               if (start <= tmp->end)
+                       goto out;
+       }
+
+       res->start = start;
+       res->end = end;
+       result = 0;
+
+ out:
+       write_unlock(&resource_lock);
+       return result;
+}
+
diff --git a/kitten/kernel/sched.c b/kitten/kernel/sched.c
new file mode 100644 (file)
index 0000000..0165700
--- /dev/null
@@ -0,0 +1,201 @@
+#include <lwk/kernel.h>
+#include <lwk/spinlock.h>
+#include <lwk/percpu.h>
+#include <lwk/aspace.h>
+#include <lwk/sched.h>
+#include <lwk/xcall.h>
+
+struct run_queue {
+       spinlock_t           lock;
+       size_t               num_tasks;
+       struct list_head     task_list;
+       struct task_struct * idle_task;
+};
+
+static DEFINE_PER_CPU(struct run_queue, run_queue);
+
+static void
+idle_task_loop(void) {
+       while (1) {
+               arch_idle_task_loop_body();
+               schedule();
+       }
+}
+
+int __init
+sched_subsys_init(void)
+{
+       id_t cpu_id;
+       struct run_queue *runq;
+       struct task_struct *idle_task;
+       start_state_t start_state;
+       int status;
+
+       /* Reserve the idle tasks' ID. All idle tasks share the same ID. */
+       status = __task_reserve_id(IDLE_TASK_ID);
+       if (status)
+               panic("Failed to reserve IDLE_TASK_ID (status=%d).", status);
+
+       /* Initialize each CPU's run queue */
+       for_each_cpu_mask(cpu_id, cpu_present_map) {
+               runq = &per_cpu(run_queue, cpu_id);
+
+               spin_lock_init(&runq->lock);
+               runq->num_tasks = 0;
+               list_head_init(&runq->task_list);
+
+               /*
+                * Create this CPU's idle task. When a CPU has no
+                * other work to do, it runs the idle task. 
+                */
+               start_state.uid         = 0;
+               start_state.gid         = 0;
+               start_state.aspace_id   = KERNEL_ASPACE_ID;
+               start_state.entry_point = (vaddr_t)idle_task_loop;
+               start_state.stack_ptr   = 0; /* will be set automatically */
+               start_state.cpu_id      = cpu_id;
+               start_state.cpumask     = NULL;
+
+               status = __task_create(IDLE_TASK_ID, "idle_task", &start_state,
+                                      &idle_task);
+               if (status)
+                       panic("Failed to create idle_task (status=%d).",status);
+
+               runq->idle_task = idle_task;
+       }
+
+       return 0;
+}
+
+void
+sched_add_task(struct task_struct *task)
+{
+       id_t cpu = task->cpu_id;
+       struct run_queue *runq;
+       unsigned long irqstate;
+
+       runq = &per_cpu(run_queue, cpu);
+       spin_lock_irqsave(&runq->lock, irqstate);
+       list_add_tail(&task->sched_link, &runq->task_list);
+       ++runq->num_tasks;
+       spin_unlock_irqrestore(&runq->lock, irqstate);
+
+       if (cpu != this_cpu)
+               xcall_reschedule(cpu);
+}
+
+void
+sched_del_task(struct task_struct *task)
+{
+       struct run_queue *runq;
+       unsigned long irqstate;
+
+       runq = &per_cpu(run_queue, task->cpu_id);
+       spin_lock_irqsave(&runq->lock, irqstate);
+       list_del(&task->sched_link);
+       --runq->num_tasks;
+       spin_unlock_irqrestore(&runq->lock, irqstate);
+}
+
+int
+sched_wakeup_task(struct task_struct *task, taskstate_t valid_states)
+{
+       id_t cpu;
+       struct run_queue *runq;
+       int status;
+       unsigned long irqstate;
+
+       /* Protect against the task being migrated to a different CPU */
+repeat_lock_runq:
+       cpu  = task->cpu_id;
+       runq = &per_cpu(run_queue, cpu);
+       spin_lock_irqsave(&runq->lock, irqstate);
+       if (cpu != task->cpu_id) {
+               spin_unlock_irqrestore(&runq->lock, irqstate);
+               goto repeat_lock_runq;
+       }
+       if (task->state & valid_states) {
+               set_mb(task->state, TASKSTATE_READY);
+               status = 0;
+       } else {
+               status = -EINVAL;
+       }
+       spin_unlock_irqrestore(&runq->lock, irqstate);
+
+       if (!status && (cpu != this_cpu))
+               xcall_reschedule(cpu);
+
+       return status;
+}
+
+static void
+context_switch(struct task_struct *prev, struct task_struct *next)
+{
+       /* Switch to the next task's address space */
+       if (prev->aspace != next->aspace)
+               arch_aspace_activate(next->aspace);
+
+       /**
+        * Switch to the next task's register state and kernel stack.
+        * There are three tasks involved in a context switch:
+        *     1. The previous task
+        *     2. The next task 
+        *     3. The task that was running when next was suspended
+        * arch_context_switch() returns 1 so that we can maintain
+        * the correct value of prev.  Otherwise, the restored register
+        * state of next would have prev set to 3, which we don't care
+        * about (it may have moved CPUs, been destroyed, etc.).
+        */
+       prev = arch_context_switch(prev, next);
+
+       /* Prevent compiler from optimizing beyond this point */
+       barrier();
+}
+
+void
+schedule(void)
+{
+       struct run_queue *runq = &per_cpu(run_queue, this_cpu);
+       struct task_struct *prev = current, *next = NULL, *task;
+
+       spin_lock_irq(&runq->lock);
+
+       /* Move the currently running task to the end of the run queue */
+       if (!list_empty(&prev->sched_link)) {
+               list_del(&prev->sched_link);
+               /* If the task has exited, don't re-link it */
+               if (prev->state != TASKSTATE_EXIT_ZOMBIE)
+                       list_add_tail(&prev->sched_link, &runq->task_list);
+       }
+
+       /* Look for a ready to execute task */
+       list_for_each_entry(task, &runq->task_list, sched_link) {
+               if (task->state == TASKSTATE_READY) {
+                       next = task;
+                       break;
+               }
+       }
+
+       /* If no tasks are ready to run, run the idle task */
+       if (next == NULL)
+               next = runq->idle_task;
+
+       if (prev != next) {
+               context_switch(prev, next);
+               /* next is now running, since it may have changed CPUs while
+                * it was sleeping, we need to refresh local variables */
+               runq = &per_cpu(run_queue, this_cpu);
+       }
+
+       spin_unlock_irq(&runq->lock);
+}
+
+void
+schedule_new_task_tail(void)
+{
+       struct run_queue *runq = &per_cpu(run_queue, this_cpu);
+       BUG_ON(irqs_enabled());
+       spin_unlock(&runq->lock);  /* keep IRQs disabled, arch code will
+                                   * re-enable IRQs as part of starting
+                                   * the new task */
+}
diff --git a/kitten/kernel/show.c b/kitten/kernel/show.c
new file mode 100644 (file)
index 0000000..7175ebf
--- /dev/null
@@ -0,0 +1,22 @@
+#include <lwk/kernel.h>
+#include <lwk/show.h>
+
+/**
+ * Prints the contents of memory in hex to the console.
+ * The region printed starts at vaddr and extends n unsigned longs.
+ */
+void
+show_memory(unsigned long vaddr, size_t n)
+{
+       int i;
+
+       for (i = 0; i < n; i++) {
+               printk(KERN_DEBUG "0x%016lx: 0x%08x_%08x\n",
+                       vaddr,
+                       *((unsigned int *)(vaddr+4)),
+                       *((unsigned int *)(vaddr))
+               );
+               vaddr += sizeof(unsigned long);
+       }
+}
+
diff --git a/kitten/kernel/spinlock.c b/kitten/kernel/spinlock.c
new file mode 100644 (file)
index 0000000..3cbf9ed
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (2004) Linus Torvalds
+ *
+ * Author: Zwane Mwaikambo <zwane@fsmlabs.com>
+ *
+ * Copyright (2004, 2005) Ingo Molnar
+ *
+ * This file contains the spinlock/rwlock implementations for the
+ * SMP and the DEBUG_SPINLOCK cases. 
+ */
+
+#include <lwk/linkage.h>
+#include <lwk/spinlock.h>
+//#include <lwk/interrupt.h>
+#include <lwk/linux_compat.h>
+
+/*
+ * Generic declaration of the raw read_trylock() function,
+ * architectures are supposed to optimize this:
+ */
+int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock)
+{
+       __raw_read_lock(lock);
+       return 1;
+}
+EXPORT_SYMBOL(generic__raw_read_trylock);
+
+int __lockfunc _spin_trylock(spinlock_t *lock)
+{
+       if (_raw_spin_trylock(lock))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(_spin_trylock);
+
+int __lockfunc _read_trylock(rwlock_t *lock)
+{
+       if (_raw_read_trylock(lock))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(_read_trylock);
+
+int __lockfunc _write_trylock(rwlock_t *lock)
+{
+       if (_raw_write_trylock(lock))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(_write_trylock);
+
+void __lockfunc _read_lock(rwlock_t *lock)
+{
+       _raw_read_lock(lock);
+}
+EXPORT_SYMBOL(_read_lock);
+
+unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       _raw_spin_lock_flags(lock, &flags);
+       return flags;
+}
+EXPORT_SYMBOL(_spin_lock_irqsave);
+
+void __lockfunc _spin_lock_irq(spinlock_t *lock)
+{
+       local_irq_disable();
+       _raw_spin_lock(lock);
+}
+EXPORT_SYMBOL(_spin_lock_irq);
+
+#if 0
+void __lockfunc _spin_lock_bh(spinlock_t *lock)
+{
+       local_bh_disable();
+       _raw_spin_lock(lock);
+}
+EXPORT_SYMBOL(_spin_lock_bh);
+#endif
+
+unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       _raw_read_lock(lock);
+       return flags;
+}
+EXPORT_SYMBOL(_read_lock_irqsave);
+
+void __lockfunc _read_lock_irq(rwlock_t *lock)
+{
+       local_irq_disable();
+       _raw_read_lock(lock);
+}
+EXPORT_SYMBOL(_read_lock_irq);
+
+#if 0
+void __lockfunc _read_lock_bh(rwlock_t *lock)
+{
+       local_bh_disable();
+       _raw_read_lock(lock);
+}
+EXPORT_SYMBOL(_read_lock_bh);
+#endif
+
+unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       _raw_write_lock(lock);
+       return flags;
+}
+EXPORT_SYMBOL(_write_lock_irqsave);
+
+void __lockfunc _write_lock_irq(rwlock_t *lock)
+{
+       local_irq_disable();
+       _raw_write_lock(lock);
+}
+EXPORT_SYMBOL(_write_lock_irq);
+
+#if 0
+void __lockfunc _write_lock_bh(rwlock_t *lock)
+{
+       local_bh_disable();
+       _raw_write_lock(lock);
+}
+EXPORT_SYMBOL(_write_lock_bh);
+#endif
+
+void __lockfunc _spin_lock(spinlock_t *lock)
+{
+       _raw_spin_lock(lock);
+}
+
+EXPORT_SYMBOL(_spin_lock);
+
+void __lockfunc _write_lock(rwlock_t *lock)
+{
+       _raw_write_lock(lock);
+}
+
+EXPORT_SYMBOL(_write_lock);
+
+void __lockfunc _spin_unlock(spinlock_t *lock)
+{
+       _raw_spin_unlock(lock);
+}
+EXPORT_SYMBOL(_spin_unlock);
+
+void __lockfunc _write_unlock(rwlock_t *lock)
+{
+       _raw_write_unlock(lock);
+}
+EXPORT_SYMBOL(_write_unlock);
+
+void __lockfunc _read_unlock(rwlock_t *lock)
+{
+       _raw_read_unlock(lock);
+}
+EXPORT_SYMBOL(_read_unlock);
+
+void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+{
+       _raw_spin_unlock(lock);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(_spin_unlock_irqrestore);
+
+void __lockfunc _spin_unlock_irq(spinlock_t *lock)
+{
+       _raw_spin_unlock(lock);
+       local_irq_enable();
+}
+EXPORT_SYMBOL(_spin_unlock_irq);
+
+#if 0
+void __lockfunc _spin_unlock_bh(spinlock_t *lock)
+{
+       _raw_spin_unlock(lock);
+       local_bh_enable();
+}
+EXPORT_SYMBOL(_spin_unlock_bh);
+#endif
+
+void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+{
+       _raw_read_unlock(lock);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(_read_unlock_irqrestore);
+
+void __lockfunc _read_unlock_irq(rwlock_t *lock)
+{
+       _raw_read_unlock(lock);
+       local_irq_enable();
+}
+EXPORT_SYMBOL(_read_unlock_irq);
+
+#if 0
+void __lockfunc _read_unlock_bh(rwlock_t *lock)
+{
+       _raw_read_unlock(lock);
+       local_bh_enable();
+}
+EXPORT_SYMBOL(_read_unlock_bh);
+#endif
+
+void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+{
+       _raw_write_unlock(lock);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(_write_unlock_irqrestore);
+
+void __lockfunc _write_unlock_irq(rwlock_t *lock)
+{
+       _raw_write_unlock(lock);
+       local_irq_enable();
+}
+EXPORT_SYMBOL(_write_unlock_irq);
+
+#if 0
+void __lockfunc _write_unlock_bh(rwlock_t *lock)
+{
+       _raw_write_unlock(lock);
+       local_bh_enable();
+}
+EXPORT_SYMBOL(_write_unlock_bh);
+#endif
+
+#if 0
+int __lockfunc _spin_trylock_bh(spinlock_t *lock)
+{
+       local_bh_disable();
+       if (_raw_spin_trylock(lock))
+               return 1;
+       local_bh_enable();
+       return 0;
+}
+EXPORT_SYMBOL(_spin_trylock_bh);
+#endif
+
+int in_lock_functions(unsigned long addr)
+{
+       /* Linker adds these: start and end of __lockfunc functions */
+       extern char __lock_text_start[], __lock_text_end[];
+
+       return addr >= (unsigned long)__lock_text_start
+       && addr < (unsigned long)__lock_text_end;
+}
+EXPORT_SYMBOL(in_lock_functions);
diff --git a/kitten/kernel/task.c b/kitten/kernel/task.c
new file mode 100644 (file)
index 0000000..238f4b7
--- /dev/null
@@ -0,0 +1,237 @@
+#include <lwk/kernel.h>
+#include <lwk/xcall.h>
+#include <lwk/htable.h>
+#include <lwk/aspace.h>
+#include <lwk/task.h>
+#include <lwk/sched.h>
+#include <arch/uaccess.h>
+
+/**
+ * ID space used to allocate task IDs.
+ */
+static idspace_t idspace;
+
+/**
+ * Hash table used to lookup task structures by ID.
+ */
+static htable_t htable;
+
+/**
+ * Lock for serializing access to the htable.
+ */
+static DEFINE_SPINLOCK(htable_lock);
+
+int __init
+task_subsys_init(void)
+{
+       if (idspace_create(__TASK_MIN_ID, __TASK_MAX_ID, &idspace))
+               panic("Failed to create task ID space.");
+
+       if (htable_create(7 /* 2^7 bins */,
+                         offsetof(struct task_struct, id),
+                         offsetof(struct task_struct, ht_link),
+                         &htable))
+               panic("Failed to create task hash table.");
+
+       return 0;
+}
+
+int
+task_get_myid(id_t *id)
+{
+       *id = current->id;
+       return 0;
+}
+
+int
+sys_task_get_myid(id_t __user *id)
+{
+       int status;
+       id_t _id;
+
+       if ((status = task_get_myid(&_id)) != 0)
+               return status;
+
+       if (id && copy_to_user(id, &_id, sizeof(*id)))
+               return -EINVAL;
+
+       return 0;
+}
+
+int
+__task_reserve_id(id_t id)
+{
+       return idspace_alloc_id(idspace, id, NULL);
+}
+
+int
+__task_create(id_t id, const char *name,
+              const start_state_t *start_state,
+              struct task_struct **task)
+{
+       int status;
+       union task_union *task_union;
+       struct task_struct *tsk;
+
+       if ((task_union = kmem_get_pages(TASK_ORDER)) == NULL)
+               return -ENOMEM;
+
+       tsk = &task_union->task_info;
+
+       /*
+        * Initialize the new task. kmem_alloc() allocates zeroed memory
+        * so fields with an initial state of zero do not need to be explicitly
+        * initialized.
+        */
+       tsk->id = id;
+       if (name)
+               strlcpy(tsk->name, name, sizeof(tsk->name));
+       hlist_node_init(&tsk->ht_link);
+       tsk->state = TASKSTATE_READY;
+       tsk->uid = start_state->uid;
+       tsk->gid = start_state->gid;
+       tsk->aspace = aspace_acquire(start_state->aspace_id);
+       if (!tsk->aspace) {
+               status = -ENOENT;
+               goto error1;
+       }
+       tsk->sighand = NULL;
+       if (start_state->cpumask) {
+               cpumask_user2kernel(start_state->cpumask, &tsk->cpumask);
+               if (!cpus_subset(tsk->cpumask, current->cpumask)) {
+                       status = -EINVAL;
+                       goto error2;
+               }
+       } else {
+               tsk->cpumask = current->cpumask;
+       }
+       if ((start_state->cpu_id >= NR_CPUS)
+            || !cpu_isset(start_state->cpu_id, tsk->cpumask)) {
+               status = -EINVAL;
+               goto error2;
+       }
+       tsk->cpu_id = start_state->cpu_id;
+       list_head_init(&tsk->sched_link);
+       tsk->ptrace = 0;
+       tsk->flags = 0;
+       tsk->exit_status = 0;
+
+       /* Do architecture-specific initialization */
+       if ((status = arch_task_create(tsk, start_state)) != 0)
+               goto error2;
+
+       if (task)
+               *task = tsk;
+       return 0;
+
+error2:
+       if (tsk->aspace)
+               aspace_release(tsk->aspace);
+error1:
+       kmem_free_pages(task_union, TASK_ORDER);
+       return status;
+}
+
+int
+task_create(id_t id_request, const char *name,
+            const start_state_t *start_state, id_t *id)
+{
+       id_t new_id;
+       struct task_struct *new_task;
+       int status;
+       unsigned long irqstate;
+
+       /* Allocate an ID for the new task */
+       if ((status = idspace_alloc_id(idspace, id_request, &new_id)) != 0)
+               return status;
+
+       /* Create and initialize a new task */
+       if ((status = __task_create(new_id, name, start_state, &new_task))) {
+               idspace_free_id(idspace, new_id);
+               return status;
+       }
+
+       /* Add new task to a hash table, for quick lookups by ID */
+       spin_lock_irqsave(&htable_lock, irqstate);
+       BUG_ON(htable_add(htable, new_task));
+       spin_unlock_irqrestore(&htable_lock, irqstate);
+
+       /* Add the new task to the target CPU's run queue */
+       sched_add_task(new_task);
+
+       if (id)
+               *id = new_task->id;
+       return 0;
+}
+
+int
+sys_task_create(id_t id_request, const char __user *name,
+                const start_state_t __user *start_state, id_t __user *id)
+{
+       int status;
+       start_state_t _start_state;
+       user_cpumask_t _cpumask;
+       char _name[16];
+       id_t _id;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (copy_from_user(&_start_state, start_state, sizeof(_start_state)))
+               return -EINVAL;
+
+       if (_start_state.aspace_id == KERNEL_ASPACE_ID)
+               return -EINVAL;
+
+       if (_start_state.cpumask) {
+               if (copy_from_user(&_cpumask, _start_state.cpumask, sizeof(_cpumask)))
+                       return -EINVAL;
+               _start_state.cpumask = &_cpumask;
+       }
+
+       if (name && (strncpy_from_user(_name, name, sizeof(_name)) < 0))
+               return -EFAULT;
+       _name[sizeof(_name) - 1] = '\0';
+
+       if ((status = task_create(id_request, _name, &_start_state, &_id)) != 0)
+               return status;
+
+       if (id && copy_to_user(id, &_id, sizeof(*id)))
+               return -EFAULT;
+
+       return 0;
+}
+
+int
+task_exit(int status)
+{
+       /* Mark the task as exited...
+        * schedule() will remove it from the run queue */
+       current->exit_status = status;
+       current->state = TASKSTATE_EXIT_ZOMBIE;
+       schedule(); /* task is dead, so this should never return */
+       BUG();
+       while (1) {}
+}
+
+int
+sys_task_exit(int status)
+{
+       return task_exit(status);
+}
+
+int
+task_yield(void)
+{
+       /*
+        * Nothing to do, schedule() will be automatically
+        * called before returning to user-space
+        */
+       return 0;
+}
+
+int
+sys_task_yield(void)
+{
+       return task_yield();
+}
diff --git a/kitten/kernel/time.c b/kitten/kernel/time.c
new file mode 100644 (file)
index 0000000..1c5b7e7
--- /dev/null
@@ -0,0 +1,62 @@
+#include <lwk/time.h>
+#include <arch/div64.h>
+
+static uint64_t shift;
+static uint64_t mult;
+static uint64_t offset;
+
+/**
+ * Converts the input khz cycle counter frequency to a time source multiplier.
+ * The multiplier is used to convert cycle counts to nanoseconds.
+ */
+void
+init_cycles2ns(uint32_t khz)
+{
+       /*
+        * Shift is used to obtain greater precision.
+        * Linux uses 22 for the x86 time stamp counter.
+        * For now we assume this will work for most cases.
+        */
+       shift = 22;
+
+       /*  
+        *  khz = cyc/(Million ns)
+        *  mult/2^shift  = ns/cyc
+        *  mult = ns/cyc * 2^shift
+        *  mult = 1Million/khz * 2^shift
+        *  mult = 1000000 * 2^shift / khz
+        *  mult = (1000000<<shift) / khz
+        */
+       mult = ((u64)1000000) << shift;
+       mult += khz/2; /* round for do_div */
+       do_div(mult, khz);
+}
+
+/**
+ * Converts cycles to nanoseconds.
+ * init_cycles2ns() must be called before this will work properly.
+ */
+uint64_t
+cycles2ns(uint64_t cycles)
+{
+       return (cycles * mult) >> shift;
+}
+
+/**
+ * Returns the current time in nanoseconds.
+ */
+uint64_t
+get_time(void)
+{
+       return cycles2ns(get_cycles()) + offset;
+}
+
+/**
+ * Sets the current time in nanoseconds.
+ */
+void
+set_time(uint64_t ns)
+{
+       offset = ns - cycles2ns(get_cycles());
+}
+
diff --git a/kitten/kernel/timer.c b/kitten/kernel/timer.c
new file mode 100644 (file)
index 0000000..bf4d304
--- /dev/null
@@ -0,0 +1,129 @@
+#include <lwk/kernel.h>
+#include <lwk/spinlock.h>
+#include <lwk/percpu.h>
+#include <lwk/time.h>
+#include <lwk/timer.h>
+#include <lwk/sched.h>
+
+struct timer_queue {
+       spinlock_t       lock;
+       struct list_head timer_list;
+};
+
+static DEFINE_PER_CPU(struct timer_queue, timer_queue);
+
+int
+timer_subsys_init(void)
+{
+       id_t cpu;
+       struct timer_queue *timerq;
+
+       for_each_cpu_mask(cpu, cpu_present_map) {
+               timerq = &per_cpu(timer_queue, cpu);
+               spin_lock_init(&timerq->lock);
+               list_head_init(&timerq->timer_list);
+       }
+
+       return 0;
+}
+
+void
+timer_add(struct timer *timer)
+{
+       struct timer_queue *timerq;
+       struct list_head *pos;
+       unsigned long irqstate;
+
+       timerq = &per_cpu(timer_queue, this_cpu);
+       spin_lock_irqsave(&timerq->lock, irqstate);
+
+       /* Initialize fields we don't expect the caller to set */
+       list_head_init(&timer->link);
+       timer->cpu = this_cpu;
+
+       /* Insert the new timer into the CPU's sorted timer_list */
+       list_for_each(pos, &timerq->timer_list) {
+               struct timer *cur = list_entry(pos, struct timer, link);
+               if (cur->expires > timer->expires)
+                       break;
+       }
+       list_add_tail(&timer->link, pos);
+
+       spin_unlock_irqrestore(&timerq->lock, irqstate);
+}
+
+void
+timer_del(struct timer *timer)
+{
+       struct timer_queue *timerq;
+       unsigned long irqstate;
+
+       timerq = &per_cpu(timer_queue, timer->cpu);
+       spin_lock_irqsave(&timerq->lock, irqstate);
+
+       /* Remove the timer, if it hasn't already expired */
+       if (!list_empty(&timer->link))
+               list_del(&timer->link);
+
+       spin_unlock_irqrestore(&timerq->lock, irqstate);
+}
+
+static void
+wakeup_task(uintptr_t task)
+{
+       sched_wakeup_task((struct task_struct *)task, TASKSTATE_INTERRUPTIBLE);
+}
+
+/* Returns the time remaining */
+uint64_t
+timer_sleep_until(uint64_t when)
+{
+       struct timer timer;
+       uint64_t now;
+
+       timer.expires  = when;
+       timer.function = &wakeup_task;
+       timer.data     = (uintptr_t)current;
+       timer_add(&timer);
+
+       /* Go to sleep */
+       set_mb(current->state, TASKSTATE_INTERRUPTIBLE);
+       schedule();
+
+       /* Return the time remaining */
+       now = get_time();
+       return (when > now) ? (when - now) : 0;
+}
+
+void
+expire_timers(void)
+{
+       struct timer_queue *timerq = &per_cpu(timer_queue, this_cpu);
+       struct timer *timer;
+       uint64_t now = get_time();
+       unsigned long irqstate;
+
+       do {
+               /* Pop the head entry off of the timer list */
+               spin_lock_irqsave(&timerq->lock, irqstate);
+               if (!list_empty(&timerq->timer_list)) {
+                       timer = list_entry(timerq->timer_list.next,
+                                          struct timer,
+                                          link);
+                       if (timer->expires <= now) {
+                               list_del_init(&timer->link);
+                       } else {
+                               timer = NULL;
+                       }
+               } else {
+                       timer = NULL;
+               }
+               spin_unlock_irqrestore(&timerq->lock, irqstate);
+
+               /* Execute the timer's callback function.
+                * Note that we have released the timerq->lock, so the
+                * callback function is free to call timer_add(). */
+               if (timer)
+                       (*timer->function)(timer->data);
+       } while (timer);
+}
diff --git a/kitten/kernel/waitq.c b/kitten/kernel/waitq.c
new file mode 100644 (file)
index 0000000..80f5de9
--- /dev/null
@@ -0,0 +1,89 @@
+#include <lwk/kernel.h>
+#include <lwk/waitq.h>
+#include <lwk/sched.h>
+
+void
+waitq_init(waitq_t *waitq)
+{
+       spin_lock_init(&waitq->lock);
+       list_head_init(&waitq->waitq);
+}
+
+void
+waitq_init_entry(waitq_entry_t *entry, struct task_struct *task)
+{
+       entry->task = task;
+       list_head_init(&entry->link);
+}
+
+bool
+waitq_active(waitq_t *waitq)
+{
+       bool active;
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&waitq->lock, irqstate);
+       active = !list_empty(&waitq->waitq);
+       spin_unlock_irqrestore(&waitq->lock, irqstate);
+
+       return active;
+}
+
+void
+waitq_add_entry(waitq_t *waitq, waitq_entry_t *entry)
+{
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&waitq->lock, irqstate);
+       BUG_ON(!list_empty(&entry->link));
+       list_add(&entry->link, &waitq->waitq);
+       spin_unlock_irqrestore(&waitq->lock, irqstate);
+}
+
+void
+waitq_remove_entry(waitq_t *waitq, waitq_entry_t *entry)
+{
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&waitq->lock, irqstate);
+       BUG_ON(list_empty(&entry->link));
+       list_del_init(&entry->link);
+       spin_unlock_irqrestore(&waitq->lock, irqstate);
+}
+
+void
+waitq_prepare_to_wait(waitq_t *waitq, waitq_entry_t *entry, taskstate_t state)
+{
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&waitq->lock, irqstate);
+       if (list_empty(&entry->link))
+               list_add(&entry->link, &waitq->waitq);
+       set_mb(entry->task->state, state);
+       spin_unlock_irqrestore(&waitq->lock, irqstate);
+}
+
+void
+waitq_finish_wait(waitq_t *waitq, waitq_entry_t *entry)
+{
+       set_mb(entry->task->state, TASKSTATE_READY);
+       waitq_remove_entry(waitq, entry);
+}
+
+void
+waitq_wakeup(waitq_t *waitq)
+{
+       unsigned long irqstate;
+       struct list_head *tmp;
+       waitq_entry_t *entry;
+
+       spin_lock_irqsave(&waitq->lock, irqstate);
+       list_for_each(tmp, &waitq->waitq) {
+               entry  = list_entry(tmp, waitq_entry_t, link);
+               sched_wakeup_task(
+                       entry->task,
+                       (TASKSTATE_UNINTERRUPTIBLE | TASKSTATE_INTERRUPTIBLE)
+               );
+       }
+       spin_unlock_irqrestore(&waitq->lock, irqstate);
+}
diff --git a/kitten/kernel/xcall.c b/kitten/kernel/xcall.c
new file mode 100644 (file)
index 0000000..cd5ace8
--- /dev/null
@@ -0,0 +1,71 @@
+#include <lwk/kernel.h>
+#include <lwk/smp.h>
+#include <lwk/xcall.h>
+
+/**
+ * Carries out an inter-CPU function call. The specified function is executed
+ * on all of the target CPUs that are currently online and executes in 
+ * interrupt context with interrupts disabled... it must not block and should
+ * be short.
+ *
+ * Arguments:
+ *       [IN] cpu_mask: The target CPUs of the cross-call.
+ *       [IN] func:     The function to execute on each target CPU.
+ *       [IN] info:     Argument to pass to func().
+ *       [IN] wait:     true = wait for cross-call to fully complete.
+ *
+ * Returns:
+ *       Success: 0
+ *       Failure: Error code
+ *
+ * NOTE: If wait=0, care must be taken to ensure that the data pointed to by
+ *       the info argument remains valid until the cross-call function func()
+ *       completes on all target CPUs.
+ */
+int
+xcall_function(
+       cpumask_t       cpu_mask,
+       void            (*func)(void *info),
+       void *          info,
+       bool            wait
+)
+{
+       bool contains_me;
+       int status;
+
+       BUG_ON(irqs_disabled());
+       BUG_ON(!func);
+
+       /* Only target online CPUs */
+       cpus_and(cpu_mask, cpu_mask, cpu_online_map);
+
+       /* No need to xcall ourself... we'll just call func() directly */
+       if ((contains_me = cpu_isset(this_cpu, cpu_mask)))
+               cpu_clear(this_cpu, cpu_mask);
+
+       /* Perform xcall to remote CPUs */
+       if ((status = arch_xcall_function(cpu_mask, func, info, wait)))
+               return status;
+
+       /* Call func() on the local CPU, if it was in cpu_mask */
+       if (contains_me)
+               (*func)(info);
+
+       return 0;
+}
+
+/**
+ * Sends a reschedule inter-processor interrupt to the target CPU.
+ * This causes the target CPU to call schedule().
+ *
+ * NOTE: It is safe to call this with locks held and interrupts
+ *       disabled so long as the caller will drop the locks and
+ *       re-enable interrupts "soon", independent of whether the
+ *       target actually receives the reschedule interrupt. 
+ *       Deadlock may occur if these conditions aren't met.
+ */
+void
+xcall_reschedule(id_t cpu)
+{
+       arch_xcall_reschedule(cpu);
+}
diff --git a/kitten/lib/Kconfig.debug b/kitten/lib/Kconfig.debug
new file mode 100644 (file)
index 0000000..c2cddce
--- /dev/null
@@ -0,0 +1,98 @@
+config DEBUG_KERNEL
+       bool "Kernel debugging"
+       help
+         Say Y here if you are developing drivers or trying to debug and
+         identify kernel problems.
+
+config LOG_BUF_SHIFT
+       int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
+       range 12 21
+       default 15
+       help
+         Select kernel log buffer size as a power of 2.
+         Defaults and Examples:
+                    17 => 128 KB
+                    16 => 64 KB
+                    15 => 32 KB
+                    14 => 16 KB
+                    13 =>  8 KB
+                    12 =>  4 KB
+
+config DEBUG_MUTEXES
+       bool "Mutex debugging, deadlock detection"
+       default n
+       depends on DEBUG_KERNEL
+       help
+        This allows mutex semantics violations and mutex related deadlocks
+        (lockups) to be detected and reported automatically.
+
+config DEBUG_SPINLOCK
+       bool "Spinlock debugging"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here and build SMP to catch missing spinlock initialization
+         and certain other kinds of spinlock errors commonly made.  This is
+         best used in conjunction with the NMI watchdog so that spinlock
+         deadlocks are also debuggable.
+
+config DEBUG_SPINLOCK_SLEEP
+       bool "Sleep-inside-spinlock checking"
+       depends on DEBUG_KERNEL
+       help
+         If you say Y here, various routines which may sleep will become very
+         noisy if they are called with a spinlock held.
+
+config DEBUG_BUGVERBOSE
+       bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
+       depends on BUG
+       depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV
+       default !EMBEDDED
+       help
+         Say Y here to make BUG() panics output the file name and line number
+         of the BUG call as well as the EIP and oops trace.  This aids
+         debugging but costs about 70-100K of memory.
+
+config DEBUG_INFO
+       bool "Compile the kernel with debug info"
+       depends on DEBUG_KERNEL
+       help
+          If you say Y here the resulting kernel image will include
+         debugging info resulting in a larger kernel image.
+         Say Y here only if you plan to debug the kernel.
+
+         If unsure, say N.
+
+config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       depends on DEBUG_KERNEL
+       default y if DEBUG_INFO && UML
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         and slower, but it might give very useful debugging information on
+         some architectures or if you use external debuggers.
+         If you don't debug the kernel, you can say N.
+
+config UNWIND_INFO
+       bool "Compile the kernel with frame unwind information"
+       depends on !IA64
+       depends on !MODULES || !(MIPS || PARISC || PPC || SUPERH || V850)
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         but not slower, and 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 unwind information or frame pointers.
+
+config FORCED_INLINING
+       bool "Force gcc to inline functions marked 'inline'"
+       depends on DEBUG_KERNEL
+       default y
+       help
+         This option determines if the kernel forces gcc to inline the functions
+         developers have marked 'inline'. Doing so takes away freedom from gcc to
+         do what it thinks is best, which is desirable for the gcc 3.x series of
+         compilers. The gcc 4.x series have a rewritten inlining algorithm and
+         disabling this option will generate a smaller kernel there. Hopefully
+         this algorithm is so good that allowing gcc4 to make the decision can
+         become the default in the future, until then this option is there to
+         test gcc for this.
+
diff --git a/kitten/lib/Makefile b/kitten/lib/Makefile
new file mode 100644 (file)
index 0000000..2301ca2
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for some libs needed by the kernel.
+#
+
+lib-y := vsprintf.o string.o ctype.o cmdline.o cpumask.o bitmap.o hweight.o \
+               extable.o sort.o
diff --git a/kitten/lib/bitmap.c b/kitten/lib/bitmap.c
new file mode 100644 (file)
index 0000000..a5e3e92
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * lib/bitmap.c
+ * Helper functions for bitmap.h.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+#include <lwk/kernel.h>
+#include <lwk/ctype.h>
+#include <lwk/errno.h>
+#include <lwk/bitmap.h>
+#include <lwk/bitops.h>
+#include <lwk/linux_compat.h>
+//#include <asm/uaccess.h>
+
+/*
+ * bitmaps provide an array of bits, implemented using an an
+ * array of unsigned longs.  The number of valid bits in a
+ * given bitmap does _not_ need to be an exact multiple of
+ * BITS_PER_LONG.
+ *
+ * The possible unused bits in the last, partially used word
+ * of a bitmap are 'don't care'.  The implementation makes
+ * no particular effort to keep them zero.  It ensures that
+ * their value will not affect the results of any operation.
+ * The bitmap operations that return Boolean (bitmap_empty,
+ * for example) or scalar (bitmap_weight, for example) results
+ * carefully filter out these unused bits from impacting their
+ * results.
+ *
+ * These operations actually hold to a slightly stronger rule:
+ * if you don't input any bitmaps to these ops that have some
+ * unused bits set, then they won't output any set unused bits
+ * in output bitmaps.
+ *
+ * The byte ordering of bitmaps is more natural on little
+ * endian architectures.  See the big-endian headers
+ * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h
+ * for the best explanations of this ordering.
+ */
+
+int __bitmap_empty(const unsigned long *bitmap, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (bitmap[k])
+                       return 0;
+
+       if (bits % BITS_PER_LONG)
+               if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
+                       return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(__bitmap_empty);
+
+int __bitmap_full(const unsigned long *bitmap, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (~bitmap[k])
+                       return 0;
+
+       if (bits % BITS_PER_LONG)
+               if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
+                       return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(__bitmap_full);
+
+int __bitmap_equal(const unsigned long *bitmap1,
+               const unsigned long *bitmap2, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (bitmap1[k] != bitmap2[k])
+                       return 0;
+
+       if (bits % BITS_PER_LONG)
+               if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
+                       return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(__bitmap_equal);
+
+void __bitmap_complement(unsigned long *dst, const unsigned long *src, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               dst[k] = ~src[k];
+
+       if (bits % BITS_PER_LONG)
+               dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
+}
+EXPORT_SYMBOL(__bitmap_complement);
+
+/*
+ * __bitmap_shift_right - logical right shift of the bits in a bitmap
+ *   @dst - destination bitmap
+ *   @src - source bitmap
+ *   @nbits - shift by this many bits
+ *   @bits - bitmap size, in bits
+ *
+ * Shifting right (dividing) means moving bits in the MS -> LS bit
+ * direction.  Zeros are fed into the vacated MS positions and the
+ * LS bits shifted off the bottom are lost.
+ */
+void __bitmap_shift_right(unsigned long *dst,
+                       const unsigned long *src, int shift, int bits)
+{
+       int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
+       int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
+       unsigned long mask = (1UL << left) - 1;
+       for (k = 0; off + k < lim; ++k) {
+               unsigned long upper, lower;
+
+               /*
+                * If shift is not word aligned, take lower rem bits of
+                * word above and make them the top rem bits of result.
+                */
+               if (!rem || off + k + 1 >= lim)
+                       upper = 0;
+               else {
+                       upper = src[off + k + 1];
+                       if (off + k + 1 == lim - 1 && left)
+                               upper &= mask;
+               }
+               lower = src[off + k];
+               if (left && off + k == lim - 1)
+                       lower &= mask;
+               dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem;
+               if (left && k == lim - 1)
+                       dst[k] &= mask;
+       }
+       if (off)
+               memset(&dst[lim - off], 0, off*sizeof(unsigned long));
+}
+EXPORT_SYMBOL(__bitmap_shift_right);
+
+
+/*
+ * __bitmap_shift_left - logical left shift of the bits in a bitmap
+ *   @dst - destination bitmap
+ *   @src - source bitmap
+ *   @nbits - shift by this many bits
+ *   @bits - bitmap size, in bits
+ *
+ * Shifting left (multiplying) means moving bits in the LS -> MS
+ * direction.  Zeros are fed into the vacated LS bit positions
+ * and those MS bits shifted off the top are lost.
+ */
+
+void __bitmap_shift_left(unsigned long *dst,
+                       const unsigned long *src, int shift, int bits)
+{
+       int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
+       int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
+       for (k = lim - off - 1; k >= 0; --k) {
+               unsigned long upper, lower;
+
+               /*
+                * If shift is not word aligned, take upper rem bits of
+                * word below and make them the bottom rem bits of result.
+                */
+               if (rem && k > 0)
+                       lower = src[k - 1];
+               else
+                       lower = 0;
+               upper = src[k];
+               if (left && k == lim - 1)
+                       upper &= (1UL << left) - 1;
+               dst[k + off] = lower  >> (BITS_PER_LONG - rem) | upper << rem;
+               if (left && k + off == lim - 1)
+                       dst[k + off] &= (1UL << left) - 1;
+       }
+       if (off)
+               memset(dst, 0, off*sizeof(unsigned long));
+}
+EXPORT_SYMBOL(__bitmap_shift_left);
+
+void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                               const unsigned long *bitmap2, int bits)
+{
+       int k;
+       int nr = BITS_TO_LONGS(bits);
+
+       for (k = 0; k < nr; k++)
+               dst[k] = bitmap1[k] & bitmap2[k];
+}
+EXPORT_SYMBOL(__bitmap_and);
+
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+                               const unsigned long *bitmap2, int bits)
+{
+       int k;
+       int nr = BITS_TO_LONGS(bits);
+
+       for (k = 0; k < nr; k++)
+               dst[k] = bitmap1[k] | bitmap2[k];
+}
+EXPORT_SYMBOL(__bitmap_or);
+
+void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+                               const unsigned long *bitmap2, int bits)
+{
+       int k;
+       int nr = BITS_TO_LONGS(bits);
+
+       for (k = 0; k < nr; k++)
+               dst[k] = bitmap1[k] ^ bitmap2[k];
+}
+EXPORT_SYMBOL(__bitmap_xor);
+
+void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+                               const unsigned long *bitmap2, int bits)
+{
+       int k;
+       int nr = BITS_TO_LONGS(bits);
+
+       for (k = 0; k < nr; k++)
+               dst[k] = bitmap1[k] & ~bitmap2[k];
+}
+EXPORT_SYMBOL(__bitmap_andnot);
+
+int __bitmap_intersects(const unsigned long *bitmap1,
+                               const unsigned long *bitmap2, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (bitmap1[k] & bitmap2[k])
+                       return 1;
+
+       if (bits % BITS_PER_LONG)
+               if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
+                       return 1;
+       return 0;
+}
+EXPORT_SYMBOL(__bitmap_intersects);
+
+int __bitmap_subset(const unsigned long *bitmap1,
+                               const unsigned long *bitmap2, int bits)
+{
+       int k, lim = bits/BITS_PER_LONG;
+       for (k = 0; k < lim; ++k)
+               if (bitmap1[k] & ~bitmap2[k])
+                       return 0;
+
+       if (bits % BITS_PER_LONG)
+               if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
+                       return 0;
+       return 1;
+}
+EXPORT_SYMBOL(__bitmap_subset);
+
+int __bitmap_weight(const unsigned long *bitmap, int bits)
+{
+       int k, w = 0, lim = bits/BITS_PER_LONG;
+
+       for (k = 0; k < lim; k++)
+               w += hweight_long(bitmap[k]);
+
+       if (bits % BITS_PER_LONG)
+               w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
+
+       return w;
+}
+EXPORT_SYMBOL(__bitmap_weight);
+
+/*
+ * Bitmap printing & parsing functions: first version by Bill Irwin,
+ * second version by Paul Jackson, third by Joe Korty.
+ */
+
+#define CHUNKSZ                                32
+#define nbits_to_hold_value(val)       fls(val)
+#define unhex(c)                       (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
+#define BASEDEC 10             /* fancier cpuset lists input in decimal */
+
+/**
+ * bitmap_scnprintf - convert bitmap to an ASCII hex string.
+ * @buf: byte buffer into which string is placed
+ * @buflen: reserved size of @buf, in bytes
+ * @maskp: pointer to bitmap to convert
+ * @nmaskbits: size of bitmap, in bits
+ *
+ * Exactly @nmaskbits bits are displayed.  Hex digits are grouped into
+ * comma-separated sets of eight digits per set.
+ */
+int bitmap_scnprintf(char *buf, unsigned int buflen,
+       const unsigned long *maskp, int nmaskbits)
+{
+       int i, word, bit, len = 0;
+       unsigned long val;
+       const char *sep = "";
+       int chunksz;
+       u32 chunkmask;
+
+       chunksz = nmaskbits & (CHUNKSZ - 1);
+       if (chunksz == 0)
+               chunksz = CHUNKSZ;
+
+       i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ;
+       for (; i >= 0; i -= CHUNKSZ) {
+               chunkmask = ((1ULL << chunksz) - 1);
+               word = i / BITS_PER_LONG;
+               bit = i % BITS_PER_LONG;
+               val = (maskp[word] >> bit) & chunkmask;
+               len += scnprintf(buf+len, buflen-len, "%s%0*lx", sep,
+                       (chunksz+3)/4, val);
+               chunksz = CHUNKSZ;
+               sep = ",";
+       }
+       return len;
+}
+EXPORT_SYMBOL(bitmap_scnprintf);
+
+#if 0
+/**
+ * bitmap_parse - convert an ASCII hex string into a bitmap.
+ * @buf: pointer to buffer in user space containing string.
+ * @buflen: buffer size in bytes.  If string is smaller than this
+ *    then it must be terminated with a \0.
+ * @maskp: pointer to bitmap array that will contain result.
+ * @nmaskbits: size of bitmap, in bits.
+ *
+ * Commas group hex digits into chunks.  Each chunk defines exactly 32
+ * bits of the resultant bitmask.  No chunk may specify a value larger
+ * than 32 bits (-EOVERFLOW), and if a chunk specifies a smaller value
+ * then leading 0-bits are prepended.  -EINVAL is returned for illegal
+ * characters and for grouping errors such as "1,,5", ",44", "," and "".
+ * Leading and trailing whitespace accepted, but not embedded whitespace.
+ */
+int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
+        unsigned long *maskp, int nmaskbits)
+{
+       int c, old_c, totaldigits, ndigits, nchunks, nbits;
+       u32 chunk;
+
+       bitmap_zero(maskp, nmaskbits);
+
+       nchunks = nbits = totaldigits = c = 0;
+       do {
+               chunk = ndigits = 0;
+
+               /* Get the next chunk of the bitmap */
+               while (ubuflen) {
+                       old_c = c;
+                       if (get_user(c, ubuf++))
+                               return -EFAULT;
+                       ubuflen--;
+                       if (isspace(c))
+                               continue;
+
+                       /*
+                        * If the last character was a space and the current
+                        * character isn't '\0', we've got embedded whitespace.
+                        * This is a no-no, so throw an error.
+                        */
+                       if (totaldigits && c && isspace(old_c))
+                               return -EINVAL;
+
+                       /* A '\0' or a ',' signal the end of the chunk */
+                       if (c == '\0' || c == ',')
+                               break;
+
+                       if (!isxdigit(c))
+                               return -EINVAL;
+
+                       /*
+                        * Make sure there are at least 4 free bits in 'chunk'.
+                        * If not, this hexdigit will overflow 'chunk', so
+                        * throw an error.
+                        */
+                       if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1))
+                               return -EOVERFLOW;
+
+                       chunk = (chunk << 4) | unhex(c);
+                       ndigits++; totaldigits++;
+               }
+               if (ndigits == 0)
+                       return -EINVAL;
+               if (nchunks == 0 && chunk == 0)
+                       continue;
+
+               __bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits);
+               *maskp |= chunk;
+               nchunks++;
+               nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
+               if (nbits > nmaskbits)
+                       return -EOVERFLOW;
+       } while (ubuflen && c == ',');
+
+       return 0;
+}
+EXPORT_SYMBOL(bitmap_parse);
+#endif
+
+/*
+ * bscnl_emit(buf, buflen, rbot, rtop, bp)
+ *
+ * Helper routine for bitmap_scnlistprintf().  Write decimal number
+ * or range to buf, suppressing output past buf+buflen, with optional
+ * comma-prefix.  Return len of what would be written to buf, if it
+ * all fit.
+ */
+static inline int bscnl_emit(char *buf, int buflen, int rbot, int rtop, int len)
+{
+       if (len > 0)
+               len += scnprintf(buf + len, buflen - len, ",");
+       if (rbot == rtop)
+               len += scnprintf(buf + len, buflen - len, "%d", rbot);
+       else
+               len += scnprintf(buf + len, buflen - len, "%d-%d", rbot, rtop);
+       return len;
+}
+
+/**
+ * bitmap_scnlistprintf - convert bitmap to list format ASCII string
+ * @buf: byte buffer into which string is placed
+ * @buflen: reserved size of @buf, in bytes
+ * @maskp: pointer to bitmap to convert
+ * @nmaskbits: size of bitmap, in bits
+ *
+ * Output format is a comma-separated list of decimal numbers and
+ * ranges.  Consecutively set bits are shown as two hyphen-separated
+ * decimal numbers, the smallest and largest bit numbers set in
+ * the range.  Output format is compatible with the format
+ * accepted as input by bitmap_parselist().
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing '\0', as
+ * per ISO C99.
+ */
+int bitmap_scnlistprintf(char *buf, unsigned int buflen,
+       const unsigned long *maskp, int nmaskbits)
+{
+       int len = 0;
+       /* current bit is 'cur', most recently seen range is [rbot, rtop] */
+       int cur, rbot, rtop;
+
+       rbot = cur = find_first_bit(maskp, nmaskbits);
+       while (cur < nmaskbits) {
+               rtop = cur;
+               cur = find_next_bit(maskp, nmaskbits, cur+1);
+               if (cur >= nmaskbits || cur > rtop + 1) {
+                       len = bscnl_emit(buf, buflen, rbot, rtop, len);
+                       rbot = cur;
+               }
+       }
+       return len;
+}
+EXPORT_SYMBOL(bitmap_scnlistprintf);
+
+/**
+ * bitmap_parselist - convert list format ASCII string to bitmap
+ * @buf: read nul-terminated user string from this buffer
+ * @mask: write resulting mask here
+ * @nmaskbits: number of bits in mask to be written
+ *
+ * Input format is a comma-separated list of decimal numbers and
+ * ranges.  Consecutively set bits are shown as two hyphen-separated
+ * decimal numbers, the smallest and largest bit numbers set in
+ * the range.
+ *
+ * Returns 0 on success, -errno on invalid input strings:
+ *    -EINVAL:   second number in range smaller than first
+ *    -EINVAL:   invalid character in string
+ *    -ERANGE:   bit number specified too large for mask
+ */
+int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
+{
+       unsigned a, b;
+
+       bitmap_zero(maskp, nmaskbits);
+       do {
+               if (!isdigit(*bp))
+                       return -EINVAL;
+               b = a = simple_strtoul(bp, (char **)&bp, BASEDEC);
+               if (*bp == '-') {
+                       bp++;
+                       if (!isdigit(*bp))
+                               return -EINVAL;
+                       b = simple_strtoul(bp, (char **)&bp, BASEDEC);
+               }
+               if (!(a <= b))
+                       return -EINVAL;
+               if (b >= nmaskbits)
+                       return -ERANGE;
+               while (a <= b) {
+                       set_bit(a, maskp);
+                       a++;
+               }
+               if (*bp == ',')
+                       bp++;
+       } while (*bp != '\0' && *bp != '\n');
+       return 0;
+}
+EXPORT_SYMBOL(bitmap_parselist);
+
+/*
+ * bitmap_pos_to_ord(buf, pos, bits)
+ *     @buf: pointer to a bitmap
+ *     @pos: a bit position in @buf (0 <= @pos < @bits)
+ *     @bits: number of valid bit positions in @buf
+ *
+ * Map the bit at position @pos in @buf (of length @bits) to the
+ * ordinal of which set bit it is.  If it is not set or if @pos
+ * is not a valid bit position, map to -1.
+ *
+ * If for example, just bits 4 through 7 are set in @buf, then @pos
+ * values 4 through 7 will get mapped to 0 through 3, respectively,
+ * and other @pos values will get mapped to 0.  When @pos value 7
+ * gets mapped to (returns) @ord value 3 in this example, that means
+ * that bit 7 is the 3rd (starting with 0th) set bit in @buf.
+ *
+ * The bit positions 0 through @bits are valid positions in @buf.
+ */
+static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits)
+{
+       int i, ord;
+
+       if (pos < 0 || pos >= bits || !test_bit(pos, buf))
+               return -1;
+
+       i = find_first_bit(buf, bits);
+       ord = 0;
+       while (i < pos) {
+               i = find_next_bit(buf, bits, i + 1);
+               ord++;
+       }
+       BUG_ON(i != pos);
+
+       return ord;
+}
+
+/**
+ * bitmap_ord_to_pos(buf, ord, bits)
+ *     @buf: pointer to bitmap
+ *     @ord: ordinal bit position (n-th set bit, n >= 0)
+ *     @bits: number of valid bit positions in @buf
+ *
+ * Map the ordinal offset of bit @ord in @buf to its position in @buf.
+ * Value of @ord should be in range 0 <= @ord < weight(buf), else
+ * results are undefined.
+ *
+ * If for example, just bits 4 through 7 are set in @buf, then @ord
+ * values 0 through 3 will get mapped to 4 through 7, respectively,
+ * and all other @ord values return undefined values.  When @ord value 3
+ * gets mapped to (returns) @pos value 7 in this example, that means
+ * that the 3rd set bit (starting with 0th) is at position 7 in @buf.
+ *
+ * The bit positions 0 through @bits are valid positions in @buf.
+ */
+static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
+{
+       int pos = 0;
+
+       if (ord >= 0 && ord < bits) {
+               int i;
+
+               for (i = find_first_bit(buf, bits);
+                    i < bits && ord > 0;
+                    i = find_next_bit(buf, bits, i + 1))
+                       ord--;
+               if (i < bits && ord == 0)
+                       pos = i;
+       }
+
+       return pos;
+}
+
+/**
+ * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap
+ *     @dst: remapped result
+ *     @src: subset to be remapped
+ *     @old: defines domain of map
+ *     @new: defines range of map
+ *     @bits: number of bits in each of these bitmaps
+ *
+ * Let @old and @new define a mapping of bit positions, such that
+ * whatever position is held by the n-th set bit in @old is mapped
+ * to the n-th set bit in @new.  In the more general case, allowing
+ * for the possibility that the weight 'w' of @new is less than the
+ * weight of @old, map the position of the n-th set bit in @old to
+ * the position of the m-th set bit in @new, where m == n % w.
+ *
+ * If either of the @old and @new bitmaps are empty, or if @src and
+ * @dst point to the same location, then this routine copies @src
+ * to @dst.
+ *
+ * The positions of unset bits in @old are mapped to themselves
+ * (the identify map).
+ *
+ * Apply the above specified mapping to @src, placing the result in
+ * @dst, clearing any bits previously set in @dst.
+ *
+ * For example, lets say that @old has bits 4 through 7 set, and
+ * @new has bits 12 through 15 set.  This defines the mapping of bit
+ * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other
+ * bit positions unchanged.  So if say @src comes into this routine
+ * with bits 1, 5 and 7 set, then @dst should leave with bits 1,
+ * 13 and 15 set.
+ */
+void bitmap_remap(unsigned long *dst, const unsigned long *src,
+               const unsigned long *old, const unsigned long *new,
+               int bits)
+{
+       int oldbit, w;
+
+       if (dst == src)         /* following doesn't handle inplace remaps */
+               return;
+       bitmap_zero(dst, bits);
+
+       w = bitmap_weight(new, bits);
+       for (oldbit = find_first_bit(src, bits);
+            oldbit < bits;
+            oldbit = find_next_bit(src, bits, oldbit + 1)) {
+               int n = bitmap_pos_to_ord(old, oldbit, bits);
+               if (n < 0 || w == 0)
+                       set_bit(oldbit, dst);   /* identity map */
+               else
+                       set_bit(bitmap_ord_to_pos(new, n % w, bits), dst);
+       }
+}
+EXPORT_SYMBOL(bitmap_remap);
+
+/**
+ * bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit
+ *     @oldbit - bit position to be mapped
+ *      @old: defines domain of map
+ *      @new: defines range of map
+ *      @bits: number of bits in each of these bitmaps
+ *
+ * Let @old and @new define a mapping of bit positions, such that
+ * whatever position is held by the n-th set bit in @old is mapped
+ * to the n-th set bit in @new.  In the more general case, allowing
+ * for the possibility that the weight 'w' of @new is less than the
+ * weight of @old, map the position of the n-th set bit in @old to
+ * the position of the m-th set bit in @new, where m == n % w.
+ *
+ * The positions of unset bits in @old are mapped to themselves
+ * (the identify map).
+ *
+ * Apply the above specified mapping to bit position @oldbit, returning
+ * the new bit position.
+ *
+ * For example, lets say that @old has bits 4 through 7 set, and
+ * @new has bits 12 through 15 set.  This defines the mapping of bit
+ * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other
+ * bit positions unchanged.  So if say @oldbit is 5, then this routine
+ * returns 13.
+ */
+int bitmap_bitremap(int oldbit, const unsigned long *old,
+                               const unsigned long *new, int bits)
+{
+       int w = bitmap_weight(new, bits);
+       int n = bitmap_pos_to_ord(old, oldbit, bits);
+       if (n < 0 || w == 0)
+               return oldbit;
+       else
+               return bitmap_ord_to_pos(new, n % w, bits);
+}
+EXPORT_SYMBOL(bitmap_bitremap);
+
+/*
+ * Common code for bitmap_*_region() routines.
+ *     bitmap: array of unsigned longs corresponding to the bitmap
+ *     pos: the beginning of the region
+ *     order: region size (log base 2 of number of bits)
+ *     reg_op: operation(s) to perform on that region of bitmap
+ *
+ * Can set, verify and/or release a region of bits in a bitmap,
+ * depending on which combination of REG_OP_* flag bits is set.
+ *
+ * A region of a bitmap is a sequence of bits in the bitmap, of
+ * some size '1 << order' (a power of two), aligned to that same
+ * '1 << order' power of two.
+ *
+ * Returns 1 if REG_OP_ISFREE succeeds (region is all zero bits).
+ * Returns 0 in all other cases and reg_ops.
+ */
+
+enum {
+       REG_OP_ISFREE,          /* true if region is all zero bits */
+       REG_OP_ALLOC,           /* set all bits in region */
+       REG_OP_RELEASE,         /* clear all bits in region */
+};
+
+static int __reg_op(unsigned long *bitmap, int pos, int order, int reg_op)
+{
+       int nbits_reg;          /* number of bits in region */
+       int index;              /* index first long of region in bitmap */
+       int offset;             /* bit offset region in bitmap[index] */
+       int nlongs_reg;         /* num longs spanned by region in bitmap */
+       int nbitsinlong;        /* num bits of region in each spanned long */
+       unsigned long mask;     /* bitmask for one long of region */
+       int i;                  /* scans bitmap by longs */
+       int ret = 0;            /* return value */
+
+       /*
+        * Either nlongs_reg == 1 (for small orders that fit in one long)
+        * or (offset == 0 && mask == ~0UL) (for larger multiword orders.)
+        */
+       nbits_reg = 1 << order;
+       index = pos / BITS_PER_LONG;
+       offset = pos - (index * BITS_PER_LONG);
+       nlongs_reg = BITS_TO_LONGS(nbits_reg);
+       nbitsinlong = min(nbits_reg,  BITS_PER_LONG);
+
+       /*
+        * Can't do "mask = (1UL << nbitsinlong) - 1", as that
+        * overflows if nbitsinlong == BITS_PER_LONG.
+        */
+       mask = (1UL << (nbitsinlong - 1));
+       mask += mask - 1;
+       mask <<= offset;
+
+       switch (reg_op) {
+       case REG_OP_ISFREE:
+               for (i = 0; i < nlongs_reg; i++) {
+                       if (bitmap[index + i] & mask)
+                               goto done;
+               }
+               ret = 1;        /* all bits in region free (zero) */
+               break;
+
+       case REG_OP_ALLOC:
+               for (i = 0; i < nlongs_reg; i++)
+                       bitmap[index + i] |= mask;
+               break;
+
+       case REG_OP_RELEASE:
+               for (i = 0; i < nlongs_reg; i++)
+                       bitmap[index + i] &= ~mask;
+               break;
+       }
+done:
+       return ret;
+}
+
+/**
+ * bitmap_find_free_region - find a contiguous aligned mem region
+ *     @bitmap: array of unsigned longs corresponding to the bitmap
+ *     @bits: number of bits in the bitmap
+ *     @order: region size (log base 2 of number of bits) to find
+ *
+ * Find a region of free (zero) bits in a @bitmap of @bits bits and
+ * allocate them (set them to one).  Only consider regions of length
+ * a power (@order) of two, aligned to that power of two, which
+ * makes the search algorithm much faster.
+ *
+ * Return the bit offset in bitmap of the allocated region,
+ * or -errno on failure.
+ */
+int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
+{
+       int pos;                /* scans bitmap by regions of size order */
+
+       for (pos = 0; pos < bits; pos += (1 << order))
+               if (__reg_op(bitmap, pos, order, REG_OP_ISFREE))
+                       break;
+       if (pos == bits)
+               return -ENOMEM;
+       __reg_op(bitmap, pos, order, REG_OP_ALLOC);
+       return pos;
+}
+EXPORT_SYMBOL(bitmap_find_free_region);
+
+/**
+ * bitmap_release_region - release allocated bitmap region
+ *     @bitmap: array of unsigned longs corresponding to the bitmap
+ *     @pos: beginning of bit region to release
+ *     @order: region size (log base 2 of number of bits) to release
+ *
+ * This is the complement to __bitmap_find_free_region and releases
+ * the found region (by clearing it in the bitmap).
+ *
+ * No return value.
+ */
+void bitmap_release_region(unsigned long *bitmap, int pos, int order)
+{
+       __reg_op(bitmap, pos, order, REG_OP_RELEASE);
+}
+EXPORT_SYMBOL(bitmap_release_region);
+
+/**
+ * bitmap_allocate_region - allocate bitmap region
+ *     @bitmap: array of unsigned longs corresponding to the bitmap
+ *     @pos: beginning of bit region to allocate
+ *     @order: region size (log base 2 of number of bits) to allocate
+ *
+ * Allocate (set bits in) a specified region of a bitmap.
+ *
+ * Return 0 on success, or -EBUSY if specified region wasn't
+ * free (not all bits were zero).
+ */
+int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
+{
+       if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE))
+               return -EBUSY;
+       __reg_op(bitmap, pos, order, REG_OP_ALLOC);
+       return 0;
+}
+EXPORT_SYMBOL(bitmap_allocate_region);
diff --git a/kitten/lib/cmdline.c b/kitten/lib/cmdline.c
new file mode 100644 (file)
index 0000000..cbbce00
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * linux/lib/cmdline.c
+ * Helper functions generally used for parsing kernel command line
+ * and module options.
+ *
+ * Code and copyrights come from init/main.c and arch/i386/kernel/setup.c.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ *
+ * GNU Indent formatting options for this file: -kr -i8 -npsl -pcs
+ *
+ */
+
+#include <lwk/kernel.h>
+#include <lwk/string.h>
+#include <lwk/linux_compat.h>
+
+
+/**
+ *     get_option - Parse integer from an option string
+ *     @str: option string
+ *     @pint: (output) integer value parsed from @str
+ *
+ *     Read an int from an option string; if available accept a subsequent
+ *     comma as well.
+ *
+ *     Return values:
+ *     0 : no int in string
+ *     1 : int found, no subsequent comma
+ *     2 : int found including a subsequent comma
+ */
+
+int get_option (char **str, int *pint)
+{
+       char *cur = *str;
+
+       if (!cur || !(*cur))
+               return 0;
+       *pint = simple_strtol (cur, str, 0);
+       if (cur == *str)
+               return 0;
+       if (**str == ',') {
+               (*str)++;
+               return 2;
+       }
+
+       return 1;
+}
+
+/**
+ *     get_options - Parse a string into a list of integers
+ *     @str: String to be parsed
+ *     @nints: size of integer array
+ *     @ints: integer array
+ *
+ *     This function parses a string containing a comma-separated
+ *     list of integers.  The parse halts when the array is
+ *     full, or when no more numbers can be retrieved from the
+ *     string.
+ *
+ *     Return value is the character in the string which caused
+ *     the parse to end (typically a null terminator, if @str is
+ *     completely parseable).
+ */
+char *get_options(const char *str, int nints, int *ints)
+{
+       int res, i = 1;
+
+       while (i < nints) {
+               res = get_option ((char **)&str, ints + i);
+               if (res == 0)
+                       break;
+               i++;
+               if (res == 1)
+                       break;
+       }
+       ints[0] = i - 1;
+       return (char *)str;
+}
+
+/**
+ *     memparse - parse a string with mem suffixes into a number
+ *     @ptr: Where parse begins
+ *     @retptr: (output) Pointer to next char after parse completes
+ *
+ *     Parses a string into a number.  The number stored at @ptr is
+ *     potentially suffixed with %K (for kilobytes, or 1024 bytes),
+ *     %M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or
+ *     1073741824).  If the number is suffixed with K, M, or G, then
+ *     the return value is the number multiplied by one kilobyte, one
+ *     megabyte, or one gigabyte, respectively.
+ */
+
+unsigned long long memparse (char *ptr, char **retptr)
+{
+       unsigned long long ret = simple_strtoull (ptr, retptr, 0);
+
+       switch (**retptr) {
+       case 'G':
+       case 'g':
+               ret <<= 10;
+       case 'M':
+       case 'm':
+               ret <<= 10;
+       case 'K':
+       case 'k':
+               ret <<= 10;
+               (*retptr)++;
+       default:
+               break;
+       }
+       return ret;
+}
+
+
+EXPORT_SYMBOL(memparse);
+EXPORT_SYMBOL(get_option);
+EXPORT_SYMBOL(get_options);
diff --git a/kitten/lib/cpumask.c b/kitten/lib/cpumask.c
new file mode 100644 (file)
index 0000000..1387f12
--- /dev/null
@@ -0,0 +1,40 @@
+#include <lwk/kernel.h>
+#include <lwk/bitops.h>
+#include <lwk/cpumask.h>
+
+int __first_cpu(const cpumask_t *srcp)
+{
+       return min_t(int, NR_CPUS, find_first_bit(srcp->bits, NR_CPUS));
+}
+
+int __next_cpu(int n, const cpumask_t *srcp)
+{
+       return min_t(int, NR_CPUS, find_next_bit(srcp->bits, NR_CPUS, n+1));
+}
+
+/*
+ * Find the highest possible smp_cpu_id()
+ *
+ * Note: if we're prepared to assume that cpu_possible_map never changes
+ * (reasonable) then this function should cache its return value.
+ */
+int highest_possible_cpu_id(void)
+{
+       unsigned int cpu;
+       unsigned highest = 0;
+
+       for_each_cpu_mask(cpu, cpu_present_map)
+               highest = cpu;
+       return highest;
+}
+
+int __any_online_cpu(const cpumask_t *mask)
+{
+       int cpu;
+
+       for_each_cpu_mask(cpu, *mask) {
+               if (cpu_online(cpu))
+                       break;
+       }
+       return cpu;
+}
diff --git a/kitten/lib/ctype.c b/kitten/lib/ctype.c
new file mode 100644 (file)
index 0000000..3ece18a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  linux/lib/ctype.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <lwk/ctype.h>
+#include <lwk/linux_compat.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,                   /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,                       /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,                       /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,                       /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,     /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,                       /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,                       /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,                       /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,     /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,                       /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,                       /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,                       /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
+
+EXPORT_SYMBOL(_ctype);
diff --git a/kitten/lib/extable.c b/kitten/lib/extable.c
new file mode 100644 (file)
index 0000000..ddaf960
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c.
+ *
+ * Copyright (C) 2004 Paul Mackerras, IBM Corp.
+ *
+ * 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.
+ */
+
+#include <lwk/init.h>
+#include <lwk/sort.h>
+#include <lwk/extable.h>
+
+#ifndef ARCH_HAS_SORT_EXTABLE
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ */
+static int cmp_ex(const void *a, const void *b)
+{
+       const struct exception_table_entry *x = a, *y = b;
+
+       /* avoid overflow */
+       if (x->insn > y->insn)
+               return 1;
+       if (x->insn < y->insn)
+               return -1;
+       return 0;
+}
+
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
+{
+       sort(start, finish - start, sizeof(struct exception_table_entry),
+            cmp_ex, NULL);
+}
+#endif
+
+#ifndef ARCH_HAS_SEARCH_EXTABLE
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+              const struct exception_table_entry *last,
+              unsigned long value)
+{
+       while (first <= last) {
+               const struct exception_table_entry *mid;
+
+               mid = (last - first) / 2 + first;
+               /*
+                * careful, the distance between entries can be
+                * larger than 2GB:
+                */
+               if (mid->insn < value)
+                       first = mid + 1;
+               else if (mid->insn > value)
+                       last = mid - 1;
+               else
+                       return mid;
+        }
+        return NULL;
+}
+#endif
diff --git a/kitten/lib/hweight.c b/kitten/lib/hweight.c
new file mode 100644 (file)
index 0000000..3d06cff
--- /dev/null
@@ -0,0 +1,53 @@
+#include <lwk/linux_compat.h>
+#include <arch/types.h>
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+unsigned int hweight32(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55555555);
+       res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+       res = (res + (res >> 4)) & 0x0F0F0F0F;
+       res = res + (res >> 8);
+       return (res + (res >> 16)) & 0x000000FF;
+}
+EXPORT_SYMBOL(hweight32);
+
+unsigned int hweight16(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x5555);
+       res = (res & 0x3333) + ((res >> 2) & 0x3333);
+       res = (res + (res >> 4)) & 0x0F0F;
+       return (res + (res >> 8)) & 0x00FF;
+}
+EXPORT_SYMBOL(hweight16);
+
+unsigned int hweight8(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55);
+       res = (res & 0x33) + ((res >> 2) & 0x33);
+       return (res + (res >> 4)) & 0x0F;
+}
+EXPORT_SYMBOL(hweight8);
+
+unsigned long hweight64(__u64 w)
+{
+#if BITS_PER_LONG == 32
+       return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+#elif BITS_PER_LONG == 64
+       __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
+       res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
+       res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
+       res = res + (res >> 8);
+       res = res + (res >> 16);
+       return (res + (res >> 32)) & 0x00000000000000FFul;
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+EXPORT_SYMBOL(hweight64);
diff --git a/kitten/lib/inflate.c b/kitten/lib/inflate.c
new file mode 100644 (file)
index 0000000..f47ed8a
--- /dev/null
@@ -0,0 +1,1265 @@
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+   version c10p1, 10 January 1993 */
+
+/* 
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3 
+ *
+ * Nicolas Pitre <nico@cam.org>, 1999/04/14 :
+ *   Little mods for all variable to reside either into rodata or bss segments
+ *   by marking constant variables with 'const' and initializing all the others
+ *   at run-time only.  This allows for the kernel uncompressor to run
+ *   directly from Flash or ROM memory on embedded systems.
+ */
+
+/*
+   Inflate deflated (PKZIP's method 8 compressed) data.  The compression
+   method searches for as much of the current string of bytes (up to a
+   length of 258) in the previous 32 K bytes.  If it doesn't find any
+   matches (of at least length 3), it codes the next byte.  Otherwise, it
+   codes the length of the matched string and its distance backwards from
+   the current position.  There is a single Huffman code that codes both
+   single bytes (called "literals") and match lengths.  A second Huffman
+   code codes the distance information, which follows a length code.  Each
+   length or distance code actually represents a base value and a number
+   of "extra" (sometimes zero) bits to get to add to the base value.  At
+   the end of each deflated block is a special end-of-block (EOB) literal/
+   length code.  The decoding process is basically: get a literal/length
+   code; if EOB then done; if a literal, emit the decoded byte; if a
+   length then get the distance and emit the referred-to bytes from the
+   sliding window of previously emitted data.
+
+   There are (currently) three kinds of inflate blocks: stored, fixed, and
+   dynamic.  The compressor deals with some chunk of data at a time, and
+   decides which method to use on a chunk-by-chunk basis.  A chunk might
+   typically be 32 K or 64 K.  If the chunk is incompressible, then the
+   "stored" method is used.  In this case, the bytes are simply stored as
+   is, eight bits per byte, with none of the above coding.  The bytes are
+   preceded by a count, since there is no longer an EOB code.
+
+   If the data is compressible, then either the fixed or dynamic methods
+   are used.  In the dynamic method, the compressed data is preceded by
+   an encoding of the literal/length and distance Huffman codes that are
+   to be used to decode this block.  The representation is itself Huffman
+   coded, and so is preceded by a description of that code.  These code
+   descriptions take up a little space, and so for small blocks, there is
+   a predefined set of codes, called the fixed codes.  The fixed method is
+   used if the block codes up smaller that way (usually for quite small
+   chunks), otherwise the dynamic method is used.  In the latter case, the
+   codes are customized to the probabilities in the current block, and so
+   can code it much better than the pre-determined fixed codes.
+   The Huffman codes themselves are decoded using a multi-level table
+   lookup, in order to maximize the speed of decoding plus the speed of
+   building the decoding tables.  See the comments below that precede the
+   lbits and dbits tuning parameters.
+ */
+
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarly, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+#include <lwk/compiler.h>
+
+#ifdef RCSID
+static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
+#endif
+
+#ifndef STATIC
+
+#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
+#  include <sys/types.h>
+#  include <stdlib.h>
+#endif
+
+#include "gzip.h"
+#define STATIC
+#endif /* !STATIC */
+
+#ifndef INIT
+#define INIT
+#endif
+       
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model).
+   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
+   means that v is a literal, 16 < e < 32 means that v is a pointer to
+   the next table, which codes e - 16 bits, and lastly e == 99 indicates
+   an unused code.  If a code with e == 99 is looked up, this implies an
+   error in the data. */
+struct huft {
+  uch e;                /* number of extra bits or operation */
+  uch b;                /* number of bits in this code or subcode */
+  union {
+    ush n;              /* literal, length base, or distance base */
+    struct huft *t;     /* pointer to next level of table */
+  } v;
+};
+
+
+/* Function prototypes */
+STATIC int INIT huft_build OF((unsigned *, unsigned, unsigned, 
+               const ush *, const ush *, struct huft **, int *));
+STATIC int INIT huft_free OF((struct huft *));
+STATIC int INIT inflate_codes OF((struct huft *, struct huft *, int, int));
+STATIC int INIT inflate_stored OF((void));
+STATIC int INIT inflate_fixed OF((void));
+STATIC int INIT inflate_dynamic OF((void));
+STATIC int INIT inflate_block OF((int *));
+STATIC int INIT inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed
+   stream to find repeated byte strings.  This is implemented here as a
+   circular buffer.  The index is updated simply by incrementing and then
+   ANDing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32 K area.  It is assumed
+   to be usable as if it were declared "uch slide[32768];" or as just
+   "uch *slide;" and then malloc'ed in the latter case.  The definition
+   must be in unzip.h, included above. */
+/* unsigned wp;             current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static const unsigned border[] = {    /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static const ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+static const ush cplext[] = {         /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static const ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+static const ush cpdext[] = {         /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+   
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed, and are initialized at the beginning of a
+   routine that uses these macros from a global bit buffer and count.
+
+   If we assume that EOB will be the longest code, then we will never
+   ask for bits with NEEDBITS that are beyond the end of the stream.
+   So, NEEDBITS should not read any more bytes than are needed to
+   meet the request.  Then no bytes need to be "returned" to the buffer
+   at the end of the last block.
+
+   However, this assumption is not true for fixed blocks--the EOB code
+   is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+   (The EOB code is shorter than other codes because fixed blocks are
+   generally short.  So, while a block always has an EOB, many other
+   literal/length codes have a significantly lower probability of
+   showing up at all.)  However, by making the first table have a
+   lookup of seven bits, the EOB code will be found in that first
+   lookup, and so will not require that too many bits be pulled from
+   the stream.
+ */
+
+STATIC ulg bb;                         /* bit buffer */
+STATIC unsigned bk;                    /* bits in bit buffer */
+
+STATIC const ush mask_bits[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEXTBYTE()  ({ int v = get_byte(); if (v < 0) goto underrun; (uch)v; })
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+STATIC const int lbits = 9;          /* bits in base literal/length lookup table */
+STATIC const int dbits = 6;          /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16         /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+
+STATIC unsigned hufts;         /* track memory usage */
+
+
+STATIC int INIT huft_build(
+       unsigned *b,            /* code lengths in bits (all assumed <= BMAX) */
+       unsigned n,             /* number of codes (assumed <= N_MAX) */
+       unsigned s,             /* number of simple-valued codes (0..s-1) */
+       const ush *d,           /* list of base values for non-simple codes */
+       const ush *e,           /* list of extra bits for non-simple codes */
+       struct huft **t,        /* result: starting table */
+       int *m                  /* maximum lookup bits, returns actual */
+       )
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory. */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+  struct {
+    unsigned c[BMAX+1];           /* bit length count table */
+    struct huft *u[BMAX];         /* table stack */
+    unsigned v[N_MAX];            /* values in order of bit length */
+    unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  } *stk;
+  unsigned *c, *v, *x;
+  struct huft **u;
+  int ret;
+
+DEBG("huft1 ");
+
+  stk = malloc(sizeof(*stk));
+  if (stk == NULL)
+    return 3;                  /* out of memory */
+
+  c = stk->c;
+  v = stk->v;
+  x = stk->x;
+  u = stk->u;
+
+  /* Generate counts for each bit length */
+  memzero(stk->c, sizeof(stk->c));
+  p = b;  i = n;
+  do {
+    Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), 
+           n-i, *p));
+    c[*p]++;                    /* assume all entries <= BMAX */
+    p++;                      /* Can't combine with above line (Solaris bug) */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (struct huft *)NULL;
+    *m = 0;
+    ret = 2;
+    goto out;
+  }
+
+DEBG("huft2 ");
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned)l > i)
+    l = i;
+  *m = l;
+
+DEBG("huft3 ");
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0) {
+      ret = 2;                 /* bad input: more codes than bits */
+      goto out;
+    }
+  if ((y -= c[i]) < 0) {
+    ret = 2;
+    goto out;
+  }
+  c[i] += y;
+
+DEBG("huft4 ");
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+DEBG("huft5 ");
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                   /* set n to length of v */
+
+DEBG("h6 ");
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
+  q = (struct huft *)NULL;      /* ditto */
+  z = 0;                        /* ditto */
+DEBG("h6a ");
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+DEBG("h6b ");
+    a = c[k];
+    while (a--)
+    {
+DEBG("h6b1 ");
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+DEBG1("1 ");
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+DEBG1("2 ");
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)       /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;            /* enough codes to use up j bits */
+              f -= *xp;           /* else deduct codes from patterns */
+            }
+        }
+DEBG1("3 ");
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+            (struct huft *)NULL)
+        {
+          if (h)
+            huft_free(u[0]);
+          ret = 3;             /* not enough memory */
+         goto out;
+        }
+DEBG1("4 ");
+        hufts += z + 1;         /* track memory usage */
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->v.t)) = (struct huft *)NULL;
+        u[h] = ++q;             /* table starts after link */
+
+DEBG1("5 ");
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.b = (uch)l;         /* bits to dump before this table */
+          r.e = (uch)(16 + j);  /* bits in this table */
+          r.v.t = q;            /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+DEBG1("6 ");
+      }
+DEBG("h6c ");
+
+      /* set up table entry in r */
+      r.b = (uch)(k - w);
+      if (p >= v + n)
+        r.e = 99;               /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
+        r.v.n = (ush)(*p);             /* simple code is just the value */
+       p++;                           /* one compiler does not like *p++ */
+      }
+      else
+      {
+        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
+        r.v.n = d[*p++ - s];
+      }
+DEBG("h6d ");
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+DEBG("h6e ");
+    }
+DEBG("h6f ");
+  }
+
+DEBG("huft7 ");
+
+  /* Return true (1) if we were given an incomplete table */
+  ret = y != 0 && g != 1;
+
+  out:
+  free(stk);
+  return ret;
+}
+
+
+
+STATIC int INIT huft_free(
+       struct huft *t         /* table to free */
+       )
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != (struct huft *)NULL)
+  {
+    q = (--p)->v.t;
+    free((char*)p);
+    p = q;
+  } 
+  return 0;
+}
+
+
+STATIC int INIT inflate_codes(
+       struct huft *tl,    /* literal/length decoder tables */
+       struct huft *td,    /* distance decoder tables */
+       int bl,             /* number of bits decoded by tl[] */
+       int bd              /* number of bits decoded by td[] */
+       )
+/* inflate (decompress) the codes in a deflated (compressed) block.
+   Return an error code or zero if it all goes ok. */
+{
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+  /* inflate the coded data */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  for (;;)                      /* do until end of block */
+  {
+    NEEDBITS((unsigned)bl)
+    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+      do {
+        if (e == 99)
+          return 1;
+        DUMPBITS(t->b)
+        e -= 16;
+        NEEDBITS(e)
+      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+    DUMPBITS(t->b)
+    if (e == 16)                /* then it's a literal */
+    {
+      slide[w++] = (uch)t->v.n;
+      Tracevv((stderr, "%c", slide[w-1]));
+      if (w == WSIZE)
+      {
+        flush_output(w);
+        w = 0;
+      }
+    }
+    else                        /* it's an EOB or a length */
+    {
+      /* exit if end of block */
+      if (e == 15)
+        break;
+
+      /* get length of block to copy */
+      NEEDBITS(e)
+      n = t->v.n + ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e);
+
+      /* decode distance of block to copy */
+      NEEDBITS((unsigned)bd)
+      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      NEEDBITS(e)
+      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e)
+      Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+      /* do the copy */
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+        if (w - d >= e)         /* (this test assumes unsigned comparison) */
+        {
+          memcpy(slide + w, slide + d, e);
+          w += e;
+          d += e;
+        }
+        else                      /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+          do {
+            slide[w++] = slide[d++];
+           Tracevv((stderr, "%c", slide[w-1]));
+          } while (--e);
+        if (w == WSIZE)
+        {
+          flush_output(w);
+          w = 0;
+        }
+      } while (n);
+    }
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  /* done */
+  return 0;
+
+ underrun:
+  return 4;                    /* Input underrun */
+}
+
+
+
+STATIC int INIT inflate_stored(void)
+/* "decompress" an inflated type 0 (stored) block. */
+{
+  unsigned n;           /* number of bytes in block */
+  unsigned w;           /* current window position */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+DEBG("<stor");
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+
+  /* go to byte boundary */
+  n = k & 7;
+  DUMPBITS(n);
+
+
+  /* get the length and its complement */
+  NEEDBITS(16)
+  n = ((unsigned)b & 0xffff);
+  DUMPBITS(16)
+  NEEDBITS(16)
+  if (n != (unsigned)((~b) & 0xffff))
+    return 1;                   /* error in compressed data */
+  DUMPBITS(16)
+
+
+  /* read and output the compressed data */
+  while (n--)
+  {
+    NEEDBITS(8)
+    slide[w++] = (uch)b;
+    if (w == WSIZE)
+    {
+      flush_output(w);
+      w = 0;
+    }
+    DUMPBITS(8)
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  DEBG(">");
+  return 0;
+
+ underrun:
+  return 4;                    /* Input underrun */
+}
+
+
+/*
+ * We use `noinline' here to prevent gcc-3.5 from using too much stack space
+ */
+STATIC int noinline INIT inflate_fixed(void)
+/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+{
+  int i;                /* temporary variable */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned *l;          /* length list for huft_build */
+
+DEBG("<fix");
+
+  l = malloc(sizeof(*l) * 288);
+  if (l == NULL)
+    return 3;                  /* out of memory */
+
+  /* set up literal table */
+  for (i = 0; i < 144; i++)
+    l[i] = 8;
+  for (; i < 256; i++)
+    l[i] = 9;
+  for (; i < 280; i++)
+    l[i] = 7;
+  for (; i < 288; i++)          /* make a complete, but wrong code set */
+    l[i] = 8;
+  bl = 7;
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+    free(l);
+    return i;
+  }
+
+  /* set up distance table */
+  for (i = 0; i < 30; i++)      /* make an incomplete code set */
+    l[i] = 5;
+  bd = 5;
+  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+  {
+    huft_free(tl);
+    free(l);
+
+    DEBG(">");
+    return i;
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd)) {
+    free(l);
+    return 1;
+  }
+
+  /* free the decoding tables, return */
+  free(l);
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+/*
+ * We use `noinline' here to prevent gcc-3.5 from using too much stack space
+ */
+STATIC int noinline INIT inflate_dynamic(void)
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+  int i;                /* temporary variables */
+  unsigned j;
+  unsigned l;           /* last length */
+  unsigned m;           /* mask for bit lengths table */
+  unsigned n;           /* number of lengths to get */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned nb;          /* number of bit length codes */
+  unsigned nl;          /* number of literal/length codes */
+  unsigned nd;          /* number of distance codes */
+  unsigned *ll;         /* literal/length and distance code lengths */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+  int ret;
+
+DEBG("<dyn");
+
+#ifdef PKZIP_BUG_WORKAROUND
+  ll = malloc(sizeof(*ll) * (288+32));  /* literal/length and distance code lengths */
+#else
+  ll = malloc(sizeof(*ll) * (286+30));  /* literal/length and distance code lengths */
+#endif
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in table lengths */
+  NEEDBITS(5)
+  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
+  DUMPBITS(5)
+  NEEDBITS(5)
+  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
+  DUMPBITS(5)
+  NEEDBITS(4)
+  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
+  DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+  if (nl > 288 || nd > 32)
+#else
+  if (nl > 286 || nd > 30)
+#endif
+  {
+    ret = 1;             /* bad lengths */
+    goto out;
+  }
+
+DEBG("dyn1 ");
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+  {
+    NEEDBITS(3)
+    ll[border[j]] = (unsigned)b & 7;
+    DUMPBITS(3)
+  }
+  for (; j < 19; j++)
+    ll[border[j]] = 0;
+
+DEBG("dyn2 ");
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  bl = 7;
+  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+  {
+    if (i == 1)
+      huft_free(tl);
+    ret = i;                   /* incomplete code set */
+    goto out;
+  }
+
+DEBG("dyn3 ");
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[bl];
+  i = l = 0;
+  while ((unsigned)i < n)
+  {
+    NEEDBITS((unsigned)bl)
+    j = (td = tl + ((unsigned)b & m))->b;
+    DUMPBITS(j)
+    j = td->v.n;
+    if (j < 16)                 /* length of code in bits (0..15) */
+      ll[i++] = l = j;          /* save last length in l */
+    else if (j == 16)           /* repeat last length 3 to 6 times */
+    {
+      NEEDBITS(2)
+      j = 3 + ((unsigned)b & 3);
+      DUMPBITS(2)
+      if ((unsigned)i + j > n) {
+        ret = 1;
+       goto out;
+      }
+      while (j--)
+        ll[i++] = l;
+    }
+    else if (j == 17)           /* 3 to 10 zero length codes */
+    {
+      NEEDBITS(3)
+      j = 3 + ((unsigned)b & 7);
+      DUMPBITS(3)
+      if ((unsigned)i + j > n) {
+        ret = 1;
+       goto out;
+      }
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+    else                        /* j == 18: 11 to 138 zero length codes */
+    {
+      NEEDBITS(7)
+      j = 11 + ((unsigned)b & 0x7f);
+      DUMPBITS(7)
+      if ((unsigned)i + j > n) {
+        ret = 1;
+       goto out;
+      }
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+  }
+
+DEBG("dyn4 ");
+
+  /* free decoding table for trees */
+  huft_free(tl);
+
+DEBG("dyn5 ");
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+DEBG("dyn5a ");
+
+  /* build the decoding tables for literal/length and distance codes */
+  bl = lbits;
+  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+  {
+DEBG("dyn5b ");
+    if (i == 1) {
+      error("incomplete literal tree");
+      huft_free(tl);
+    }
+    ret = i;                   /* incomplete code set */
+    goto out;
+  }
+DEBG("dyn5c ");
+  bd = dbits;
+  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+  {
+DEBG("dyn5d ");
+    if (i == 1) {
+      error("incomplete distance tree");
+#ifdef PKZIP_BUG_WORKAROUND
+      i = 0;
+    }
+#else
+      huft_free(td);
+    }
+    huft_free(tl);
+    ret = i;                   /* incomplete code set */
+    goto out;
+#endif
+  }
+
+DEBG("dyn6 ");
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd)) {
+    ret = 1;
+    goto out;
+  }
+
+DEBG("dyn7 ");
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+
+  DEBG(">");
+  ret = 0;
+out:
+  free(ll);
+  return ret;
+
+underrun:
+  ret = 4;                     /* Input underrun */
+  goto out;
+}
+
+
+
+STATIC int INIT inflate_block(
+       int *e                  /* last block flag */
+       )
+/* decompress an inflated block */
+{
+  unsigned t;           /* block type */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+  DEBG("<blk");
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in last block bit */
+  NEEDBITS(1)
+  *e = (int)b & 1;
+  DUMPBITS(1)
+
+
+  /* read in block type */
+  NEEDBITS(2)
+  t = (unsigned)b & 3;
+  DUMPBITS(2)
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+  /* inflate that block type */
+  if (t == 2)
+    return inflate_dynamic();
+  if (t == 0)
+    return inflate_stored();
+  if (t == 1)
+    return inflate_fixed();
+
+  DEBG(">");
+
+  /* bad block type */
+  return 2;
+
+ underrun:
+  return 4;                    /* Input underrun */
+}
+
+
+
+STATIC int INIT inflate(void)
+/* decompress an inflated entry */
+{
+  int e;                /* last block flag */
+  int r;                /* result code */
+  unsigned h;           /* maximum struct huft's malloc'ed */
+  void *ptr;
+
+  /* initialize window, bit buffer */
+  wp = 0;
+  bk = 0;
+  bb = 0;
+
+
+  /* decompress until the last block */
+  h = 0;
+  do {
+    hufts = 0;
+    gzip_mark(&ptr);
+    if ((r = inflate_block(&e)) != 0) {
+      gzip_release(&ptr);          
+      return r;
+    }
+    gzip_release(&ptr);
+    if (hufts > h)
+      h = hufts;
+  } while (!e);
+
+  /* Undo too much lookahead. The next read will be byte aligned so we
+   * can discard unused bits in the last meaningful byte.
+   */
+  while (bk >= 8) {
+    bk -= 8;
+    inptr--;
+  }
+
+  /* flush out slide */
+  flush_output(wp);
+
+
+  /* return success */
+#ifdef DEBUG
+  fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+  return 0;
+}
+
+/**********************************************************************
+ *
+ * The following are support routines for inflate.c
+ *
+ **********************************************************************/
+
+static ulg crc_32_tab[256];
+static ulg crc;                /* initialized in makecrc() so it'll reside in bss */
+#define CRC_VALUE (crc ^ 0xffffffffUL)
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from 
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static void INIT
+makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler     */
+
+  unsigned long c;      /* crc shift register */
+  unsigned long e;      /* polynomial exclusive-or pattern */
+  int i;                /* counter for all possible eight bit values */
+  int k;                /* byte being shifted into crc apparatus */
+
+  /* terms of polynomial defining this crc (except x^32): */
+  static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* Make exclusive-or pattern from polynomial */
+  e = 0;
+  for (i = 0; i < sizeof(p)/sizeof(int); i++)
+    e |= 1L << (31 - p[i]);
+
+  crc_32_tab[0] = 0;
+
+  for (i = 1; i < 256; i++)
+  {
+    c = 0;
+    for (k = i | 256; k != 1; k >>= 1)
+    {
+      c = c & 1 ? (c >> 1) ^ e : c >> 1;
+      if (k & 1)
+        c ^= e;
+    }
+    crc_32_tab[i] = c;
+  }
+
+  /* this is initialized here so this code could reside in ROM */
+  crc = (ulg)0xffffffffUL; /* shift register contents */
+}
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+/*
+ * Do the uncompression!
+ */
+static int INIT gunzip(void)
+{
+    uch flags;
+    unsigned char magic[2]; /* magic header */
+    char method;
+    ulg orig_crc = 0;       /* original crc */
+    ulg orig_len = 0;       /* original uncompressed length */
+    int res;
+
+    magic[0] = NEXTBYTE();
+    magic[1] = NEXTBYTE();
+    method   = NEXTBYTE();
+
+    if (magic[0] != 037 ||
+       ((magic[1] != 0213) && (magic[1] != 0236))) {
+           error("bad gzip magic numbers");
+           return -1;
+    }
+
+    /* We only support method #8, DEFLATED */
+    if (method != 8)  {
+           error("internal error, invalid method");
+           return -1;
+    }
+
+    flags  = (uch)get_byte();
+    if ((flags & ENCRYPTED) != 0) {
+           error("Input is encrypted");
+           return -1;
+    }
+    if ((flags & CONTINUATION) != 0) {
+           error("Multi part input");
+           return -1;
+    }
+    if ((flags & RESERVED) != 0) {
+           error("Input has invalid flags");
+           return -1;
+    }
+    NEXTBYTE();        /* Get timestamp */
+    NEXTBYTE();
+    NEXTBYTE();
+    NEXTBYTE();
+
+    (void)NEXTBYTE();  /* Ignore extra flags for the moment */
+    (void)NEXTBYTE();  /* Ignore OS type for the moment */
+
+    if ((flags & EXTRA_FIELD) != 0) {
+           unsigned len = (unsigned)NEXTBYTE();
+           len |= ((unsigned)NEXTBYTE())<<8;
+           while (len--) (void)NEXTBYTE();
+    }
+
+    /* Get original file name if it was truncated */
+    if ((flags & ORIG_NAME) != 0) {
+           /* Discard the old name */
+           while (NEXTBYTE() != 0) /* null */ ;
+    } 
+
+    /* Discard file comment if any */
+    if ((flags & COMMENT) != 0) {
+           while (NEXTBYTE() != 0) /* null */ ;
+    }
+
+    /* Decompress */
+    if ((res = inflate())) {
+           switch (res) {
+           case 0:
+                   break;
+           case 1:
+                   error("invalid compressed format (err=1)");
+                   break;
+           case 2:
+                   error("invalid compressed format (err=2)");
+                   break;
+           case 3:
+                   error("out of memory");
+                   break;
+           case 4:
+                   error("out of input data");
+                   break;
+           default:
+                   error("invalid compressed format (other)");
+           }
+           return -1;
+    }
+           
+    /* Get the crc and original length */
+    /* crc32  (see algorithm.doc)
+     * uncompressed input size modulo 2^32
+     */
+    orig_crc = (ulg) NEXTBYTE();
+    orig_crc |= (ulg) NEXTBYTE() << 8;
+    orig_crc |= (ulg) NEXTBYTE() << 16;
+    orig_crc |= (ulg) NEXTBYTE() << 24;
+    
+    orig_len = (ulg) NEXTBYTE();
+    orig_len |= (ulg) NEXTBYTE() << 8;
+    orig_len |= (ulg) NEXTBYTE() << 16;
+    orig_len |= (ulg) NEXTBYTE() << 24;
+    
+    /* Validate decompression */
+    if (orig_crc != CRC_VALUE) {
+           error("crc error");
+           return -1;
+    }
+    if (orig_len != bytes_out) {
+           error("length error");
+           return -1;
+    }
+    return 0;
+
+ underrun:                     /* NEXTBYTE() goto's here if needed */
+    error("out of input data");
+    return -1;
+}
+
+
diff --git a/kitten/lib/sort.c b/kitten/lib/sort.c
new file mode 100644 (file)
index 0000000..d48aed2
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
+ *
+ * Jan 23 2005  Matt Mackall <mpm@selenic.com>
+ */
+
+#include <lwk/kernel.h>
+#include <lwk/sort.h>
+#include <lwk/linux_compat.h>
+
+static void u32_swap(void *a, void *b, int size)
+{
+       u32 t = *(u32 *)a;
+       *(u32 *)a = *(u32 *)b;
+       *(u32 *)b = t;
+}
+
+static void generic_swap(void *a, void *b, int size)
+{
+       char t;
+
+       do {
+               t = *(char *)a;
+               *(char *)a++ = *(char *)b;
+               *(char *)b++ = t;
+       } while (--size > 0);
+}
+
+/**
+ * sort - sort an array of elements
+ * @base: pointer to data to sort
+ * @num: number of elements
+ * @size: size of each element
+ * @cmp: pointer to comparison function
+ * @swap: pointer to swap function or NULL
+ *
+ * This function does a heapsort on the given array. You may provide a
+ * swap function optimized to your element type.
+ *
+ * Sorting time is O(n log n) both on average and worst-case. While
+ * qsort is about 20% faster on average, it suffers from exploitable
+ * O(n*n) worst-case behavior and extra memory requirements that make
+ * it less suitable for kernel use.
+ */
+
+void sort(void *base, size_t num, size_t size,
+         int (*cmp)(const void *, const void *),
+         void (*swap)(void *, void *, int size))
+{
+       /* pre-scale counters for performance */
+       int i = (num/2 - 1) * size, n = num * size, c, r;
+
+       if (!swap)
+               swap = (size == 4 ? u32_swap : generic_swap);
+
+       /* heapify */
+       for ( ; i >= 0; i -= size) {
+               for (r = i; r * 2 + size < n; r  = c) {
+                       c = r * 2 + size;
+                       if (c < n - size && cmp(base + c, base + c + size) < 0)
+                               c += size;
+                       if (cmp(base + r, base + c) >= 0)
+                               break;
+                       swap(base + r, base + c, size);
+               }
+       }
+
+       /* sort */
+       for (i = n - size; i >= 0; i -= size) {
+               swap(base, base + i, size);
+               for (r = 0; r * 2 + size < i; r = c) {
+                       c = r * 2 + size;
+                       if (c < i - size && cmp(base + c, base + c + size) < 0)
+                               c += size;
+                       if (cmp(base + r, base + c) >= 0)
+                               break;
+                       swap(base + r, base + c, size);
+               }
+       }
+}
+
+EXPORT_SYMBOL(sort);
+
+#if 0
+/* a simple boot-time regression test */
+
+int cmpint(const void *a, const void *b)
+{
+       return *(int *)a - *(int *)b;
+}
+
+static int sort_test(void)
+{
+       int *a, i, r = 1;
+
+       a = kmalloc(1000 * sizeof(int), GFP_KERNEL);
+       BUG_ON(!a);
+
+       printk("testing sort()\n");
+
+       for (i = 0; i < 1000; i++) {
+               r = (r * 725861) % 6599;
+               a[i] = r;
+       }
+
+       sort(a, 1000, sizeof(int), cmpint, NULL);
+
+       for (i = 0; i < 999; i++)
+               if (a[i] > a[i+1]) {
+                       printk("sort() failed!\n");
+                       break;
+               }
+
+       kfree(a);
+
+       return 0;
+}
+
+module_init(sort_test);
+#endif
diff --git a/kitten/lib/string.c b/kitten/lib/string.c
new file mode 100644 (file)
index 0000000..73c0cfd
--- /dev/null
@@ -0,0 +1,627 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ *                    Matthew Hawkins <matt@mh.dropbear.id.au>
+ * -  Kissed strtok() goodbye
+ */
+
+#include <lwk/kernel.h>
+#include <lwk/types.h>
+#include <lwk/string.h>
+#include <lwk/ctype.h>
+#include <lwk/linux_compat.h>
+#include <arch/bug.h>
+
+#ifndef __HAVE_ARCH_STRNICMP
+/**
+ * strnicmp - Case insensitive, length-limited string comparison
+ * @s1: One string
+ * @s2: The other string
+ * @len: the maximum number of characters to compare
+ */
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+       /* Yes, Virginia, it had better be unsigned */
+       unsigned char c1, c2;
+
+       c1 = c2 = 0;
+       if (len) {
+               do {
+                       c1 = *s1;
+                       c2 = *s2;
+                       s1++;
+                       s2++;
+                       if (!c1)
+                               break;
+                       if (!c2)
+                               break;
+                       if (c1 == c2)
+                               continue;
+                       c1 = tolower(c1);
+                       c2 = tolower(c2);
+                       if (c1 != c2)
+                               break;
+               } while (--len);
+       }
+       return (int)c1 - (int)c2;
+}
+EXPORT_SYMBOL(strnicmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRCPY
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+#undef strcpy
+char *strcpy(char *dest, const char *src)
+{
+       char *tmp = dest;
+
+       while ((*dest++ = *src++) != '\0')
+               /* nothing */;
+       return tmp;
+}
+EXPORT_SYMBOL(strcpy);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * The result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ *
+ * In the case where the length of @src is less than  that  of
+ * count, the remainder of @dest will be padded with %NUL.
+ *
+ */
+char *strncpy(char *dest, const char *src, size_t count)
+{
+       char *tmp = dest;
+
+       while (count) {
+               if ((*tmp = *src) != 0)
+                       src++;
+               tmp++;
+               count--;
+       }
+       return dest;
+}
+EXPORT_SYMBOL(strncpy);
+#endif
+
+#ifndef __HAVE_ARCH_STRLCPY
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+       size_t ret = strlen(src);
+
+       if (size) {
+               size_t len = (ret >= size) ? size - 1 : ret;
+               memcpy(dest, src, len);
+               dest[len] = '\0';
+       }
+       return ret;
+}
+EXPORT_SYMBOL(strlcpy);
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+/**
+ * strcat - Append one %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ */
+#undef strcat
+char *strcat(char *dest, const char *src)
+{
+       char *tmp = dest;
+
+       while (*dest)
+               dest++;
+       while ((*dest++ = *src++) != '\0')
+               ;
+       return tmp;
+}
+EXPORT_SYMBOL(strcat);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCAT
+/**
+ * strncat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The maximum numbers of bytes to copy
+ *
+ * Note that in contrast to strncpy, strncat ensures the result is
+ * terminated.
+ */
+char *strncat(char *dest, const char *src, size_t count)
+{
+       char *tmp = dest;
+
+       if (count) {
+               while (*dest)
+                       dest++;
+               while ((*dest++ = *src++) != 0) {
+                       if (--count == 0) {
+                               *dest = '\0';
+                               break;
+                       }
+               }
+       }
+       return tmp;
+}
+EXPORT_SYMBOL(strncat);
+#endif
+
+#ifndef __HAVE_ARCH_STRLCAT
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The size of the destination buffer.
+ */
+size_t strlcat(char *dest, const char *src, size_t count)
+{
+       size_t dsize = strlen(dest);
+       size_t len = strlen(src);
+       size_t res = dsize + len;
+
+       /* This would be a bug */
+       BUG_ON(dsize >= count);
+
+       dest += dsize;
+       count -= dsize;
+       if (len >= count)
+               len = count-1;
+       memcpy(dest, src, len);
+       dest[len] = 0;
+       return res;
+}
+EXPORT_SYMBOL(strlcat);
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+#undef strcmp
+int strcmp(const char *cs, const char *ct)
+{
+       signed char __res;
+
+       while (1) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+       }
+       return __res;
+}
+EXPORT_SYMBOL(strcmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+       signed char __res = 0;
+
+       while (count) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+               count--;
+       }
+       return __res;
+}
+EXPORT_SYMBOL(strncmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strchr(const char *s, int c)
+{
+       for (; *s != (char)c; ++s)
+               if (*s == '\0')
+                       return NULL;
+       return (char *)s;
+}
+EXPORT_SYMBOL(strchr);
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strrchr(const char *s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+           if (*p == (char)c)
+               return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+EXPORT_SYMBOL(strrchr);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCHR
+/**
+ * strnchr - Find a character in a length limited string
+ * @s: The string to be searched
+ * @count: The number of characters to be searched
+ * @c: The character to search for
+ */
+char *strnchr(const char *s, size_t count, int c)
+{
+       for (; count-- && *s != '\0'; ++s)
+               if (*s == (char)c)
+                       return (char *)s;
+       return NULL;
+}
+EXPORT_SYMBOL(strnchr);
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char *s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+EXPORT_SYMBOL(strlen);
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char *s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+EXPORT_SYMBOL(strnlen);
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+/**
+ * strspn - Calculate the length of the initial substring of @s which only
+ *     contain letters in @accept
+ * @s: The string to be searched
+ * @accept: The string to search for
+ */
+size_t strspn(const char *s, const char *accept)
+{
+       const char *p;
+       const char *a;
+       size_t count = 0;
+
+       for (p = s; *p != '\0'; ++p) {
+               for (a = accept; *a != '\0'; ++a) {
+                       if (*p == *a)
+                               break;
+               }
+               if (*a == '\0')
+                       return count;
+               ++count;
+       }
+       return count;
+}
+
+EXPORT_SYMBOL(strspn);
+#endif
+
+#ifndef __HAVE_ARCH_STRCSPN
+/**
+ * strcspn - Calculate the length of the initial substring of @s which does
+ *     not contain letters in @reject
+ * @s: The string to be searched
+ * @reject: The string to avoid
+ */
+size_t strcspn(const char *s, const char *reject)
+{
+       const char *p;
+       const char *r;
+       size_t count = 0;
+
+       for (p = s; *p != '\0'; ++p) {
+               for (r = reject; *r != '\0'; ++r) {
+                       if (*p == *r)
+                               return count;
+               }
+               ++count;
+       }
+       return count;
+}
+EXPORT_SYMBOL(strcspn);
+#endif
+
+#ifndef __HAVE_ARCH_STRPBRK
+/**
+ * strpbrk - Find the first occurrence of a set of characters
+ * @cs: The string to be searched
+ * @ct: The characters to search for
+ */
+char *strpbrk(const char *cs, const char *ct)
+{
+       const char *sc1, *sc2;
+
+       for (sc1 = cs; *sc1 != '\0'; ++sc1) {
+               for (sc2 = ct; *sc2 != '\0'; ++sc2) {
+                       if (*sc1 == *sc2)
+                               return (char *)sc1;
+               }
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(strpbrk);
+#endif
+
+#ifndef __HAVE_ARCH_STRSEP
+/**
+ * strsep - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * strsep() updates @s to point after the token, ready for the next call.
+ *
+ * It returns empty tokens, too, behaving exactly like the libc function
+ * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
+ * Same semantics, slimmer shape. ;)
+ */
+char *strsep(char **s, const char *ct)
+{
+       char *sbegin = *s;
+       char *end;
+
+       if (sbegin == NULL)
+               return NULL;
+
+       end = strpbrk(sbegin, ct);
+       if (end)
+               *end++ = '\0';
+       *s = end;
+       return sbegin;
+}
+EXPORT_SYMBOL(strsep);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
+ */
+void *memset(void *s, int c, size_t count)
+{
+       char *xs = s;
+
+       while (count--)
+               *xs++ = c;
+       return s;
+}
+EXPORT_SYMBOL(memset);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+void *memcpy(void *dest, const void *src, size_t count)
+{
+       char *tmp = dest;
+       const char *s = src;
+
+       while (count--)
+               *tmp++ = *s++;
+       return dest;
+}
+EXPORT_SYMBOL(memcpy);
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+/**
+ * memmove - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * Unlike memcpy(), memmove() copes with overlapping areas.
+ */
+void *memmove(void *dest, const void *src, size_t count)
+{
+       char *tmp;
+       const char *s;
+
+       if (dest <= src) {
+               tmp = dest;
+               s = src;
+               while (count--)
+                       *tmp++ = *s++;
+       } else {
+               tmp = dest;
+               tmp += count;
+               s = src;
+               s += count;
+               while (count--)
+                       *--tmp = *--s;
+       }
+       return dest;
+}
+EXPORT_SYMBOL(memmove);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+#undef memcmp
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+       const unsigned char *su1, *su2;
+       int res = 0;
+
+       for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+               if ((res = *su1 - *su2) != 0)
+                       break;
+       return res;
+}
+EXPORT_SYMBOL(memcmp);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSCAN
+/**
+ * memscan - Find a character in an area of memory.
+ * @addr: The memory area
+ * @c: The byte to search for
+ * @size: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or 1 byte past
+ * the area if @c is not found
+ */
+void *memscan(void *addr, int c, size_t size)
+{
+       unsigned char *p = addr;
+
+       while (size) {
+               if (*p == c)
+                       return (void *)p;
+               p++;
+               size--;
+       }
+       return (void *)p;
+}
+EXPORT_SYMBOL(memscan);
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+       int l1, l2;
+
+       l2 = strlen(s2);
+       if (!l2)
+               return (char *)s1;
+       l1 = strlen(s1);
+       while (l1 >= l2) {
+               l1--;
+               if (!memcmp(s1, s2, l2))
+                       return (char *)s1;
+               s1++;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(strstr);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCHR
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
+void *memchr(const void *s, int c, size_t n)
+{
+       const unsigned char *p = s;
+       while (n-- != 0) {
+               if ((unsigned char)c == *p++) {
+                       return (void *)(p - 1);
+               }
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(memchr);
+#endif
+
+
+/**
+ * Converts error code into human readable string.
+ */
+char *
+strerror(int errnum)
+{
+       if (errnum < 0)
+               errnum *= -1;
+
+       switch (errnum) {
+               case ENOMEM:    return "Out of memory";
+               case EINVAL:    return "Invalid argument";
+       }
+
+       return "unknown";
+}
+
diff --git a/kitten/lib/vsprintf.c b/kitten/lib/vsprintf.c
new file mode 100644 (file)
index 0000000..d1a52f3
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/* 
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+#include <stdarg.h>
+#include <lwk/linux_compat.h>
+#include <lwk/types.h>
+#include <lwk/string.h>
+#include <lwk/ctype.h>
+#include <lwk/kernel.h>
+
+#include <arch/page.h>         /* for PAGE_SIZE */
+#include <arch/div64.h>
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+       unsigned long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*cp == '0') {
+                       base = 8;
+                       cp++;
+                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                               cp++;
+                               base = 16;
+                       }
+               }
+       } else if (base == 16) {
+               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+                       cp += 2;
+       }
+       while (isxdigit(*cp) &&
+              (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+               result = result*base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+       return result;
+}
+
+EXPORT_SYMBOL(simple_strtoul);
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+       if(*cp=='-')
+               return -simple_strtoul(cp+1,endp,base);
+       return simple_strtoul(cp,endp,base);
+}
+
+EXPORT_SYMBOL(simple_strtol);
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+       unsigned long long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*cp == '0') {
+                       base = 8;
+                       cp++;
+                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                               cp++;
+                               base = 16;
+                       }
+               }
+       } else if (base == 16) {
+               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+                       cp += 2;
+       }
+       while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+           ? toupper(*cp) : *cp)-'A'+10) < base) {
+               result = result*base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+       return result;
+}
+
+EXPORT_SYMBOL(simple_strtoull);
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+       if(*cp=='-')
+               return -simple_strtoull(cp+1,endp,base);
+       return simple_strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+       int i=0;
+
+       while (isdigit(**s))
+               i = i*10 + *((*s)++) - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+{
+       char c,sign,tmp[66];
+       const char *digits;
+       static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+       static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       int i;
+
+       digits = (type & LARGE) ? large_digits : small_digits;
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return NULL;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if ((signed long long) num < 0) {
+                       sign = '-';
+                       num = - (signed long long) num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0)
+               tmp[i++] = digits[do_div(num,base)];
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT))) {
+               while(size-->0) {
+                       if (buf <= end)
+                               *buf = ' ';
+                       ++buf;
+               }
+       }
+       if (sign) {
+               if (buf <= end)
+                       *buf = sign;
+               ++buf;
+       }
+       if (type & SPECIAL) {
+               if (base==8) {
+                       if (buf <= end)
+                               *buf = '0';
+                       ++buf;
+               } else if (base==16) {
+                       if (buf <= end)
+                               *buf = '0';
+                       ++buf;
+                       if (buf <= end)
+                               *buf = digits[33];
+                       ++buf;
+               }
+       }
+       if (!(type & LEFT)) {
+               while (size-- > 0) {
+                       if (buf <= end)
+                               *buf = c;
+                       ++buf;
+               }
+       }
+       while (i < precision--) {
+               if (buf <= end)
+                       *buf = '0';
+               ++buf;
+       }
+       while (i-- > 0) {
+               if (buf <= end)
+                       *buf = tmp[i];
+               ++buf;
+       }
+       while (size-- > 0) {
+               if (buf <= end)
+                       *buf = ' ';
+               ++buf;
+       }
+       return buf;
+}
+
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long long num;
+       int i, base;
+       char *str, *end, c;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+                               /* 't' added for ptrdiff_t */
+
+       /* Reject out-of-range values early */
+       if (unlikely((int) size < 0)) {
+               /* There can be only one.. */
+               static int warn = 1;
+               WARN_ON(warn);
+               warn = 0;
+               return 0;
+       }
+
+       str = buf;
+       end = buf + size - 1;
+
+       if (end < buf - 1) {
+               end = ((void *) -1);
+               size = end - buf + 1;
+       }
+
+       for (; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       if (str <= end)
+                               *str = *fmt;
+                       ++str;
+                       continue;
+               }
+
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= LEFT; goto repeat;
+                               case '+': flags |= PLUS; goto repeat;
+                               case ' ': flags |= SPACE; goto repeat;
+                               case '#': flags |= SPECIAL; goto repeat;
+                               case '0': flags |= ZEROPAD; goto repeat;
+                       }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt))
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;  
+                       if (isdigit(*fmt))
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+                   *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
+                       qualifier = *fmt;
+                       ++fmt;
+                       if (qualifier == 'l' && *fmt == 'l') {
+                               qualifier = 'L';
+                               ++fmt;
+                       }
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+                       case 'c':
+                               if (!(flags & LEFT)) {
+                                       while (--field_width > 0) {
+                                               if (str <= end)
+                                                       *str = ' ';
+                                               ++str;
+                                       }
+                               }
+                               c = (unsigned char) va_arg(args, int);
+                               if (str <= end)
+                                       *str = c;
+                               ++str;
+                               while (--field_width > 0) {
+                                       if (str <= end)
+                                               *str = ' ';
+                                       ++str;
+                               }
+                               continue;
+
+                       case 's':
+                               s = va_arg(args, char *);
+                               if ((unsigned long)s < PAGE_SIZE)
+                                       s = "<NULL>";
+
+                               len = strnlen(s, precision);
+
+                               if (!(flags & LEFT)) {
+                                       while (len < field_width--) {
+                                               if (str <= end)
+                                                       *str = ' ';
+                                               ++str;
+                                       }
+                               }
+                               for (i = 0; i < len; ++i) {
+                                       if (str <= end)
+                                               *str = *s;
+                                       ++str; ++s;
+                               }
+                               while (len < field_width--) {
+                                       if (str <= end)
+                                               *str = ' ';
+                                       ++str;
+                               }
+                               continue;
+
+                       case 'p':
+                               if (field_width == -1) {
+                                       field_width = 2*sizeof(void *);
+                                       flags |= ZEROPAD;
+                               }
+                               str = number(str, end,
+                                               (unsigned long) va_arg(args, void *),
+                                               16, field_width, precision, flags);
+                               continue;
+
+
+                       case 'n':
+                               /* FIXME:
+                               * What does C99 say about the overflow case here? */
+                               if (qualifier == 'l') {
+                                       long * ip = va_arg(args, long *);
+                                       *ip = (str - buf);
+                               } else if (qualifier == 'Z' || qualifier == 'z') {
+                                       size_t * ip = va_arg(args, size_t *);
+                                       *ip = (str - buf);
+                               } else {
+                                       int * ip = va_arg(args, int *);
+                                       *ip = (str - buf);
+                               }
+                               continue;
+
+                       case '%':
+                               if (str <= end)
+                                       *str = '%';
+                               ++str;
+                               continue;
+
+                               /* integer number formats - set up the flags and "break" */
+                       case 'o':
+                               base = 8;
+                               break;
+
+                       case 'X':
+                               flags |= LARGE;
+                       case 'x':
+                               base = 16;
+                               break;
+
+                       case 'd':
+                       case 'i':
+                               flags |= SIGN;
+                       case 'u':
+                               break;
+
+                       default:
+                               if (str <= end)
+                                       *str = '%';
+                               ++str;
+                               if (*fmt) {
+                                       if (str <= end)
+                                               *str = *fmt;
+                                       ++str;
+                               } else {
+                                       --fmt;
+                               }
+                               continue;
+               }
+               if (qualifier == 'L')
+                       num = va_arg(args, long long);
+               else if (qualifier == 'l') {
+                       num = va_arg(args, unsigned long);
+                       if (flags & SIGN)
+                               num = (signed long) num;
+               } else if (qualifier == 'Z' || qualifier == 'z') {
+                       num = va_arg(args, size_t);
+               } else if (qualifier == 't') {
+                       num = va_arg(args, ptrdiff_t);
+               } else if (qualifier == 'h') {
+                       num = (unsigned short) va_arg(args, int);
+                       if (flags & SIGN)
+                               num = (signed short) num;
+               } else {
+                       num = va_arg(args, unsigned int);
+                       if (flags & SIGN)
+                               num = (signed int) num;
+               }
+               str = number(str, end, num, base,
+                               field_width, precision, flags);
+       }
+       if (str <= end)
+               *str = '\0';
+       else if (size > 0)
+               /* don't write out a null byte if the buf size is zero */
+               *end = '\0';
+       /* the trailing null byte doesn't count towards the total
+       * ++str;
+       */
+       return str-buf;
+}
+
+EXPORT_SYMBOL(vsnprintf);
+
+/**
+ * vscnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is <= 0 the function
+ * returns 0.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want scnprintf instead.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+       int i;
+
+       i=vsnprintf(buf,size,fmt,args);
+       return (i >= size) ? (size - 1) : i;
+}
+
+EXPORT_SYMBOL(vscnprintf);
+
+/**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99.  If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsnprintf(buf,size,fmt,args);
+       va_end(args);
+       return i;
+}
+
+EXPORT_SYMBOL(snprintf);
+
+/**
+ * scnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
+ * greater than or equal to @size, the resulting string is truncated.
+ */
+
+int scnprintf(char * buf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vsnprintf(buf, size, fmt, args);
+       va_end(args);
+       return (i >= size) ? (size - 1) : i;
+}
+EXPORT_SYMBOL(scnprintf);
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use vsnprintf or vscnprintf in order to avoid
+ * buffer overflows.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+       return vsnprintf(buf, INT_MAX, fmt, args);
+}
+
+EXPORT_SYMBOL(vsprintf);
+
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use snprintf or scnprintf in order to avoid
+ * buffer overflows.
+ */
+int sprintf(char * buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsnprintf(buf, INT_MAX, fmt, args);
+       va_end(args);
+       return i;
+}
+
+EXPORT_SYMBOL(sprintf);
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:       input buffer
+ * @fmt:       format of buffer
+ * @args:      arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+       const char *str = buf;
+       char *next;
+       char digit;
+       int num = 0;
+       int qualifier;
+       int base;
+       int field_width;
+       int is_sign = 0;
+
+       while(*fmt && *str) {
+               /* skip any white space in format */
+               /* white space in format matchs any amount of
+                * white space, including none, in the input.
+                */
+               if (isspace(*fmt)) {
+                       while (isspace(*fmt))
+                               ++fmt;
+                       while (isspace(*str))
+                               ++str;
+               }
+
+               /* anything that is not a conversion must match exactly */
+               if (*fmt != '%' && *fmt) {
+                       if (*fmt++ != *str++)
+                               break;
+                       continue;
+               }
+
+               if (!*fmt)
+                       break;
+               ++fmt;
+               
+               /* skip this conversion.
+                * advance both strings to next white space
+                */
+               if (*fmt == '*') {
+                       while (!isspace(*fmt) && *fmt)
+                               fmt++;
+                       while (!isspace(*str) && *str)
+                               str++;
+                       continue;
+               }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt))
+                       field_width = skip_atoi(&fmt);
+
+               /* get conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+                   *fmt == 'Z' || *fmt == 'z') {
+                       qualifier = *fmt++;
+                       if (unlikely(qualifier == *fmt)) {
+                               if (qualifier == 'h') {
+                                       qualifier = 'H';
+                                       fmt++;
+                               } else if (qualifier == 'l') {
+                                       qualifier = 'L';
+                                       fmt++;
+                               }
+                       }
+               }
+               base = 10;
+               is_sign = 0;
+
+               if (!*fmt || !*str)
+                       break;
+
+               switch(*fmt++) {
+               case 'c':
+               {
+                       char *s = (char *) va_arg(args,char*);
+                       if (field_width == -1)
+                               field_width = 1;
+                       do {
+                               *s++ = *str++;
+                       } while (--field_width > 0 && *str);
+                       num++;
+               }
+               continue;
+               case 's':
+               {
+                       char *s = (char *) va_arg(args, char *);
+                       if(field_width == -1)
+                               field_width = INT_MAX;
+                       /* first, skip leading white space in buffer */
+                       while (isspace(*str))
+                               str++;
+
+                       /* now copy until next white space */
+                       while (*str && !isspace(*str) && field_width--) {
+                               *s++ = *str++;
+                       }
+                       *s = '\0';
+                       num++;
+               }
+               continue;
+               case 'n':
+                       /* return number of characters read so far */
+               {
+                       int *i = (int *)va_arg(args,int*);
+                       *i = str - buf;
+               }
+               continue;
+               case 'o':
+                       base = 8;
+                       break;
+               case 'x':
+               case 'X':
+                       base = 16;
+                       break;
+               case 'i':
+                        base = 0;
+               case 'd':
+                       is_sign = 1;
+               case 'u':
+                       break;
+               case '%':
+                       /* looking for '%' in str */
+                       if (*str++ != '%') 
+                               return num;
+                       continue;
+               default:
+                       /* invalid format; stop here */
+                       return num;
+               }
+
+               /* have some sort of integer conversion.
+                * first, skip white space in buffer.
+                */
+               while (isspace(*str))
+                       str++;
+
+               digit = *str;
+               if (is_sign && digit == '-')
+                       digit = *(str + 1);
+
+               if (!digit
+                    || (base == 16 && !isxdigit(digit))
+                    || (base == 10 && !isdigit(digit))
+                    || (base == 8 && (!isdigit(digit) || digit > '7'))
+                    || (base == 0 && !isdigit(digit)))
+                               break;
+
+               switch(qualifier) {
+               case 'H':       /* that's 'hh' in format */
+                       if (is_sign) {
+                               signed char *s = (signed char *) va_arg(args,signed char *);
+                               *s = (signed char) simple_strtol(str,&next,base);
+                       } else {
+                               unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
+                               *s = (unsigned char) simple_strtoul(str, &next, base);
+                       }
+                       break;
+               case 'h':
+                       if (is_sign) {
+                               short *s = (short *) va_arg(args,short *);
+                               *s = (short) simple_strtol(str,&next,base);
+                       } else {
+                               unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
+                               *s = (unsigned short) simple_strtoul(str, &next, base);
+                       }
+                       break;
+               case 'l':
+                       if (is_sign) {
+                               long *l = (long *) va_arg(args,long *);
+                               *l = simple_strtol(str,&next,base);
+                       } else {
+                               unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
+                               *l = simple_strtoul(str,&next,base);
+                       }
+                       break;
+               case 'L':
+                       if (is_sign) {
+                               long long *l = (long long*) va_arg(args,long long *);
+                               *l = simple_strtoll(str,&next,base);
+                       } else {
+                               unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
+                               *l = simple_strtoull(str,&next,base);
+                       }
+                       break;
+               case 'Z':
+               case 'z':
+               {
+                       size_t *s = (size_t*) va_arg(args,size_t*);
+                       *s = (size_t) simple_strtoul(str,&next,base);
+               }
+               break;
+               default:
+                       if (is_sign) {
+                               int *i = (int *) va_arg(args, int*);
+                               *i = (int) simple_strtol(str,&next,base);
+                       } else {
+                               unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
+                               *i = (unsigned int) simple_strtoul(str,&next,base);
+                       }
+                       break;
+               }
+               num++;
+
+               if (!next)
+                       break;
+               str = next;
+       }
+       return num;
+}
+
+EXPORT_SYMBOL(vsscanf);
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:       input buffer
+ * @fmt:       formatting of buffer
+ * @...:       resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args,fmt);
+       i = vsscanf(buf,fmt,args);
+       va_end(args);
+       return i;
+}
+
+EXPORT_SYMBOL(sscanf);
diff --git a/kitten/mm/Makefile b/kitten/mm/Makefile
new file mode 100644 (file)
index 0000000..360568b
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y := bootmem.o buddy.o kmem.o aspace.o pmem.o pmem_liblwk.o \
+               aspace_liblwk.o
diff --git a/kitten/mm/aspace.c b/kitten/mm/aspace.c
new file mode 100644 (file)
index 0000000..f6af525
--- /dev/null
@@ -0,0 +1,1003 @@
+/* Copyright (c) 2007,2008 Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/task.h>
+#include <lwk/spinlock.h>
+#include <lwk/string.h>
+#include <lwk/aspace.h>
+#include <lwk/idspace.h>
+#include <lwk/htable.h>
+#include <lwk/log2.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/pmem.h>
+#include <arch/uaccess.h>
+
+/**
+ * ID space used to allocate address space IDs.
+ */
+static idspace_t idspace;
+
+/**
+ * Hash table used to lookup address space structures by ID.
+ */
+static htable_t htable;
+
+/**
+ * Lock for serializing access to the htable.
+ */
+static DEFINE_SPINLOCK(htable_lock);
+
+/**
+ * Memory region structure. A memory region represents a contiguous region 
+ * [start, end) of valid memory addresses in an address space.
+ */
+struct region {
+       struct aspace *  aspace;   /* Address space this region belongs to */
+       struct list_head link;     /* Linkage in the aspace->region_list */
+
+       vaddr_t          start;    /* Starting address of the region */
+       vaddr_t          end;      /* 1st byte after end of the region */
+       vmflags_t        flags;    /* Permissions, caching, etc. */
+       vmpagesize_t     pagesz;   /* Allowed page sizes... 2^bit */
+       id_t             smartmap; /* If (flags & VM_SMARTMAP), ID of the
+                                     aspace this region is mapped to */
+       char             name[16]; /* Human-readable name of the region */
+};
+
+/**
+ * This calculates a region's end address. Normally end is the address of the
+ * first byte after the region. However if the region extends to the end of
+ * memory, that is not possible so set end to the last valid address,
+ * ULONG_MAX.
+ */
+static vaddr_t
+calc_end(vaddr_t start, size_t extent)
+{
+       vaddr_t end = start + extent;
+       if (end == 0)
+               end = ULONG_MAX;
+       return end;
+}
+
+/**
+ * Locates the region covering the specified address.
+ */
+static struct region *
+find_region(struct aspace *aspace, vaddr_t addr)
+{
+       struct region *rgn;
+       
+       list_for_each_entry(rgn, &aspace->region_list, link) {
+               if ((rgn->start <= addr) && (rgn->end > addr))
+                       return rgn;
+       }
+       return NULL;
+}
+
+/**
+ * Finds a region that overlaps the specified interval.
+ */
+static struct region *
+find_overlapping_region(struct aspace *aspace, vaddr_t start, vaddr_t end)
+{
+       struct region *rgn;
+
+       list_for_each_entry(rgn, &aspace->region_list, link) {
+               if ((start < rgn->end) && (end > rgn->start))
+                       return rgn;
+       }
+       return NULL;
+}
+
+/**
+ * Locates the region that is SMARTMAP'ed to the specified aspace ID.
+ */
+static struct region *
+find_smartmap_region(struct aspace *aspace, id_t src_aspace)
+{
+       struct region *rgn;
+       
+       list_for_each_entry(rgn, &aspace->region_list, link) {
+               if ((rgn->flags & VM_SMARTMAP) && (rgn->smartmap == src_aspace))
+                       return rgn;
+       }
+       return NULL;
+}
+
+/**
+ * Looks up an aspace object by ID and returns it with its spinlock locked.
+ */
+static struct aspace *
+lookup_and_lock(id_t id)
+{
+       struct aspace *aspace;
+
+       /* Lock the hash table, lookup aspace object by ID */
+       spin_lock(&htable_lock);
+       if ((aspace = htable_lookup(htable, id)) == NULL) {
+               spin_unlock(&htable_lock);
+               return NULL;
+       }
+
+       /* Lock the identified aspace */
+       spin_lock(&aspace->lock);
+
+       /* Unlock the hash table, others may now use it */
+       spin_unlock(&htable_lock);
+
+       return aspace;
+}
+
+/**
+ * Like lookup_and_lock(), but looks up two address spaces instead of one.
+ */
+static int
+lookup_and_lock_two(id_t a, id_t b,
+                    struct aspace **aspace_a, struct aspace **aspace_b)
+{
+       /* Lock the hash table, lookup aspace objects by ID */
+       spin_lock(&htable_lock);
+       if ((*aspace_a = htable_lookup(htable, a)) == NULL) {
+               spin_unlock(&htable_lock);
+               return -ENOENT;
+       }
+
+       if ((*aspace_b = htable_lookup(htable, b)) == NULL) {
+               spin_unlock(&htable_lock);
+               return -ENOENT;
+       }
+
+       /* Lock the identified aspaces */
+       spin_lock(&(*aspace_a)->lock);
+       spin_lock(&(*aspace_b)->lock);
+
+       /* Unlock the hash table, others may now use it */
+       spin_unlock(&htable_lock);
+
+       return 0;
+}
+
+static bool
+id_ok(id_t id)
+{
+       return ((id >= ASPACE_MIN_ID) && (id <= ASPACE_MAX_ID));
+}
+
+int __init
+aspace_subsys_init(void)
+{
+       int status;
+
+       /* Create an ID space for allocating address space IDs */
+       if ((status = idspace_create(__ASPACE_MIN_ID, __ASPACE_MAX_ID, &idspace)))
+               panic("Failed to create aspace ID space (status=%d).", status);
+
+       /* Create a hash table that will be used for quick ID->aspace lookups */
+       if ((status = htable_create(7 /* 2^7 bins */,
+                                   offsetof(struct aspace, id),
+                                   offsetof(struct aspace, ht_link),
+                                   &htable)))
+               panic("Failed to create aspace hash table (status=%d).", status);
+
+       /* Create an aspace for use by kernel threads */
+       if ((status = aspace_create(KERNEL_ASPACE_ID, "kernel", NULL)))
+               panic("Failed to create kernel aspace (status=%d).", status);
+
+       /* Switch to the newly created kernel address space */
+       if ((current->aspace = aspace_acquire(KERNEL_ASPACE_ID)) == NULL)
+               panic("Failed to acquire kernel aspace.");
+       arch_aspace_activate(current->aspace);
+
+       return 0;
+}
+
+int
+aspace_get_myid(id_t *id)
+{
+       *id = current->aspace->id;
+       return 0;
+}
+
+int
+sys_aspace_get_myid(id_t __user *id)
+{
+       int status;
+       id_t _id;
+
+       if ((status = aspace_get_myid(&_id)) != 0)
+               return status;
+
+       if (id && copy_to_user(id, &_id, sizeof(*id)))
+               return -EINVAL;
+
+       return 0;
+}
+
+int
+aspace_create(id_t id_request, const char *name, id_t *id)
+{
+       int status;
+       id_t new_id;
+       struct aspace *aspace;
+       unsigned long flags;
+
+       if ((status = idspace_alloc_id(idspace, id_request, &new_id)) != 0)
+               return status;
+
+       if ((aspace = kmem_alloc(sizeof(*aspace))) == NULL) {
+               idspace_free_id(idspace, new_id);
+               return -ENOMEM;
+       }
+
+       /*
+        * Initialize the address space. kmem_alloc() allocates zeroed memory
+        * so fields with an initial state of zero do not need to be explicitly
+        * initialized.
+        */
+       aspace->id = new_id;
+       spin_lock_init(&aspace->lock);
+       list_head_init(&aspace->region_list);
+       hlist_node_init(&aspace->ht_link);
+       if (name)
+               strlcpy(aspace->name, name, sizeof(aspace->name));
+
+       /* Create a region for the kernel portion of the address space */
+       status =
+       __aspace_add_region(
+               aspace,
+               PAGE_OFFSET,
+               ULONG_MAX-PAGE_OFFSET+1, /* # bytes to end of memory */
+               VM_KERNEL,
+               PAGE_SIZE,
+               "kernel"
+       );
+       if (status)
+               goto error1;
+
+       /* Do architecture-specific initialization */
+       if ((status = arch_aspace_create(aspace)) != 0)
+               goto error2;
+
+       /* Add new address space to a hash table, for quick lookups by ID */
+       spin_lock_irqsave(&htable_lock, flags);
+       BUG_ON(htable_add(htable, aspace));
+       spin_unlock_irqrestore(&htable_lock, flags);
+
+       if (id)
+               *id = new_id;
+       return 0;
+
+error2:
+       BUG_ON(__aspace_del_region(aspace,PAGE_OFFSET,ULONG_MAX-PAGE_OFFSET+1));
+error1:
+       idspace_free_id(idspace, aspace->id);
+       kmem_free(aspace);
+       return status;
+}
+
+int
+sys_aspace_create(id_t id_request, const char __user *name, id_t __user *id)
+{
+       int status;
+       char _name[16];
+       id_t _id;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if ((id_request != ANY_ID) && !id_ok(id_request))
+               return -EINVAL;
+
+       if (strncpy_from_user(_name, name, sizeof(_name)) < 0)
+               return -EFAULT;
+       _name[sizeof(_name) - 1] = '\0';
+
+       if ((status = aspace_create(id_request, _name, &_id)) != 0)
+               return status;
+
+       BUG_ON(!id_ok(_id));
+
+       if (id && copy_to_user(id, &_id, sizeof(*id)))
+               return -EFAULT;
+
+       return 0;
+}
+
+int
+aspace_destroy(id_t id)
+{
+       struct aspace *aspace;
+       struct list_head *pos, *tmp;
+       struct region *rgn;
+       unsigned long irqstate;
+
+       /* Lock the hash table, lookup aspace object by ID */
+       spin_lock_irqsave(&htable_lock, irqstate);
+       if ((aspace = htable_lookup(htable, id)) == NULL) {
+               spin_unlock_irqrestore(&htable_lock, irqstate);
+               return -EINVAL;
+       }
+
+       /* Lock the identified aspace */
+       spin_lock(&aspace->lock);
+
+       if (aspace->refcnt) {
+               spin_unlock(&aspace->lock);
+               spin_unlock_irqrestore(&htable_lock, irqstate);
+               return -EBUSY;
+       }
+
+       /* Remove aspace from hash table, preventing others from finding it */
+       BUG_ON(htable_del(htable, aspace));
+
+       /* Unlock the hash table, others may now use it */
+       spin_unlock_irqrestore(&htable_lock, irqstate);
+       spin_unlock(&aspace->lock);
+       /* Finish up destroying the aspace, we have the only reference */
+       list_for_each_safe(pos, tmp, &aspace->region_list) {
+               rgn = list_entry(pos, struct region, link);
+               /* Must drop our reference on all SMARTMAP'ed aspaces */
+               if (rgn->flags & VM_SMARTMAP) {
+                       struct aspace *src;
+                       spin_lock_irqsave(&htable_lock, irqstate);
+                       src = htable_lookup(htable, rgn->smartmap);
+                       BUG_ON(src == NULL);
+                       spin_lock(&src->lock);
+                       --src->refcnt;
+                       spin_unlock(&src->lock);
+                       spin_unlock_irqrestore(&htable_lock, irqstate);
+               }
+               list_del(&rgn->link);
+               kmem_free(rgn);
+       }
+       arch_aspace_destroy(aspace);
+       BUG_ON(idspace_free_id(idspace, aspace->id));
+       kmem_free(aspace);
+       return 0;
+}
+
+int
+sys_aspace_destroy(id_t id)
+{
+       if (current->uid != 0)
+               return -EPERM;
+       if (!id_ok(id))
+               return -EINVAL;
+       return aspace_destroy(id);
+}
+
+/**
+ * Acquires an address space object. The object is guaranteed not to be
+ * deleted until it is released via aspace_release().
+ */
+struct aspace *
+aspace_acquire(id_t id)
+{
+       struct aspace *aspace;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+       if ((aspace = lookup_and_lock(id)) != NULL) {
+               ++aspace->refcnt;
+               spin_unlock(&aspace->lock);
+       }
+       local_irq_restore(irqstate);
+       return aspace;
+}
+
+/**
+ * Releases an aspace object that was previously acquired via aspace_acquire().
+ * The aspace object passed in must be unlocked.
+ */
+void
+aspace_release(struct aspace *aspace)
+{
+       unsigned long irqstate;
+       spin_lock_irqsave(&aspace->lock, irqstate);
+       --aspace->refcnt;
+       spin_unlock_irqrestore(&aspace->lock, irqstate);
+}
+
+int
+__aspace_find_hole(struct aspace *aspace,
+                   vaddr_t start_hint, size_t extent, size_t alignment,
+                   vaddr_t *start)
+{
+       struct region *rgn;
+       vaddr_t hole;
+
+       if (!aspace || !extent || !is_power_of_2(alignment))
+               return -EINVAL;
+
+       if (start_hint == 0)
+               start_hint = 1;
+
+       hole = round_up(start_hint, alignment);
+       while ((rgn = find_overlapping_region(aspace, hole, hole + extent))) {
+               if (rgn->end == ULONG_MAX)
+                       return -ENOENT;
+               hole = round_up(rgn->end, alignment);
+       }
+       
+       if (start)
+               *start = hole;
+       return 0;
+}
+
+int
+aspace_find_hole(id_t id,
+                 vaddr_t start_hint, size_t extent, size_t alignment,
+                 vaddr_t *start)
+{
+       int status;
+       struct aspace *aspace;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+       aspace = lookup_and_lock(id);
+       status = __aspace_find_hole(aspace, start_hint, extent, alignment,
+                                   start);
+       if (aspace) spin_unlock(&aspace->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+sys_aspace_find_hole(id_t id,
+                     vaddr_t start_hint, size_t extent, size_t alignment,
+                     vaddr_t __user *start)
+{
+       vaddr_t _start;
+       int status;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (!id_ok(id))
+               return -EINVAL;
+
+       status = aspace_find_hole(id, start_hint, extent, alignment, &_start);
+       if (status)
+               return status;
+       
+       if (start && copy_to_user(start, &_start, sizeof(_start)))
+               return -EFAULT;
+
+       return 0;
+}
+
+int
+__aspace_add_region(struct aspace *aspace,
+                    vaddr_t start, size_t extent,
+                    vmflags_t flags, vmpagesize_t pagesz,
+                    const char *name)
+{
+       struct region *rgn;
+       struct region *cur;
+       struct list_head *pos;
+       vaddr_t end = calc_end(start, extent);
+
+       if (!aspace || !start)
+               return -EINVAL;
+
+       /* Region must have non-zero size */
+       if (extent == 0) {
+               printk(KERN_WARNING "Extent must be non-zero.\n");
+               return -EINVAL;
+       }
+
+       /* Region must have a positive size */
+       if (start >= end) {
+               printk(KERN_WARNING
+                      "Invalid region size (start=0x%lx, extent=0x%lx).\n",
+                      start, extent);
+               return -EINVAL;
+       }
+
+       /* Architecture must support the page size specified */
+       if ((pagesz & cpu_info[0].pagesz_mask) == 0) {
+               printk(KERN_WARNING
+                       "Invalid page size specified (pagesz=0x%lx).\n",
+                       pagesz);
+               return -EINVAL;
+       }
+       pagesz &= cpu_info[0].pagesz_mask;
+
+       /* Only one page size may be specified */
+       if (!is_power_of_2(pagesz)) {
+               printk(KERN_WARNING
+                      "More than one page size specified (pagesz=0x%lx).\n",
+                      pagesz);
+               return -EINVAL;
+       }
+
+       /* Region must be aligned to at least the specified page size */
+       if ((start & (pagesz-1)) || ((end!=ULONG_MAX) && (end & (pagesz-1)))) {
+               printk(KERN_WARNING
+                      "Region is misaligned (start=0x%lx, end=0x%lx).\n",
+                      start, end);
+               return -EINVAL;
+       }
+
+       /* Region must not overlap with any existing regions */
+       list_for_each_entry(cur, &aspace->region_list, link) {
+               if ((start < cur->end) && (end > cur->start)) {
+                       printk(KERN_WARNING
+                              "Region overlaps with existing region.\n");
+                       return -ENOTUNIQ;
+               }
+       }
+
+       /* Allocate and initialize a new region object */
+       if ((rgn = kmem_alloc(sizeof(struct region))) == NULL)
+               return -ENOMEM;
+
+       rgn->aspace = aspace;
+       rgn->start  = start;
+       rgn->end    = end;
+       rgn->flags  = flags;
+       rgn->pagesz = pagesz;
+       if (name)
+               strlcpy(rgn->name, name, sizeof(rgn->name));
+
+       /* The heap region is special, remember its bounds */
+       if (flags & VM_HEAP) {
+               aspace->heap_start = start;
+               aspace->heap_end   = end;
+               aspace->brk        = aspace->heap_start;
+               aspace->mmap_brk   = aspace->heap_end;
+       }
+
+       /* Insert region into address space's sorted region list */
+       list_for_each(pos, &aspace->region_list) {
+               cur = list_entry(pos, struct region, link);
+               if (cur->start > rgn->start)
+                       break;
+       }
+       list_add_tail(&rgn->link, pos);
+       return 0;
+}
+
+int
+aspace_add_region(id_t id,
+                  vaddr_t start, size_t extent,
+                  vmflags_t flags, vmpagesize_t pagesz,
+                  const char *name)
+{
+       int status;
+       struct aspace *aspace;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+       aspace = lookup_and_lock(id);
+       status = __aspace_add_region(aspace, start, extent, flags, pagesz, name);
+       if (aspace) spin_unlock(&aspace->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+sys_aspace_add_region(id_t id,
+                      vaddr_t start, size_t extent,
+                      vmflags_t flags, vmpagesize_t pagesz,
+                      const char __user *name)
+{
+       char _name[16];
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (!id_ok(id))
+               return -EINVAL;
+
+       if (strncpy_from_user(_name, name, sizeof(_name)) < 0)
+               return -EFAULT;
+       _name[sizeof(_name) - 1] = '\0';
+
+       return aspace_add_region(id, start, extent, flags, pagesz, _name);
+}
+
+
+int
+__aspace_del_region(struct aspace *aspace, vaddr_t start, size_t extent)
+{
+       int status;
+       struct region *rgn;
+       vaddr_t end = calc_end(start, extent);
+
+       if (!aspace)
+               return -EINVAL;
+
+       /* Locate the region to delete */
+       rgn = find_region(aspace, start);
+       if (!rgn || (rgn->start != start) || (rgn->end != end)
+            || (rgn->flags & VM_KERNEL))
+               return -EINVAL;
+
+       if (!(rgn->flags & VM_SMARTMAP)) {
+               /* Unmap all of the memory that was mapped to the region */
+               status = __aspace_unmap_pmem(aspace, start, extent);
+               if (status)
+                       return status;
+       }
+
+       /* Remove the region from the address space */
+       list_del(&rgn->link);
+       kmem_free(rgn);
+       return 0;
+}
+
+int
+aspace_del_region(id_t id, vaddr_t start, size_t extent)
+{
+       int status;
+       struct aspace *aspace;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+       aspace = lookup_and_lock(id);
+       status = __aspace_del_region(aspace, start, extent);
+       if (aspace) spin_unlock(&aspace->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+sys_aspace_del_region(id_t id, vaddr_t start, size_t extent)
+{
+       if (current->uid != 0)
+               return -EPERM;
+       if (!id_ok(id))
+               return -EINVAL;
+       return aspace_del_region(id, start, extent);
+}
+
+static int
+map_pmem(struct aspace *aspace,
+         paddr_t pmem, vaddr_t start, size_t extent,
+         bool umem_only)
+{
+       int status;
+       struct region *rgn;
+
+       if (!aspace)
+               return -EINVAL;
+
+       if (umem_only && !pmem_is_umem(pmem, extent)) {
+               printk(KERN_WARNING
+                      "User-space tried to map non-UMEM "
+                      "(pmem=0x%lx, extent=0x%lx).\n",
+                      pmem, extent);
+               return -EPERM;
+       }
+
+       while (extent) {
+               /* Find region covering the address */
+               rgn = find_region(aspace, start);
+               if (!rgn) {
+                       printk(KERN_WARNING
+                               "Failed to find region covering addr=0x%lx.\n",
+                               start);
+                       return -EINVAL;
+               }
+
+               /* Can't map anything to kernel or SMARTMAP regions */
+               if ((rgn->flags & VM_KERNEL) || (rgn->flags & VM_SMARTMAP)) {
+                       printk(KERN_WARNING
+                               "Trying to map memory to protected region.\n");
+                       return -EINVAL;
+               }
+
+               /* addresses must be aligned to region's page size */
+               if ((start & (rgn->pagesz-1)) || (pmem & (rgn->pagesz-1))) {
+                       printk(KERN_WARNING
+                               "Misalignment "
+                               "(start=0x%lx, pmem=0x%lx, pagesz=0x%lx).\n",
+                               start, pmem, rgn->pagesz);
+                       return -EINVAL;
+               }
+
+               /* Map until full extent mapped or end of region is reached */
+               while (extent && (start < rgn->end)) {
+
+                       status = 
+                       arch_aspace_map_page(
+                               aspace,
+                               start,
+                               pmem,
+                               rgn->flags,
+                               rgn->pagesz
+                       );
+                       if (status)
+                               return status;
+
+                       extent -= rgn->pagesz;
+                       start  += rgn->pagesz;
+                       pmem   += rgn->pagesz;
+               }
+       }
+
+       return 0;
+}
+
+static int
+map_pmem_locked(id_t id,
+                paddr_t pmem, vaddr_t start, size_t extent,
+                bool umem_only)
+{
+       int status;
+       struct aspace *aspace;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+       aspace = lookup_and_lock(id);
+       status = map_pmem(aspace, pmem, start, extent, umem_only);
+       if (aspace) spin_unlock(&aspace->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+__aspace_map_pmem(struct aspace *aspace,
+                  paddr_t pmem, vaddr_t start, size_t extent)
+{
+       return map_pmem(aspace, pmem, start, extent, false);
+}
+
+int
+aspace_map_pmem(id_t id, paddr_t pmem, vaddr_t start, size_t extent)
+{
+       return map_pmem_locked(id, pmem, start, extent, false);
+}
+
+int
+sys_aspace_map_pmem(id_t id, paddr_t pmem, vaddr_t start, size_t extent)
+{
+       if (current->uid != 0)
+               return -EPERM;
+       if (!id_ok(id))
+               return -EINVAL;
+       return map_pmem_locked(id, pmem, start, extent, true);
+}
+
+int
+__aspace_unmap_pmem(struct aspace *aspace, vaddr_t start, size_t extent)
+{
+       struct region *rgn;
+
+       if (!aspace)
+               return -EINVAL;
+
+       while (extent) {
+               /* Find region covering the address */
+               rgn = find_region(aspace, start);
+               if (!rgn) {
+                       printk(KERN_WARNING
+                               "Failed to find region covering addr=0x%lx.\n",
+                               start);
+                       return -EINVAL;
+               }
+
+               /* Can't unmap anything from kernel or SMARTMAP regions */
+               if ((rgn->flags & VM_KERNEL) || (rgn->flags & VM_SMARTMAP)) {
+                       printk(KERN_WARNING
+                               "Trying to map memory to protected region.\n");
+                       return -EINVAL;
+               }
+
+               /* address must be aligned to region's page size */
+               if (start & (rgn->pagesz-1)) {
+                       printk(KERN_WARNING
+                               "Misalignment (start=0x%lx, pagesz=0x%lx).\n",
+                               start, rgn->pagesz);
+                       return -EINVAL;
+               }
+
+               /* Unmap until full extent unmapped or end of region is reached */
+               while (extent && (start < rgn->end)) {
+
+                       arch_aspace_unmap_page(
+                               aspace,
+                               start,
+                               rgn->pagesz
+                       );
+
+                       extent -= rgn->pagesz;
+                       start  += rgn->pagesz;
+               }
+       }
+
+       return 0;
+}
+
+int
+aspace_unmap_pmem(id_t id, vaddr_t start, size_t extent)
+{
+       int status;
+       struct aspace *aspace;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+       aspace = lookup_and_lock(id);
+       status = __aspace_unmap_pmem(aspace, start, extent);
+       if (aspace) spin_unlock(&aspace->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+sys_aspace_unmap_pmem(id_t id, vaddr_t start, size_t extent)
+{
+       if (current->uid != 0)
+               return -EPERM;
+       if (!id_ok(id))
+               return -EINVAL;
+       return aspace_unmap_pmem(id, start, extent);
+}
+
+int
+__aspace_smartmap(struct aspace *src, struct aspace *dst,
+                  vaddr_t start, size_t extent)
+{
+       int status;
+       vaddr_t end = start + extent;
+       char name[16];
+       struct region *rgn;
+
+       /* Can only SMARTMAP a given aspace in once */
+       if (find_smartmap_region(dst, src->id))
+               return -EINVAL;
+
+       if (start >= end)
+               return -EINVAL;
+
+       if ((start & (SMARTMAP_ALIGN-1)) || (end & (SMARTMAP_ALIGN-1)))
+               return -EINVAL;
+
+       snprintf(name, sizeof(name), "SMARTMAP-%u", (unsigned int)src->id);
+       if ((status = __aspace_add_region(dst, start, extent,
+                                         VM_SMARTMAP, PAGE_SIZE, name)))
+               return status;
+
+       /* Do architecture-specific SMARTMAP initialization */
+       if ((status = arch_aspace_smartmap(src, dst, start, extent))) {
+               BUG_ON(__aspace_del_region(dst, start, extent));
+               return status;
+       }
+
+       /* Remember the source aspace that the SMARTMAP region is mapped to */
+       rgn = find_region(dst, start);
+       BUG_ON(!rgn);
+       rgn->smartmap = src->id;
+
+       /* Ensure source aspace doesn't go away while we have it SMARTMAP'ed */
+       ++src->refcnt;
+
+       return 0;
+}
+
+int
+aspace_smartmap(id_t src, id_t dst, vaddr_t start, size_t extent)
+{
+       int status;
+       struct aspace *src_spc, *dst_spc;
+       unsigned long irqstate;
+
+       /* Don't allow self SMARTMAP'ing */
+       if (src == dst)
+               return -EINVAL;
+
+       local_irq_save(irqstate);
+       if ((status = lookup_and_lock_two(src, dst, &src_spc, &dst_spc))) {
+               local_irq_restore(irqstate);
+               return status;
+       }
+       status = __aspace_smartmap(src_spc, dst_spc, start, extent);
+       spin_unlock(&src_spc->lock);
+       spin_unlock(&dst_spc->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+sys_aspace_smartmap(id_t src, id_t dst, vaddr_t start, size_t extent)
+{
+       if (current->uid != 0)
+               return -EPERM;
+       if (!id_ok(src) || !id_ok(dst))
+               return -EINVAL;
+       return aspace_smartmap(src, dst, start, extent);
+}
+
+int
+__aspace_unsmartmap(struct aspace *src, struct aspace *dst)
+{
+       struct region *rgn;
+       size_t extent;
+
+       if ((rgn = find_smartmap_region(dst, src->id)) == NULL)
+               return -EINVAL;
+       extent = rgn->end - rgn->start;
+
+       /* Do architecture-specific SMARTMAP unmapping */
+       BUG_ON(arch_aspace_unsmartmap(src, dst, rgn->start, extent));
+
+       /* Delete the SMARTMAP region and release our reference on the source */
+       BUG_ON(__aspace_del_region(dst, rgn->start, extent));
+       --src->refcnt;
+
+       return 0;
+}
+
+int
+aspace_unsmartmap(id_t src, id_t dst)
+{
+       int status;
+       struct aspace *src_spc, *dst_spc;
+       unsigned long irqstate;
+
+       /* Don't allow self SMARTMAP'ing */
+       if (src == dst)
+               return -EINVAL;
+
+       local_irq_save(irqstate);
+       if ((status = lookup_and_lock_two(src, dst, &src_spc, &dst_spc))) {
+               local_irq_restore(irqstate);
+               return status;
+       }
+       status = __aspace_unsmartmap(src_spc, dst_spc);
+       spin_unlock(&src_spc->lock);
+       spin_unlock(&dst_spc->lock);
+       local_irq_restore(irqstate);
+       return status;
+}
+
+int
+sys_aspace_unsmartmap(id_t src, id_t dst)
+{
+       if (current->uid != 0)
+               return -EPERM;
+       if (!id_ok(src) || !id_ok(dst))
+               return -EINVAL;
+       return aspace_unsmartmap(src, dst);
+}
+
+int
+aspace_dump2console(id_t id)
+{
+       struct aspace *aspace;
+       struct region *rgn;
+       unsigned long irqstate;
+
+       local_irq_save(irqstate);
+
+       if ((aspace = lookup_and_lock(id)) == NULL) {
+               local_irq_restore(irqstate);
+               return -EINVAL;
+       }
+
+       printk(KERN_DEBUG "DUMP OF ADDRESS SPACE %u:\n", aspace->id);
+       printk(KERN_DEBUG "  name:    %s\n", aspace->name);
+       printk(KERN_DEBUG "  refcnt:  %d\n", aspace->refcnt);
+       printk(KERN_DEBUG "  regions:\n");
+       list_for_each_entry(rgn, &aspace->region_list, link) {
+               printk(KERN_DEBUG
+                       "    [0x%016lx, 0x%016lx%c %s\n",
+                       rgn->start,
+                       rgn->end,
+                       (rgn->end == ULONG_MAX) ? ']' : ')',
+                       rgn->name
+               );
+       }
+
+       spin_unlock(&aspace->lock);
+       local_irq_restore(irqstate);
+       return 0;
+}
+
+int
+sys_aspace_dump2console(id_t id)
+{
+       return aspace_dump2console(id);
+}
diff --git a/kitten/mm/aspace_liblwk.c b/kitten/mm/aspace_liblwk.c
new file mode 120000 (symlink)
index 0000000..aa5083f
--- /dev/null
@@ -0,0 +1 @@
+../user/liblwk/aspace.c
\ No newline at end of file
diff --git a/kitten/mm/bootmem.c b/kitten/mm/bootmem.c
new file mode 100644 (file)
index 0000000..6220cf1
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ *  lwk/mm/bootmem.c
+ *
+ *  Copyright (C) 1999 Ingo Molnar
+ *  Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999
+ *
+ *  simple boot-time physical memory area allocator and
+ *  free memory collector. It's used to deal with reserved
+ *  system memory and memory holes as well.
+ */
+
+#include <lwk/init.h>
+#include <lwk/pfn.h>
+#include <lwk/bootmem.h>
+#include <lwk/params.h>
+#include <lwk/log2.h>
+#include <lwk/pmem.h>
+#include <lwk/kmem.h>
+#include <lwk/bitops.h>
+#include <arch/io.h>
+
+/**
+ * Set to true once bootmem allocator has been destroyed.
+ */
+static bool bootmem_destoyed = false;
+
+/**
+ * Access to this subsystem has to be serialized externally.
+ * (this is true for the boot process anyway)
+ */
+
+
+/**
+ * Amount of system memory to reserve for use by the kernel. The first
+ * kmem_size bytes of system memory [0, kmem_size) will be added to the
+ * kernel memory pool. The remainder of system memory is left untouched by
+ * the kernel and is available for use by applications.
+ */
+static unsigned long kmem_size = (1024 * 1024 * 8);  /* default is first 8 MB */
+param(kmem_size, ulong);
+
+
+/**
+ *
+ */
+static bootmem_data_t __initdata bootmem_data;
+
+/**
+ * List of bootmem_data structures, each describing a section of
+ * physical memory.
+ */
+static LIST_HEAD(bdata_list);
+
+/**
+ * Returns the number of _pages_ that will be allocated for the boot bitmap.
+ */
+unsigned long __init
+bootmem_bootmap_pages(unsigned long pages)
+{
+       unsigned long mapsize;
+
+       mapsize = (pages+7)/8;
+       mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
+       mapsize >>= PAGE_SHIFT;
+
+       return mapsize;
+}
+
+/**
+ * Links a newly created bootmem_data structure to the bdata_list.
+ */
+static void __init
+link_bootmem(bootmem_data_t *bdata)
+{
+       bootmem_data_t *ent;
+       if (list_empty(&bdata_list)) {
+               list_add(&bdata->list, &bdata_list);
+               return;
+       }
+       /* insert in order */
+       list_for_each_entry(ent, &bdata_list, list) {
+               if (bdata->node_boot_start < ent->node_boot_start) {
+                       list_add_tail(&bdata->list, &ent->list);
+                       return;
+               }
+       }
+       list_add_tail(&bdata->list, &bdata_list);
+       return;
+}
+
+/**
+ * Called once to set up the allocator itself.
+ */
+static unsigned long __init
+init_bootmem_core(
+       bootmem_data_t  *bdata,
+       unsigned long   mapstart,
+       unsigned long   start,
+       unsigned long   end
+)
+{
+       unsigned long mapsize = ((end - start)+7)/8;
+
+       mapsize = ALIGN(mapsize, sizeof(long));
+       bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
+       bdata->node_boot_start = (start << PAGE_SHIFT);
+       bdata->node_low_pfn = end;
+       link_bootmem(bdata);
+
+       /*
+        * Initially all pages are reserved - setup_arch() has to
+        * register free RAM areas explicitly.
+        */
+       memset(bdata->node_bootmem_map, 0xff, mapsize);
+
+       return mapsize;
+}
+
+/**
+ * Marks a particular physical memory range as unallocatable. Usable RAM
+ * might be used for boot-time allocations - or it might get added
+ * to the free page pool later on.
+ */
+static void __init
+reserve_bootmem_core(
+       bootmem_data_t  *bdata,
+       unsigned long   addr,
+       unsigned long   size
+)
+{
+       unsigned long sidx, eidx;
+       unsigned long i;
+
+       /*
+        * round up, partially reserved pages are considered
+        * fully reserved.
+        */
+       BUG_ON(!size);
+       BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn);
+       BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn);
+
+       sidx = PFN_DOWN(addr - bdata->node_boot_start);
+       eidx = PFN_UP(addr + size - bdata->node_boot_start);
+
+       for (i = sidx; i < eidx; i++) {
+               if (test_and_set_bit(i, bdata->node_bootmem_map)) {
+#ifdef CONFIG_DEBUG_BOOTMEM
+                       printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
+#endif
+               }
+       }
+}
+
+/**
+ * Frees a section of bootmemory.
+ */
+static void __init
+free_bootmem_core(
+       bootmem_data_t  *bdata,
+       unsigned long   addr,
+       unsigned long   size
+)
+{
+       unsigned long i;
+       unsigned long start;
+       /*
+        * round down end of usable mem, partially free pages are
+        * considered reserved.
+        */
+       unsigned long sidx;
+       unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE;
+       unsigned long end = (addr + size)/PAGE_SIZE;
+
+       BUG_ON(!size);
+       BUG_ON(end > bdata->node_low_pfn);
+
+       if (addr < bdata->last_success)
+               bdata->last_success = addr;
+
+       /*
+        * Round up the beginning of the address.
+        */
+       start = (addr + PAGE_SIZE-1) / PAGE_SIZE;
+       sidx = start - (bdata->node_boot_start/PAGE_SIZE);
+
+       for (i = sidx; i < eidx; i++) {
+               if (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map)))
+                       BUG();
+       }
+}
+
+/**
+ * We 'merge' subsequent allocations to save space. We might 'lose'
+ * some fraction of a page if allocations cannot be satisfied due to
+ * size constraints on boxes where there is physical RAM space
+ * fragmentation - in these cases (mostly large memory boxes) this
+ * is not a problem.
+ *
+ * On low memory boxes we get it right in 100% of the cases.
+ *
+ * alignment has to be a power of 2 value.
+ *
+ * NOTE:  This function is _not_ reentrant.
+ */
+void * __init
+__alloc_bootmem_core(
+       struct bootmem_data     *bdata,
+       unsigned long           size,
+       unsigned long           align,
+       unsigned long           goal,
+       unsigned long           limit
+)
+{
+       unsigned long offset, remaining_size, areasize, preferred;
+       unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn;
+       void *ret;
+
+       if (bootmem_destoyed)
+               panic("The bootmem allocator has been destroyed.");
+
+       if(!size) {
+               printk("__alloc_bootmem_core(): zero-sized request\n");
+               BUG();
+       }
+       BUG_ON(align & (align-1));
+
+       if (limit && bdata->node_boot_start >= limit)
+               return NULL;
+
+        limit >>=PAGE_SHIFT;
+       if (limit && end_pfn > limit)
+               end_pfn = limit;
+
+       eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
+       offset = 0;
+       if (align &&
+           (bdata->node_boot_start & (align - 1UL)) != 0)
+               offset = (align - (bdata->node_boot_start & (align - 1UL)));
+       offset >>= PAGE_SHIFT;
+
+       /*
+        * We try to allocate bootmem pages above 'goal'
+        * first, then we try to allocate lower pages.
+        */
+       if (goal && (goal >= bdata->node_boot_start) && 
+           ((goal >> PAGE_SHIFT) < end_pfn)) {
+               preferred = goal - bdata->node_boot_start;
+
+               if (bdata->last_success >= preferred)
+                       if (!limit || (limit && limit > bdata->last_success))
+                               preferred = bdata->last_success;
+       } else
+               preferred = 0;
+
+       preferred = ALIGN(preferred, align) >> PAGE_SHIFT;
+       preferred += offset;
+       areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
+       incr = align >> PAGE_SHIFT ? : 1;
+
+restart_scan:
+       for (i = preferred; i < eidx; i += incr) {
+               unsigned long j;
+               i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i);
+               i = ALIGN(i, incr);
+               if (i >= eidx)
+                       break;
+               if (test_bit(i, bdata->node_bootmem_map))
+                       continue;
+               for (j = i + 1; j < i + areasize; ++j) {
+                       if (j >= eidx)
+                               goto fail_block;
+                       if (test_bit (j, bdata->node_bootmem_map))
+                               goto fail_block;
+               }
+               start = i;
+               goto found;
+       fail_block:
+               i = ALIGN(j, incr);
+       }
+
+       if (preferred > offset) {
+               preferred = offset;
+               goto restart_scan;
+       }
+       return NULL;
+
+found:
+       bdata->last_success = start << PAGE_SHIFT;
+       BUG_ON(start >= eidx);
+
+       /*
+        * Is the next page of the previous allocation-end the start
+        * of this allocation's buffer? If yes then we can 'merge'
+        * the previous partial page with this allocation.
+        */
+       if (align < PAGE_SIZE &&
+           bdata->last_offset && bdata->last_pos+1 == start) {
+               offset = ALIGN(bdata->last_offset, align);
+               BUG_ON(offset > PAGE_SIZE);
+               remaining_size = PAGE_SIZE-offset;
+               if (size < remaining_size) {
+                       areasize = 0;
+                       /* last_pos unchanged */
+                       bdata->last_offset = offset+size;
+                       ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
+                                               bdata->node_boot_start);
+               } else {
+                       remaining_size = size - remaining_size;
+                       areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE;
+                       ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
+                                               bdata->node_boot_start);
+                       bdata->last_pos = start+areasize-1;
+                       bdata->last_offset = remaining_size;
+               }
+               bdata->last_offset &= ~PAGE_MASK;
+       } else {
+               bdata->last_pos = start + areasize - 1;
+               bdata->last_offset = size & ~PAGE_MASK;
+               ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);
+       }
+
+       /*
+        * Reserve the area now:
+        */
+       for (i = start; i < start+areasize; i++)
+               if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
+                       BUG();
+       memset(ret, 0, size);
+       return ret;
+}
+
+static void __init
+free_all_bootmem_core(struct bootmem_data *bdata)
+{
+       unsigned long pfn;
+       unsigned long vaddr;
+       unsigned long i, m, count;
+       unsigned long bootmem_total=0, kmem_total=0, umem_total=0;
+       unsigned long kmem_max_idx, max_idx;
+       unsigned long *map; 
+       struct pmem_region rgn;
+
+       BUG_ON(!bdata->node_bootmem_map);
+
+       kmem_max_idx = (kmem_size >> PAGE_SHIFT) - (bdata->node_boot_start >> PAGE_SHIFT);
+       max_idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
+       BUG_ON(kmem_max_idx > max_idx);
+
+       /* Create the initial kernel managed memory pool (kmem) */
+       count = 0;
+       pfn = bdata->node_boot_start >> PAGE_SHIFT;  /* first extant page of node */
+       map = bdata->node_bootmem_map;
+       for (i = 0; i < kmem_max_idx; ) {
+               unsigned long v = ~map[i / BITS_PER_LONG];
+
+               if (v) {
+                       vaddr = (unsigned long) __va(pfn << PAGE_SHIFT);
+                       for (m = 1; m && i < kmem_max_idx; m<<=1, vaddr+=PAGE_SIZE, i++) {
+                               if (v & m) {
+                                       count++;
+                                       kmem_add_memory(vaddr, PAGE_SIZE);
+                               }
+                       }
+               } else {
+                       i+=BITS_PER_LONG;
+               }
+               pfn += BITS_PER_LONG;
+       }
+       BUG_ON(count == 0);
+
+       /*
+        * At this point, kmem_alloc() will work. The physical memory tracking
+        * code relies on kmem_alloc(), so it cannot be initialized until now.
+        *
+        * Tell the physical memory tracking subsystem about the kernel-managed
+        * pool and the remaining memory that will be managed by user-space.
+        */
+       pfn = bdata->node_boot_start >> PAGE_SHIFT;  /* first extant page of node */
+       map = bdata->node_bootmem_map;
+       pmem_region_unset_all(&rgn);
+       rgn.type_is_set = true;
+       rgn.allocated_is_set = true;
+       rgn.lgroup_is_set = true;
+       for (i = 0; i < max_idx; ) {
+               unsigned long v = ~map[i / BITS_PER_LONG];
+               unsigned long paddr = (unsigned long) pfn << PAGE_SHIFT;
+
+               for (m = 1; m && i < max_idx; m<<=1, paddr+=PAGE_SIZE, i++) {
+                       rgn.start = paddr;
+                       rgn.end   = paddr + PAGE_SIZE;
+
+                       if (v & m) {
+                               if (i < kmem_max_idx) {
+                                       rgn.type = PMEM_TYPE_KMEM;
+                                       rgn.allocated = true;
+                                       rgn.lgroup = 0;
+                                       ++kmem_total;
+                               } else {
+                                       rgn.type = PMEM_TYPE_UMEM;
+                                       rgn.allocated = false;
+                                       rgn.lgroup = 0;
+                                       ++umem_total;
+                               }
+                       } else {
+                               rgn.type = PMEM_TYPE_BOOTMEM;
+                               rgn.allocated = true;
+                               rgn.lgroup = 0;
+                               ++bootmem_total;
+                       }
+
+                       if (pmem_add(&rgn))
+                               BUG();
+               }
+
+               pfn += BITS_PER_LONG;
+       }
+
+       /*
+        * Now free the allocator bitmap itself, it's not
+        * needed anymore:
+        */
+       vaddr = (unsigned long)bdata->node_bootmem_map;
+       count = 0;
+       pmem_region_unset_all(&rgn);
+       rgn.type_is_set = true;
+       rgn.allocated_is_set = true;
+       rgn.lgroup_is_set = true;
+       for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,vaddr+=PAGE_SIZE) {
+               count++;
+
+               rgn.start = __pa(vaddr);
+               rgn.end   = rgn.start + PAGE_SIZE;
+
+               if (i < kmem_max_idx) {
+                       kmem_add_memory(vaddr, PAGE_SIZE);
+                       rgn.type = PMEM_TYPE_KMEM;
+                       rgn.allocated = true;
+                       rgn.lgroup = 0;
+               } else {
+                       rgn.type = PMEM_TYPE_UMEM;
+                       rgn.allocated = false;
+                       rgn.lgroup = 0;
+               }
+
+               pmem_add(&rgn);
+       }
+       BUG_ON(count == 0);
+
+       /* Mark the bootmem allocator as dead */
+       bdata->node_bootmem_map = NULL;
+
+       printk(KERN_DEBUG
+              "The boot-strap bootmem allocator has been destroyed:\n");
+       printk(KERN_DEBUG
+              "  %lu bytes released to the kernel-managed memory pool (kmem)\n",
+              kmem_total << PAGE_SHIFT);
+       printk(KERN_DEBUG
+              "  %lu bytes released to the user-managed memory pool (umem)\n",
+              umem_total << PAGE_SHIFT);
+}
+
+/**
+ * Initialize boot memory allocator.
+ */
+unsigned long __init
+init_bootmem(unsigned long start, unsigned long pages)
+{
+       return init_bootmem_core(&bootmem_data, start, 0, pages);
+}
+
+/**
+ * Reserve a portion of the boot memory.
+ * This prevents the reserved memory from being allocated.
+ */
+void __init
+reserve_bootmem(unsigned long addr, unsigned long size)
+{
+       reserve_bootmem_core(&bootmem_data, addr, size);
+}
+
+/**
+ * Return a portion of boot memory to the free pool.
+ * Note that the region freed is the set of pages covering
+ * the byte range [addr, addr+size).
+ */
+void __init
+free_bootmem(unsigned long addr, unsigned long size)
+{
+       free_bootmem_core(&bootmem_data, addr, size);
+}
+
+void __init
+free_all_bootmem(void)
+{
+       free_all_bootmem_core(&bootmem_data);
+       bootmem_destoyed = true;
+}
+
+static void * __init
+__alloc_bootmem_nopanic(unsigned long size, unsigned long align, unsigned long goal)
+{
+       bootmem_data_t *bdata;
+       void *ptr;
+
+       list_for_each_entry(bdata, &bdata_list, list)
+               if ((ptr = __alloc_bootmem_core(bdata, size, align, goal, 0)))
+                       return(ptr);
+       return NULL;
+}
+
+/**
+ * Allocate a chunk of memory from the boot memory allocator.
+ *
+ *     size  = number of bytes requested
+ *     align = required alignment
+ *     goal  = hint specifying address to start search.
+ */
+void * __init
+__alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal)
+{
+       void *mem = __alloc_bootmem_nopanic(size,align,goal);
+       if (mem)
+               return mem;
+       /*
+        * Whoops, we cannot satisfy the allocation request.
+        */
+       printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+       panic("Out of memory");
+       return NULL;
+}
+
+/**
+ * Allocates a block of memory of the specified size.
+ */
+void * __init
+alloc_bootmem(unsigned long size)
+{
+       return __alloc_bootmem(size, SMP_CACHE_BYTES, 0);
+}
+
+/**
+ * Allocates a block of memory of the specified size and alignment.
+ */
+void * __init
+alloc_bootmem_aligned(unsigned long size, unsigned long align)
+{
+       return __alloc_bootmem(size, align, 0);
+}
+
+/**
+ * Initializes the kernel memory subsystem.
+ */
+void __init
+mem_subsys_init(void)
+{
+       /* We like powers of two */
+       if (!is_power_of_2(kmem_size)) {
+               printk(KERN_WARNING "kmem_size must be a power of two.");
+               kmem_size = roundup_pow_of_two(kmem_size);
+       }
+
+       printk(KERN_DEBUG
+              "First %lu bytes of system memory reserved for the kernel.\n",
+              kmem_size);
+
+       /* Initialize the kernel memory pool */
+       kmem_create_zone(PAGE_OFFSET, kmem_size);
+       free_all_bootmem();
+       arch_memsys_init(kmem_size);
+}
+
diff --git a/kitten/mm/buddy.c b/kitten/mm/buddy.c
new file mode 100644 (file)
index 0000000..ad132cb
--- /dev/null
@@ -0,0 +1,274 @@
+/* Copyright (c) 2007, Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/log2.h>
+#include <lwk/buddy.h>
+#include <lwk/bootmem.h>
+
+
+/**
+ * Each free block has one of these structures at its head. The link member
+ * provides linkage for the mp->avail[order] free list, where order is the
+ * size of the free block.
+ */
+struct block {
+       struct list_head link;
+       unsigned long    order;
+};
+
+
+/**
+ * Converts a block address to its block index in the specified buddy allocator.
+ * A block's index is used to find the block's tag bit, mp->tag_bits[block_id].
+ */
+static unsigned long
+block_to_id(struct buddy_mempool *mp, struct block *block)
+{
+       unsigned long block_id =
+               ((unsigned long)block - mp->base_addr) >> mp->min_order;
+       BUG_ON(block_id >= mp->num_blocks);
+       return block_id;
+}
+
+
+/**
+ * Marks a block as free by setting its tag bit to one.
+ */
+static void
+mark_available(struct buddy_mempool *mp, struct block *block)
+{
+       __set_bit(block_to_id(mp, block), mp->tag_bits);
+}
+
+
+/**
+ * Marks a block as allocated by setting its tag bit to zero.
+ */
+static void
+mark_allocated(struct buddy_mempool *mp, struct block *block)
+{
+       __clear_bit(block_to_id(mp, block), mp->tag_bits);
+}
+
+
+/**
+ * Returns true if block is free, false if it is allocated.
+ */
+static int
+is_available(struct buddy_mempool *mp, struct block *block)
+{
+       return test_bit(block_to_id(mp, block), mp->tag_bits);
+}
+
+
+/**
+ * Returns the address of the block's buddy block.
+ */
+static void *
+find_buddy(struct buddy_mempool *mp, struct block *block, unsigned long order)
+{
+       unsigned long _block;
+       unsigned long _buddy;
+
+       BUG_ON((unsigned long)block < mp->base_addr);
+
+       /* Fixup block address to be zero-relative */
+       _block = (unsigned long)block - mp->base_addr;
+
+       /* Calculate buddy in zero-relative space */
+       _buddy = _block ^ (1UL << order);
+
+       /* Return the buddy's address */
+       return (void *)(_buddy + mp->base_addr);
+}
+
+
+/**
+ * Initializes a buddy system memory allocator object.
+ *
+ * Arguments:
+ *       [IN] base_addr:  Base address of the memory pool.
+ *       [IN] pool_order: Size of the memory pool (2^pool_order bytes).
+ *       [IN] min_order:  Minimum allocatable block size (2^min_order bytes).
+ *
+ * Returns:
+ *       Success: Pointer to an initialized buddy system memory allocator.
+ *       Failure: NULL
+ *
+ * NOTE: The min_order argument is provided as an optimization. Since one tag
+ *       bit is required for each minimum-sized block, large memory pools that
+ *       allow order 0 allocations will use large amounts of memory. Specifying
+ *       a min_order of 5 (32 bytes), for example, reduces the number of tag
+ *       bits by 32x.
+ */
+struct buddy_mempool *
+buddy_init(
+       unsigned long base_addr,
+       unsigned long pool_order,
+       unsigned long min_order
+)
+{
+       struct buddy_mempool *mp;
+       unsigned long i;
+
+       /* Smallest block size must be big enough to hold a block structure */
+       if ((1UL << min_order) < sizeof(struct block))
+               min_order = ilog2( roundup_pow_of_two(sizeof(struct block)) );
+
+       /* The minimum block order must be smaller than the pool order */
+       if (min_order > pool_order)
+               return NULL;
+
+       mp = alloc_bootmem(sizeof(struct buddy_mempool));
+       
+       mp->base_addr  = base_addr;
+       mp->pool_order = pool_order;
+       mp->min_order  = min_order;
+
+       /* Allocate a list for every order up to the maximum allowed order */
+       mp->avail = alloc_bootmem((pool_order + 1) * sizeof(struct list_head));
+
+       /* Initially all lists are empty */
+       for (i = 0; i <= pool_order; i++)
+               INIT_LIST_HEAD(&mp->avail[i]);
+
+       /* Allocate a bitmap with 1 bit per minimum-sized block */
+       mp->num_blocks = (1UL << pool_order) / (1UL << min_order);
+       mp->tag_bits   = alloc_bootmem(
+                            BITS_TO_LONGS(mp->num_blocks) * sizeof(long)
+                        );
+
+       /* Initially mark all minimum-sized blocks as allocated */
+       bitmap_zero(mp->tag_bits, mp->num_blocks);
+
+       return mp;
+}
+
+
+/**
+ * Allocates a block of memory of the requested size (2^order bytes).
+ *
+ * Arguments:
+ *       [IN] mp:    Buddy system memory allocator object.
+ *       [IN] order: Block size to allocate (2^order bytes).
+ *
+ * Returns:
+ *       Success: Pointer to the start of the allocated memory block.
+ *       Failure: NULL
+ */
+void *
+buddy_alloc(struct buddy_mempool *mp, unsigned long order)
+{
+       unsigned long j;
+       struct list_head *list;
+       struct block *block;
+       struct block *buddy_block;
+
+       BUG_ON(mp == NULL);
+       BUG_ON(order > mp->pool_order);
+
+       /* Fixup requested order to be at least the minimum supported */
+       if (order < mp->min_order)
+               order = mp->min_order;
+
+       for (j = order; j <= mp->pool_order; j++) {
+
+               /* Try to allocate the first block in the order j list */
+               list = &mp->avail[j];
+               if (list_empty(list))
+                       continue;
+               block = list_entry(list->next, struct block, link);
+               list_del(&block->link);
+               mark_allocated(mp, block);
+
+               /* Trim if a higher order block than necessary was allocated */
+               while (j > order) {
+                       --j;
+                       buddy_block = (struct block *)((unsigned long)block + (1UL << j));
+                       buddy_block->order = j;
+                       mark_available(mp, buddy_block);
+                       list_add(&buddy_block->link, &mp->avail[j]);
+               }
+
+               return block;
+       }
+
+       return NULL;
+}
+
+
+/**
+ * Returns a block of memory to the buddy system memory allocator.
+ *
+ * Arguments:
+ *       [IN] mp:    Buddy system memory allocator object.
+ *       [IN] addr:  Address of memory block to free.
+ *       [IN] order: Size of the memory block (2^order bytes).
+ */
+void
+buddy_free(struct buddy_mempool *mp, void *addr, unsigned long order)
+{
+       struct block *block;
+       struct block *buddy;
+
+       BUG_ON(mp == NULL);
+       BUG_ON(order > mp->pool_order);
+
+       /* Fixup requested order to be at least the minimum supported */
+       if (order < mp->min_order)
+               order = mp->min_order;
+
+       /* Overlay block structure on the memory block being freed */
+       block = addr;
+       BUG_ON(is_available(mp, block));
+
+       /* Coalesce as much as possible with adjacent free buddy blocks */
+       while (order < mp->pool_order) {
+               /* Determine our buddy block's address */
+               buddy = find_buddy(mp, block, order);
+
+               /* Make sure buddy is available and has the same size as us */
+               if (!is_available(mp, buddy))
+                       break;
+               if (is_available(mp, buddy) && (buddy->order != order))
+                       break;
+
+               /* OK, we're good to go... buddy merge! */
+               list_del(&buddy->link);
+               if (buddy < block)
+                       block = buddy;
+               ++order;
+               block->order = order;
+       }
+
+       /* Add the (possibly coalesced) block to the appropriate free list */
+       block->order = order;
+       mark_available(mp, block);
+       list_add(&block->link, &mp->avail[order]);
+}
+
+
+/**
+ * Dumps the state of a buddy system memory allocator object to the console.
+ */
+void
+buddy_dump_mempool(struct buddy_mempool *mp)
+{
+       unsigned long i;
+       unsigned long num_blocks;
+       struct list_head *entry;
+
+       printk(KERN_DEBUG "DUMP OF BUDDY MEMORY POOL:\n");
+
+       for (i = mp->min_order; i <= mp->pool_order; i++) {
+
+               /* Count the number of memory blocks in the list */
+               num_blocks = 0;
+               list_for_each(entry, &mp->avail[i])
+                       ++num_blocks;
+
+               printk(KERN_DEBUG "  order %2lu: %lu free blocks\n", i, num_blocks);
+       }
+}
+
+
diff --git a/kitten/mm/kmem.c b/kitten/mm/kmem.c
new file mode 100644 (file)
index 0000000..693054a
--- /dev/null
@@ -0,0 +1,240 @@
+/* Copyright (c) 2007, Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/buddy.h>
+#include <lwk/log2.h>
+
+
+/**
+ * This specifies the minimum sized memory block to request from the underlying
+ * buddy system memory allocator, 2^MIN_ORDER bytes. It must be at least big
+ * enough to hold a 'struct kmem_block_hdr'.
+ */
+#define MIN_ORDER      5  /* 32 bytes */
+
+
+/**
+ * Magic value used for sanity checking. Every block of memory allocated via
+ * kmem_alloc() has this value in its block header.
+ */
+#define KMEM_MAGIC     0xF0F0F0F0F0F0F0F0UL
+
+
+/**
+ * The kernel memory pool. This manages all memory available for dynamic
+ * allocation by the kernel. The kernel reserves some amount of memory
+ * (e.g., the first 8 MB, amount specifiable on kernel boot command line) for
+ * its own use, included in which is the kernel memory pool. The rest of memory
+ * is reserved for user applications.
+ *
+ * NOTE: There is currently only one buddy_mempool for the entire system.
+ *       This may change to one per NUMA node in the future.
+ */
+static struct buddy_mempool *kmem = NULL;
+
+
+/**
+ * Total number of bytes in the kernel memory pool.
+ */
+static unsigned long kmem_bytes_managed;
+
+
+/**
+ * Total number of bytes allocated from the kernel memory pool.
+ */
+static unsigned long kmem_bytes_allocated;
+
+
+/**
+ * Each block of memory allocated from the kernel memory pool has one of these
+ * structures at its head. The structure contains information needed to free
+ * the block and return it to the underlying memory allocator.
+ *
+ * When a block is allocated, the address returned to the caller is
+ * sizeof(struct kmem_block_hdr) bytes greater than the block allocated from
+ * the underlying memory allocator.
+ *
+ * WARNING: This structure is defined to be exactly 16 bytes in size.
+ *          Do not change this unless you really know what you are doing.
+ */
+struct kmem_block_hdr {
+       uint64_t order;  /* order of the block allocated from buddy system */
+       uint64_t magic;  /* magic value used as sanity check */
+} __attribute__((packed));
+
+
+/**
+ * This adds a zone to the kernel memory pool. Zones exist to allow there to be
+ * multiple non-adjacent regions of physically contiguous memory. The
+ * bookkeeping needed to cover the gaps would waste a lot of memory and have no
+ * benefit.
+ *
+ * Arguments:
+ *       [IN] base_addr: Base address of the memory pool.
+ *       [IN] size:      Size of the memory pool in bytes.
+ *
+ * NOTE: Currently only one zone is supported. Calling kmem_create_zone() more
+ *       than once will result in a panic.
+ */
+void
+kmem_create_zone(unsigned long base_addr, size_t size)
+{
+       unsigned long pool_order = ilog2(roundup_pow_of_two(size));
+       unsigned long min_order  = MIN_ORDER;
+
+       /* For now, protect against calling kmem_create_zone() more than once */
+       BUG_ON(kmem != NULL);
+
+       /* Initialize the underlying buddy allocator */
+       if ((kmem = buddy_init(base_addr, pool_order, min_order)) == NULL)
+               panic("buddy_init() failed.");
+}
+
+
+/**
+ * This adds memory to the kernel memory pool. The memory region being added
+ * must fall within a zone previously specified via kmem_create_zone().
+ *
+ * Arguments:
+ *       [IN] base_addr: Base address of the memory region to add.
+ *       [IN] size:      Size of the memory region in bytes.
+ */
+void
+kmem_add_memory(unsigned long base_addr, size_t size)
+{
+       /*
+        * kmem buddy allocator is initially empty.
+        * Memory is added to it via buddy_free().
+        * buddy_free() will panic if there are any problems with the args.
+        */
+       buddy_free(kmem, (void *)base_addr, ilog2(size));
+
+       /* Update statistics */
+       kmem_bytes_managed += size;
+}
+
+
+/**
+ * Allocates memory from the kernel memory pool. This will return a memory
+ * region that is at least 16-byte aligned. The memory returned is zeroed.
+ *
+ * Arguments:
+ *       [IN] size: Amount of memory to allocate in bytes.
+ *
+ * Returns:
+ *       Success: Pointer to the start of the allocated memory.
+ *       Failure: NULL
+ */
+void *
+kmem_alloc(size_t size)
+{
+       unsigned long order;
+       struct kmem_block_hdr *hdr;
+
+       /* Make room for block header */
+       size += sizeof(struct kmem_block_hdr);
+
+       /* Calculate the block order needed */
+       order = ilog2(roundup_pow_of_two(size));
+       if (order < MIN_ORDER)
+               order = MIN_ORDER;
+
+       /* Allocate memory from the underlying buddy system */
+       if ((hdr = buddy_alloc(kmem, order)) == NULL)
+               return NULL;
+
+       /* Zero the block */
+       memset(hdr, 0, (1UL << order));
+
+       /* Initialize the block header */
+       hdr->order = order;       /* kmem_free() needs this to free the block */
+       hdr->magic = KMEM_MAGIC;  /* used for sanity check */
+
+       /* Update statistics */
+       kmem_bytes_allocated += (1UL << order);
+
+       /* Return address of first byte after block header to caller */
+       return hdr + 1;
+}
+
+
+/**
+ * Frees memory previously allocated with kmem_alloc().
+ *
+ * Arguments:
+ *       [IN] addr: Address of the memory region to free.
+ *
+ * NOTE: The size of the memory region being freed is assumed to be in a
+ *       'struct kmem_block_hdr' header located immediately before the address
+ *       passed in by the caller. This header is created and initialized by
+ *       kmem_alloc().
+ */
+void
+kmem_free(void *addr)
+{
+       struct kmem_block_hdr *hdr;
+
+       BUG_ON((unsigned long)addr < sizeof(struct kmem_block_hdr));
+
+       /* Find the block header */
+       hdr = (struct kmem_block_hdr *)addr - 1;
+       BUG_ON(hdr->magic != KMEM_MAGIC);
+
+       /* Return block to the underlying buddy system */
+       buddy_free(kmem, hdr, hdr->order);
+
+       kmem_bytes_allocated -= (1 << hdr->order);
+}
+
+
+/**
+ * Allocates pages of memory from the kernel memory pool. The number of pages
+ * requested must be a power of two and the returned pages will be contiguous
+ * in physical memory. The memory returned is zeroed.
+ *
+ * Arguments:
+ *       [IN] order: Number of pages to allocated, 2^order:
+ *                       0 = 1 page
+ *                       1 = 2 pages
+ *                       2 = 4 pages
+ *                       3 = 8 pages
+ *                       ...
+ * Returns:
+ *       Success: Pointer to the start of the allocated memory.
+ *       Failure: NULL
+ */
+void *
+kmem_get_pages(unsigned long order)
+{
+       unsigned long block_order;
+       void *addr;
+
+       /* Calculate the block size needed; convert page order to byte order */
+       block_order = order + ilog2(PAGE_SIZE);
+
+       /* Allocate memory from the underlying buddy system */
+       if ((addr = buddy_alloc(kmem, block_order)) == NULL)
+               return NULL;
+
+       /* Zero the block and return its address */
+       memset(addr, 0, (1UL << block_order));
+       return addr;
+}
+
+
+/**
+ * Frees pages of memory previously allocated with kmem_get_pages().
+ *
+ * Arguments:
+ *       [IN] addr:  Address of the memory region to free.
+ *       [IN] order: Number of pages to free, 2^order.
+ *                   The order must match the value passed to kmem_get_pages()
+ *                   when the pages were allocated.
+ */
+void
+kmem_free_pages(void *addr, unsigned long order)
+{
+       buddy_free(kmem, addr, order + ilog2(PAGE_SIZE));
+}
+
+
diff --git a/kitten/mm/pmem.c b/kitten/mm/pmem.c
new file mode 100644 (file)
index 0000000..b1cbc9b
--- /dev/null
@@ -0,0 +1,478 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/kernel.h>
+#include <lwk/spinlock.h>
+#include <lwk/string.h>
+#include <lwk/list.h>
+#include <lwk/log2.h>
+#include <lwk/pmem.h>
+#include <arch/uaccess.h>
+
+static LIST_HEAD(pmem_list);
+static DEFINE_SPINLOCK(pmem_list_lock);
+
+struct pmem_list_entry {
+       struct list_head        link;
+       struct pmem_region      rgn;
+};
+
+static struct pmem_list_entry *
+alloc_pmem_list_entry(void)
+{
+       return kmem_alloc(sizeof(struct pmem_list_entry));
+}
+
+static void
+free_pmem_list_entry(struct pmem_list_entry *entry)
+{
+       kmem_free(entry);
+}
+
+static bool
+calc_overlap(const struct pmem_region *a, const struct pmem_region *b,
+             struct pmem_region *dst)
+{
+       if (!((a->start < b->end) && (a->end > b->start)))
+               return false;
+
+       if (dst) {
+               dst->start = max(a->start, b->start);
+               dst->end   = min(a->end, b->end);
+       }
+
+       return true;
+}
+
+static bool
+regions_overlap(const struct pmem_region *a, const struct pmem_region *b)
+{
+       return calc_overlap(a, b, NULL);
+}
+
+static bool
+region_is_unique(const struct pmem_region *rgn)
+{
+       struct pmem_list_entry *entry;
+
+       list_for_each_entry(entry, &pmem_list, link) {
+               if (regions_overlap(rgn, &entry->rgn))
+                       return false;
+       }
+       return true;
+}
+
+static bool
+region_is_sane(const struct pmem_region *rgn)
+{
+       int i;
+
+       if (!rgn)
+               return false;
+
+       if (rgn->end <= rgn->start)
+               return false;
+
+       for (i = 0; i < sizeof(rgn->name); i++)  {
+               if (rgn->name[i] == '\0')
+                       break;
+       }
+       if (i == sizeof(rgn->name))
+               return false;
+
+       return true;
+}
+
+static bool
+region_is_known(const struct pmem_region *rgn)
+{
+       struct pmem_list_entry *entry;
+       struct pmem_region overlap;
+       size_t size;
+
+       size = rgn->end - rgn->start;
+       list_for_each_entry(entry, &pmem_list, link) {
+               if (!calc_overlap(rgn, &entry->rgn, &overlap))
+                       continue;
+
+               size -= (overlap.end - overlap.start);
+       }
+
+       return (size == 0) ? true : false;
+}
+
+static void
+insert_pmem_list_entry(struct pmem_list_entry *entry)
+{
+       struct list_head *pos;
+       struct pmem_list_entry *cur;
+
+       /* Locate the entry that the new entry should be inserted before */
+       list_for_each(pos, &pmem_list) {
+               cur = list_entry(pos, struct pmem_list_entry, link);
+               if (cur->rgn.start > entry->rgn.start)
+                       break;
+       }
+       list_add_tail(&entry->link, pos);
+}
+
+static bool
+regions_are_mergeable(const struct pmem_region *a, const struct pmem_region *b)
+{
+       if ((a->end != b->start) && (b->end != a->start))
+               return false;
+
+       if (a->type_is_set != b->type_is_set)
+               return false;
+       if (a->type_is_set && (a->type != b->type))
+               return false;
+
+       if (a->lgroup_is_set != b->lgroup_is_set)
+               return false;
+       if (a->lgroup_is_set && (a->lgroup != b->lgroup))
+               return false;
+
+       if (a->allocated_is_set != b->allocated_is_set)
+               return false;
+       if (a->allocated_is_set && (a->allocated != b->allocated))
+               return false;
+
+       if (a->name_is_set != b->name_is_set)
+               return false;
+       if (a->name_is_set && !strcmp(a->name, b->name))
+               return false;
+
+       return true;
+}
+
+static bool
+region_matches(const struct pmem_region *query, const struct pmem_region *rgn)
+{
+       if (!regions_overlap(query, rgn))
+               return false;
+
+       if (query->type_is_set
+             && (!rgn->type_is_set || (rgn->type != query->type)))
+               return false;
+
+       if (query->lgroup_is_set
+             && (!rgn->lgroup_is_set || (rgn->lgroup != query->lgroup)))
+               return false;
+
+       if (query->allocated_is_set
+             && (!rgn->allocated_is_set || (rgn->allocated != query->allocated)))
+               return false;
+
+       if (query->name_is_set
+             && (!rgn->name_is_set || strcmp(rgn->name, query->name)))
+               return false;
+
+       return true;
+}
+
+static void
+merge_pmem_list(void)
+{
+       struct pmem_list_entry *entry, *prev, *tmp;
+
+       prev = NULL;
+       list_for_each_entry_safe(entry, tmp, &pmem_list, link) {
+               if (prev && regions_are_mergeable(&prev->rgn, &entry->rgn)) {
+                       prev->rgn.end = entry->rgn.end;
+                       list_del(&entry->link);
+                       free_pmem_list_entry(entry);
+               } else {
+                       prev = entry;
+               }
+       }
+}
+
+static void
+zero_pmem(const struct pmem_region *rgn)
+{
+       /* access pmem region via the kernel's identity map */
+       memset(__va(rgn->start), 0, rgn->end - rgn->start);
+}
+
+static int
+__pmem_add(const struct pmem_region *rgn)
+{
+       struct pmem_list_entry *entry;
+
+       if (!region_is_sane(rgn))
+               return -EINVAL;
+
+       if (!region_is_unique(rgn))
+               return -EEXIST;
+
+       if (!(entry = alloc_pmem_list_entry()))
+               return -ENOMEM;
+       
+       entry->rgn = *rgn;
+
+       insert_pmem_list_entry(entry);
+       merge_pmem_list();
+
+       return 0;
+}
+
+int
+pmem_add(const struct pmem_region *rgn)
+{
+       int status;
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&pmem_list_lock, irqstate);
+       status = __pmem_add(rgn);
+       spin_unlock_irqrestore(&pmem_list_lock, irqstate);
+
+       return status;
+}
+
+int
+sys_pmem_add(const struct pmem_region __user *rgn)
+{
+       struct pmem_region _rgn;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (copy_from_user(&_rgn, rgn, sizeof(_rgn)))
+               return -EINVAL;
+
+       return pmem_add(&_rgn);
+}
+
+static int
+__pmem_update(const struct pmem_region *update, bool umem_only)
+{
+       struct pmem_list_entry *entry, *head, *tail;
+       struct pmem_region overlap;
+
+       if (!region_is_sane(update))
+               return -EINVAL;
+
+       if (!region_is_known(update))
+               return -ENOENT;
+
+       list_for_each_entry(entry, &pmem_list, link) {
+               if (!calc_overlap(update, &entry->rgn, &overlap))
+                       continue;
+
+               /* Jail user-space to PMEM_TYPE_UMEM regions */
+               if (umem_only) {
+                       if (!entry->rgn.type_is_set
+                            || (entry->rgn.type != PMEM_TYPE_UMEM))
+                               return -EPERM;
+                       if (!update->type_is_set
+                            || (update->type != PMEM_TYPE_UMEM))
+                               return -EPERM;
+               }
+
+               /* Handle head of entry non-overlap */
+               if (entry->rgn.start < overlap.start) {
+                       if (!(head = alloc_pmem_list_entry()))
+                               return -ENOMEM;
+                       head->rgn = entry->rgn;
+                       head->rgn.end = overlap.start;
+                       list_add_tail(&head->link, &entry->link);
+               }
+
+               /* Handle tail of entry non-overlap */
+               if (entry->rgn.end > overlap.end) {
+                       if (!(tail = alloc_pmem_list_entry()))
+                               return -ENOMEM;
+                       tail->rgn = entry->rgn;
+                       tail->rgn.start = overlap.end;
+                       list_add(&tail->link, &entry->link);
+               }
+
+               /* Update entry to reflect the overlap */
+               entry->rgn = *update;
+               entry->rgn.start = overlap.start;
+               entry->rgn.end   = overlap.end;
+       }
+
+       merge_pmem_list();
+
+       return 0;
+}
+
+static int
+_pmem_update(const struct pmem_region *update, bool umem_only)
+{
+       int status;
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&pmem_list_lock, irqstate);
+       status = __pmem_update(update, umem_only);
+       spin_unlock_irqrestore(&pmem_list_lock, irqstate);
+
+       return status;
+}
+
+int
+pmem_update(const struct pmem_region *update)
+{
+       return _pmem_update(update, false);
+}
+
+int
+sys_pmem_update(const struct pmem_region __user *update)
+{
+       struct pmem_region _update;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (copy_from_user(&_update, update, sizeof(_update)))
+               return -EINVAL;
+
+       return _pmem_update(&_update, true);
+}
+
+static int
+__pmem_query(const struct pmem_region *query, struct pmem_region *result)
+{
+       struct pmem_list_entry *entry;
+       struct pmem_region *rgn;
+
+       if (!region_is_sane(query))
+               return -EINVAL;
+
+       list_for_each_entry(entry, &pmem_list, link) {
+               rgn = &entry->rgn;
+               if (!region_matches(query, rgn))
+                       continue;
+
+               /* match found, update result */
+               if (result) {
+                       *result = *rgn;
+                       calc_overlap(query, rgn, result);
+               }
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+int
+pmem_query(const struct pmem_region *query, struct pmem_region *result)
+{
+       int status;
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&pmem_list_lock, irqstate);
+       status = __pmem_query(query, result);
+       spin_unlock_irqrestore(&pmem_list_lock, irqstate);
+
+       return status;
+}
+
+int
+sys_pmem_query(const struct pmem_region __user *query,
+               struct pmem_region __user *result)
+{
+       struct pmem_region _query, _result;
+       int status;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (copy_from_user(&_query, query, sizeof(_query)))
+               return -EINVAL;
+
+       if ((status = pmem_query(&_query, &_result)) != 0)
+               return status;
+
+       if (result && copy_to_user(result, &_result, sizeof(*result)))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int
+__pmem_alloc(size_t size, size_t alignment,
+             const struct pmem_region *constraint,
+             struct pmem_region *result)
+{
+       int status;
+       struct pmem_region query;
+       struct pmem_region candidate;
+
+       if (size == 0)
+               return -EINVAL;
+
+       if (alignment && !is_power_of_2(alignment))
+               return -EINVAL;
+
+       if (!region_is_sane(constraint))
+               return -EINVAL;
+
+       if (constraint->allocated_is_set && constraint->allocated)
+               return -EINVAL;
+
+       query = *constraint;
+
+       while ((status = __pmem_query(&query, &candidate)) == 0) {
+               if (alignment) {
+                       candidate.start = round_up(candidate.start, alignment);
+                       if (candidate.start >= candidate.end)
+                               continue;
+               }
+
+               if ((candidate.end - candidate.start) >= size) {
+                       candidate.end = candidate.start + size;
+                       candidate.allocated_is_set = true;
+                       candidate.allocated = true;
+                       status = __pmem_update(&candidate, false);
+                       BUG_ON(status);
+                       zero_pmem(&candidate);
+                       if (result)
+                               *result = candidate;
+                       return 0;
+               }
+
+               query.start = candidate.end;
+       }
+       BUG_ON(status != -ENOENT);
+
+       return -ENOMEM;
+}
+
+int
+pmem_alloc(size_t size, size_t alignment,
+           const struct pmem_region *constraint,
+           struct pmem_region *result)
+{
+       int status;
+       unsigned long irqstate;
+
+       spin_lock_irqsave(&pmem_list_lock, irqstate);
+       status = __pmem_alloc(size, alignment, constraint, result);
+       spin_unlock_irqrestore(&pmem_list_lock, irqstate);
+
+       return status;
+}
+
+int
+sys_pmem_alloc(size_t size, size_t alignment,
+               const struct pmem_region __user *constraint,
+               struct pmem_region __user *result)
+{
+       struct pmem_region _constraint, _result;
+       int status;
+
+       if (current->uid != 0)
+               return -EPERM;
+
+       if (copy_from_user(&_constraint, constraint, sizeof(_constraint)))
+               return -EINVAL;
+
+       if ((status = pmem_alloc(size, alignment, &_constraint, &_result)) != 0)
+               return status;
+
+       if (result && copy_to_user(result, &_result, sizeof(*result)))
+               return -EINVAL;
+
+       return 0;
+}
diff --git a/kitten/mm/pmem_liblwk.c b/kitten/mm/pmem_liblwk.c
new file mode 120000 (symlink)
index 0000000..56dba6d
--- /dev/null
@@ -0,0 +1 @@
+../user/liblwk/pmem.c
\ No newline at end of file
diff --git a/kitten/palacios-glue/Makefile b/kitten/palacios-glue/Makefile
new file mode 100644 (file)
index 0000000..f8ca9b2
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_V3VEE)    := vm.o vmm_stubs.o
diff --git a/kitten/palacios-glue/vm.c b/kitten/palacios-glue/vm.c
new file mode 100644 (file)
index 0000000..1d3e322
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+
+#include <lwk/kernel.h>
+#include <lwk/palacios.h>
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_io.h>
+
+
+int
+v3vee_run_vmm( void )
+{
+       struct v3_ctrl_ops v3_ops = {};
+
+       Init_V3( &v3vee_os_hooks, &v3_ops );
+
+       struct v3_vm_config vm_config = {
+               .rombios                = &rombios_start,
+               .rombios_size           = (&rombios_end)-(&rombios_start),
+               .vgabios                = &vgabios_start,
+               .vgabios_size           = (&vgabios_end)-(&vgabios_start),
+               .use_ramdisk            = 1,
+               .ramdisk                = (void*) initrd_start,
+               .ramdisk_size           = initrd_end - initrd_start,
+       };
+
+       struct guest_info * vm_info = v3_ops.allocate_guest();
+       v3vee_init_stubs();
+
+       v3_ops.config_guest(vm_info, &vm_config);
+
+       v3_ops.init_guest(vm_info);
+       g_vm_guest = vm_info;
+
+       printk("Starting Guest\n");
+       v3_ops.start_guest(vm_info);
+  
+       return 0;
+}
diff --git a/kitten/palacios-glue/vmm_stubs.c b/kitten/palacios-glue/vmm_stubs.c
new file mode 100644 (file)
index 0000000..aa5f54a
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <lwk/palacios.h>
+#include <lwk/types.h>
+#include <lwk/pmem.h>
+#include <lwk/string.h>
+#include <lwk/cpuinfo.h>
+#include <lwk/kernel.h>
+#include <arch/page.h>
+#include <arch/ptrace.h>
+#include <arch/apic.h>
+
+struct guest_info * g_vm_guest = NULL;
+struct guest_info * irq_to_guest_map[256];
+
+
+
+void
+v3vee_init_stubs( void )
+{
+       memset(irq_to_guest_map, 0, sizeof(irq_to_guest_map) );
+}
+
+
+static void *
+kitten_pa_to_va(void *ptr)
+{
+       return (void*) __va(ptr);
+}
+
+
+static void *
+kitten_va_to_pa(
+       void *                  ptr
+)
+{
+       return (void*) __pa(ptr);
+}
+
+
+static void *
+Allocate_VMM_Pages(
+       int                     num_pages
+) 
+{
+       struct pmem_region result;
+  
+       int rc = pmem_alloc_umem( num_pages*PAGE_SIZE,PAGE_SIZE, &result );
+       if( rc )
+               return 0;
+
+       return (void*) result.start;
+}
+
+static void
+Free_VMM_Page(
+       void *                  page
+) 
+{
+       struct pmem_region      query;
+       struct pmem_region      result;
+
+       pmem_region_unset_all(&query);
+
+       query.start     = (uintptr_t)( page );
+       query.end       = (uintptr_t)( page + PAGE_SIZE );
+
+       int rc = pmem_query(&query,&result);
+
+       if( rc )
+       {
+               panic( "Asked to free non-allocated page %p! rc=%d",
+                       page,
+                       rc
+               );
+               return;
+       }
+
+       result.allocated = 0;
+       pmem_update(&result);
+}
+
+
+
+void
+send_key_to_vmm(
+       unsigned char           status,
+       unsigned char           scancode
+)
+{
+       if( !g_vm_guest )
+               return;
+
+       struct v3_keyboard_event evt = {
+               .status         = status,
+               .scan_code      = scancode,
+       };
+
+       v3_deliver_keyboard_event( g_vm_guest, &evt );
+}
+
+
+void
+send_mouse_to_vmm(
+       unsigned char           packet[3]
+)
+{
+       if( !g_vm_guest )
+               return;
+
+       struct v3_mouse_event evt;
+       memcpy(evt.data, packet, 3);
+
+       v3_deliver_mouse_event(g_vm_guest, &evt);
+}
+
+
+void
+send_tick_to_vmm(
+       unsigned int            period_us
+)
+{
+       if( !g_vm_guest )
+               return;
+
+       struct v3_timer_event evt = {
+               .period_us      = period_us,
+       };
+
+       v3_deliver_timer_event( g_vm_guest, &evt );
+}
+
+
+void
+translate_intr_handler(
+       struct pt_regs *        regs,
+       unsigned int            vector
+) 
+{
+       struct v3_interrupt intr = {
+               .irq            = vector-32,
+               .error          = regs->orig_rax,
+               .should_ack     = 0,
+       };
+
+       //  PrintBoth("translate_intr_handler: opaque=0x%x\n",mystate.opaque);
+       printk( "%s: irq %d\n", __func__, vector );
+       v3_deliver_irq( irq_to_guest_map[intr.irq], &intr );
+}
+
+
+int
+kitten_hook_interrupt(
+       struct guest_info *     vm,
+       unsigned int            irq
+)
+{
+       if( irq_to_guest_map[irq] ) {
+               //PrintBoth("Attempt to hook interrupt that is already hooked\n");
+               return -1;
+       }
+
+       //PrintBoth("Hooked interrupt 0x%x with opaque 0x%x\n", irq, vm);
+       printk( "%s: hook irq %d to %p\n", __func__, irq, vm );
+       irq_to_guest_map[irq] = vm;
+
+       set_idtvec_handler( irq, translate_intr_handler );
+       return 0;
+}
+
+
+static int
+ack_irq(
+       int                     irq
+) 
+{
+       lapic_ack_interrupt();
+       return 0;
+}
+
+  
+static unsigned int
+get_cpu_khz( void ) 
+{
+       return cpu_info[0].arch.cur_cpu_khz;
+}
+
+static void *
+v3vee_alloc(
+       unsigned int size
+)
+{
+       return kmem_alloc( size );
+}
+
+
+static void
+v3vee_free(
+       void * addr
+)
+{
+       return kmem_free( addr );
+}
+
+
+static void
+v3vee_printk(
+       const char *            fmt,
+       ...
+)
+{
+       va_list ap;
+       va_start( ap, fmt );
+       vprintk( fmt, ap );
+       va_end( ap );
+}
+
+
+struct v3_os_hooks v3vee_os_hooks = {
+       .print_debug            = v3vee_printk,  // serial print ideally
+       .print_info             = v3vee_printk,   // serial print ideally
+       .print_trace            = v3vee_printk,  // serial print ideally
+       .allocate_pages         = Allocate_VMM_Pages, // defined in vmm_stubs
+       .free_page              = Free_VMM_Page, // defined in vmm_stubs
+       .malloc                 = v3vee_alloc,
+       .free                   = v3vee_free,
+       .vaddr_to_paddr         = kitten_va_to_pa,
+       .paddr_to_vaddr         = kitten_pa_to_va,
+       .hook_interrupt         = kitten_hook_interrupt,
+       .ack_irq                = ack_irq,
+       .get_cpu_khz            = get_cpu_khz,
+};
+
diff --git a/kitten/palacios/.do-not-delete b/kitten/palacios/.do-not-delete
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/kitten/scripts/Kbuild.include b/kitten/scripts/Kbuild.include
new file mode 100644 (file)
index 0000000..b0d067b
--- /dev/null
@@ -0,0 +1,148 @@
+####
+# kbuild: Generic definitions
+
+# Convinient variables
+comma   := ,
+squote  := '
+empty   :=
+space   := $(empty) $(empty)
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
+
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+###
+# filechk is used to check if the content of a generated file is updated.
+# Sample usage:
+# define filechk_sample
+#      echo $KERNELRELEASE
+# endef
+# version.h : Makefile
+#      $(call filechk,sample)
+# The rule defined shall write to stdout the content of the new file.
+# The existing file will be compared with the new one.
+# - If no file exist it is created
+# - If the content differ the new file is used
+# - If they are equal no change, and no timestamp update
+# - stdin is piped in from the first prerequisite ($<) so one has
+#   to specify a valid file as first prerequisite (often the kbuild file)
+define filechk
+       $(Q)set -e;                             \
+       echo '  CHK     $@';                    \
+       mkdir -p $(dir $@);                     \
+       $(filechk_$(1)) < $< > $@.tmp;          \
+       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
+               rm -f $@.tmp;                   \
+       else                                    \
+               echo '  UPD     $@';            \
+               mv -f $@.tmp $@;                \
+       fi
+endef
+
+######
+# gcc support functions
+# See documentation in Documentation/kbuild/makefiles.txt
+
+# as-option
+# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,)
+
+as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
+            -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
+            else echo "$(2)"; fi ;)
+
+# cc-option
+# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
+
+cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
+             > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+
+# cc-option-yn
+# Usage: flag := $(call cc-option-yn, -march=winchip-c6)
+cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
+                > /dev/null 2>&1; then echo "y"; else echo "n"; fi;)
+
+# cc-option-align
+# Prefix align with either -falign or -malign
+cc-option-align = $(subst -functions=0,,\
+       $(call cc-option,-falign-functions=0,-malign-functions=0))
+
+# cc-version
+# Usage gcc-ver := $(call cc-version, $(CC))
+cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh \
+              $(if $(1), $(1), $(CC)))
+
+# cc-ifversion
+# Usage:  EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
+cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \
+                       echo $(3); fi;)
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
+# Usage:
+# $(Q)$(MAKE) $(build)=dir
+build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+
+# Prefix -I with $(srctree) if it is not an absolute path
+addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+# Find all -I options and call addtree
+flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
+
+# If quiet is set, only print short version of command
+cmd = @$(echo-cmd) $(cmd_$(1))
+
+# Add $(obj)/ for paths that is not absolute
+objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
+
+###
+# if_changed      - execute command if any prerequisite is newer than 
+#                   target, or command line has changed
+# if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
+#                   including used config symbols
+# if_changed_rule - as if_changed but execute rule instead
+# See Documentation/kbuild/makefiles.txt for more info
+
+ifneq ($(KBUILD_NOCMDDEP),1)
+# Check if both arguments has same arguments. Result in empty string if equal
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) )
+endif
+
+# echo command. Short version is $(quiet) equals quiet, otherwise full command
+echo-cmd = $(if $($(quiet)cmd_$(1)), \
+       echo '  $(call escsq,$($(quiet)cmd_$(1)))';)
+
+make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
+
+# function to only execute the passed command if necessary
+# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file
+# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars
+#
+if_changed = $(if $(strip $(filter-out $(PHONY),$?)          \
+               $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \
+       @set -e; \
+       $(echo-cmd) $(cmd_$(1)); \
+       echo 'cmd_$@ := $(make-cmd)' > $(@D)/.$(@F).cmd)
+
+# execute the command and also postprocess generated .d dependencies
+# file
+if_changed_dep = $(if $(strip $(filter-out $(PHONY),$?)  \
+               $(filter-out FORCE $(wildcard $^),$^)    \
+       $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),     \
+       @set -e; \
+       $(echo-cmd) $(cmd_$(1)); \
+       scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(@D)/.$(@F).tmp; \
+       rm -f $(depfile); \
+       mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
+
+# Usage: $(call if_changed_rule,foo)
+# will check if $(cmd_foo) changed, or any of the prequisites changed,
+# and if so will execute $(rule_foo)
+if_changed_rule = $(if $(strip $(filter-out $(PHONY),$?)            \
+                       $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\
+                       @set -e; \
+                       $(rule_$(1)))
diff --git a/kitten/scripts/Makefile b/kitten/scripts/Makefile
new file mode 100644 (file)
index 0000000..dc5d53c
--- /dev/null
@@ -0,0 +1,22 @@
+###
+# scripts contains sources for various helper programs used throughout
+# the kernel for the build process.
+# ---------------------------------------------------------------------------
+# kallsyms:      Find all symbols in vmlinux
+# pnmttologo:    Convert pnm files to logo files
+# conmakehash:   Create chartable
+# conmakehash:  Create arrays for initializing the kernel console tables
+
+hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
+hostprogs-$(CONFIG_LOGO)         += pnmtologo
+hostprogs-$(CONFIG_VT)           += conmakehash
+hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash
+hostprogs-$(CONFIG_IKCONFIG)     += bin2c
+
+always         := $(hostprogs-y)
+
+#subdir-$(CONFIG_MODVERSIONS) += genksyms
+#subdir-$(CONFIG_MODULES)     += mod
+
+# Let clean descend into subdirs
+subdir-        += basic kconfig
diff --git a/kitten/scripts/Makefile.build b/kitten/scripts/Makefile.build
new file mode 100644 (file)
index 0000000..e48e60d
--- /dev/null
@@ -0,0 +1,338 @@
+# ==========================================================================
+# Building
+# ==========================================================================
+
+src := $(obj)
+
+PHONY := __build
+__build:
+
+# Read .config if it exist, otherwise ignore
+-include .config
+
+include scripts/Kbuild.include
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
+
+include scripts/Makefile.lib
+
+ifdef host-progs
+ifneq ($(hostprogs-y),$(host-progs))
+$(warning kbuild: $(obj)/Makefile - Usage of host-progs is deprecated. Please replace with hostprogs-y!)
+hostprogs-y += $(host-progs)
+endif
+endif
+
+# Do not include host rules unles needed
+ifneq ($(hostprogs-y)$(hostprogs-m),)
+include scripts/Makefile.host
+endif
+
+ifneq ($(KBUILD_SRC),)
+# Create output directory if not already present
+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
+
+# Create directories for object files if directory does not exist
+# Needed when obj-y := dir/file.o syntax is used
+_dummy := $(foreach d,$(obj-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))
+endif
+
+
+ifdef EXTRA_TARGETS
+$(warning kbuild: $(obj)/Makefile - Usage of EXTRA_TARGETS is obsolete in 2.6. Please fix!)
+endif
+
+ifdef build-targets
+$(warning kbuild: $(obj)/Makefile - Usage of build-targets is obsolete in 2.6. Please fix!)
+endif
+
+ifdef export-objs
+$(warning kbuild: $(obj)/Makefile - Usage of export-objs is obsolete in 2.6. Please fix!)
+endif
+
+ifdef O_TARGET
+$(warning kbuild: $(obj)/Makefile - Usage of O_TARGET := $(O_TARGET) is obsolete in 2.6. Please fix!)
+endif
+
+ifdef L_TARGET
+$(error kbuild: $(obj)/Makefile - Use of L_TARGET is replaced by lib-y in 2.6. Please fix!)
+endif
+
+ifdef list-multi
+$(warning kbuild: $(obj)/Makefile - list-multi := $(list-multi) is obsolete in 2.6. Please fix!)
+endif
+
+ifndef obj
+$(warning kbuild: Makefile.build is included improperly)
+endif
+
+# ===========================================================================
+
+ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
+lib-target := $(obj)/lib.a
+endif
+
+ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
+builtin-target := $(obj)/built-in.o
+endif
+
+# We keep a list of all modules in $(MODVERDIR)
+
+__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
+        $(if $(KBUILD_MODULES),$(obj-m)) \
+        $(subdir-ym) $(always)
+       @:
+
+# Linus' kernel sanity checking tool
+ifneq ($(KBUILD_CHECKSRC),0)
+  ifeq ($(KBUILD_CHECKSRC),2)
+    quiet_cmd_force_checksrc = CHECK   $<
+          cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
+  else
+      quiet_cmd_checksrc     = CHECK   $<
+            cmd_checksrc     = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
+  endif
+endif
+
+
+# Compile C sources (.c)
+# ---------------------------------------------------------------------------
+
+# Default is built-in, unless we know otherwise
+modkern_cflags := $(CFLAGS_KERNEL)
+quiet_modtag := $(empty)   $(empty)
+
+$(real-objs-m)        : modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.i)  : modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.s)  : modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.lst): modkern_cflags := $(CFLAGS_MODULE)
+
+$(real-objs-m)        : quiet_modtag := [M]
+$(real-objs-m:.o=.i)  : quiet_modtag := [M]
+$(real-objs-m:.o=.s)  : quiet_modtag := [M]
+$(real-objs-m:.o=.lst): quiet_modtag := [M]
+
+$(obj-m)              : quiet_modtag := [M]
+
+# Default for not multi-part modules
+modname = $(*F)
+
+$(multi-objs-m)         : modname = $(modname-multi)
+$(multi-objs-m:.o=.i)   : modname = $(modname-multi)
+$(multi-objs-m:.o=.s)   : modname = $(modname-multi)
+$(multi-objs-m:.o=.lst) : modname = $(modname-multi)
+$(multi-objs-y)         : modname = $(modname-multi)
+$(multi-objs-y:.o=.i)   : modname = $(modname-multi)
+$(multi-objs-y:.o=.s)   : modname = $(modname-multi)
+$(multi-objs-y:.o=.lst) : modname = $(modname-multi)
+
+quiet_cmd_cc_s_c = CC $(quiet_modtag)  $@
+cmd_cc_s_c       = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<
+
+%.s: %.c FORCE
+       $(call if_changed_dep,cc_s_c)
+
+quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@
+cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
+
+%.i: %.c FORCE
+       $(call if_changed_dep,cc_i_c)
+
+# C (.c) files
+# The C file is compiled and updated dependency information is generated.
+# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
+
+quiet_cmd_cc_o_c = CC $(quiet_modtag)  $@
+
+ifndef CONFIG_MODVERSIONS
+cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+
+else
+# When module versioning is enabled the following steps are executed:
+# o compile a .tmp_<file>.o from <file>.c
+# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
+#   not export symbols, we just rename .tmp_<file>.o to <file>.o and
+#   are done.
+# o otherwise, we calculate symbol versions using the good old
+#   genksyms on the preprocessed source and postprocess them in a way
+#   that they are usable as a linker script
+# o generate <file>.o from .tmp_<file>.o using the linker to
+#   replace the unresolved symbols __crc_exported_symbol with
+#   the actual value of the checksum generated by genksyms
+
+cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
+cmd_modversions =                                                      \
+       if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then     \
+               $(CPP) -D__GENKSYMS__ $(c_flags) $<                     \
+               | $(GENKSYMS) -a $(ARCH)                                \
+               > $(@D)/.tmp_$(@F:.o=.ver);                             \
+                                                                       \
+               $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F)              \
+                       -T $(@D)/.tmp_$(@F:.o=.ver);                    \
+               rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);        \
+       else                                                            \
+               mv -f $(@D)/.tmp_$(@F) $@;                              \
+       fi;
+endif
+
+define rule_cc_o_c
+       $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
+       $(call echo-cmd,cc_o_c) $(cmd_cc_o_c);                            \
+       $(cmd_modversions)                                                \
+       scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > $(@D)/.$(@F).tmp;  \
+       rm -f $(depfile);                                                 \
+       mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd
+endef
+
+# Built-in and composite module parts
+
+%.o: %.c FORCE
+       $(call cmd,force_checksrc)
+       $(call if_changed_rule,cc_o_c)
+
+# Single-part modules are special since we need to mark them in $(MODVERDIR)
+
+$(single-used-m): %.o: %.c FORCE
+       $(call cmd,force_checksrc)
+       $(call if_changed_rule,cc_o_c)
+       @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
+
+quiet_cmd_cc_lst_c = MKLST   $@
+      cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
+                    $(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
+                                    System.map $(OBJDUMP) > $@
+
+%.lst: %.c FORCE
+       $(call if_changed_dep,cc_lst_c)
+
+# Compile assembler sources (.S)
+# ---------------------------------------------------------------------------
+
+modkern_aflags := $(AFLAGS_KERNEL)
+
+$(real-objs-m)      : modkern_aflags := $(AFLAGS_MODULE)
+$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
+
+quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
+cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
+
+%.s: %.S FORCE
+       $(call if_changed_dep,as_s_S)
+
+quiet_cmd_as_o_S = AS $(quiet_modtag)  $@
+cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
+
+%.o: %.S FORCE
+       $(call if_changed_dep,as_o_S)
+
+targets += $(real-objs-y) $(real-objs-m) $(lib-y)
+targets += $(extra-y) $(MAKECMDGOALS) $(always)
+
+# Linker scripts preprocessor (.lds.S -> .lds)
+# ---------------------------------------------------------------------------
+quiet_cmd_cpp_lds_S = LDS     $@
+      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<
+
+%.lds: %.lds.S FORCE
+       $(call if_changed_dep,cpp_lds_S)
+
+# Build the compiled-in targets
+# ---------------------------------------------------------------------------
+
+# To build objects in subdirs, we need to descend into the directories
+$(sort $(subdir-obj-y)): $(subdir-ym) ;
+
+#
+# Rule to compile a set of .o files into one .o file
+#
+ifdef builtin-target
+quiet_cmd_link_o_target = LD      $@
+# If the list of objects to link is empty, just create an empty built-in.o
+cmd_link_o_target = $(if $(strip $(obj-y)),\
+                     $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\
+                     rm -f $@; $(AR) rcs $@)
+
+$(builtin-target): $(obj-y) FORCE
+       $(call if_changed,link_o_target)
+
+targets += $(builtin-target)
+endif # builtin-target
+
+#
+# Rule to compile a set of .o files into one .a file
+#
+ifdef lib-target
+quiet_cmd_link_l_target = AR      $@
+cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(lib-y)
+
+$(lib-target): $(lib-y) FORCE
+       $(call if_changed,link_l_target)
+
+targets += $(lib-target)
+endif
+
+#
+# Rule to link composite objects
+#
+#  Composite objects are specified in kbuild makefile as follows:
+#    <composite-object>-objs := <list of .o files>
+#  or
+#    <composite-object>-y    := <list of .o files>
+link_multi_deps =                     \
+$(filter $(addprefix $(obj)/,         \
+$($(subst $(obj)/,,$(@:.o=-objs)))    \
+$($(subst $(obj)/,,$(@:.o=-y)))), $^)
+quiet_cmd_link_multi-y = LD      $@
+cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps)
+
+quiet_cmd_link_multi-m = LD [M]  $@
+cmd_link_multi-m = $(LD) $(ld_flags) $(LDFLAGS_MODULE) -o $@ $(link_multi_deps)
+
+# We would rather have a list of rules like
+#      foo.o: $(foo-objs)
+# but that's not so easy, so we rather make all composite objects depend
+# on the set of all their parts
+$(multi-used-y) : %.o: $(multi-objs-y) FORCE
+       $(call if_changed,link_multi-y)
+
+$(multi-used-m) : %.o: $(multi-objs-m) FORCE
+       $(call if_changed,link_multi-m)
+       @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
+
+targets += $(multi-used-y) $(multi-used-m)
+
+
+# Descending
+# ---------------------------------------------------------------------------
+
+PHONY += $(subdir-ym)
+$(subdir-ym):
+       $(Q)$(MAKE) $(build)=$@
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  include $(cmd_files)
+endif
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
diff --git a/kitten/scripts/Makefile.clean b/kitten/scripts/Makefile.clean
new file mode 100644 (file)
index 0000000..cff3349
--- /dev/null
@@ -0,0 +1,102 @@
+# ==========================================================================
+# Cleaning up
+# ==========================================================================
+
+src := $(obj)
+
+PHONY := __clean
+__clean:
+
+# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
+
+# Figure out what we need to build from the various variables
+# ==========================================================================
+
+__subdir-y     := $(patsubst %/,%,$(filter %/, $(obj-y)))
+subdir-y       += $(__subdir-y)
+__subdir-m     := $(patsubst %/,%,$(filter %/, $(obj-m)))
+subdir-m       += $(__subdir-m)
+__subdir-n     := $(patsubst %/,%,$(filter %/, $(obj-n)))
+subdir-n       += $(__subdir-n)
+__subdir-      := $(patsubst %/,%,$(filter %/, $(obj-)))
+subdir-                += $(__subdir-)
+
+# Subdirectories we need to descend into
+
+subdir-ym      := $(sort $(subdir-y) $(subdir-m))
+subdir-ymn      := $(sort $(subdir-ym) $(subdir-n) $(subdir-))
+
+# Add subdir path
+
+subdir-ymn     := $(addprefix $(obj)/,$(subdir-ymn))
+
+# build a list of files to remove, usually releative to the current
+# directory
+
+__clean-files  := $(extra-y) $(EXTRA_TARGETS) $(always) \
+                  $(targets) $(clean-files)             \
+                  $(host-progs)                         \
+                  $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
+
+# as clean-files is given relative to the current directory, this adds
+# a $(obj) prefix, except for absolute paths
+
+__clean-files   := $(wildcard                                               \
+                   $(addprefix $(obj)/, $(filter-out /%, $(__clean-files))) \
+                  $(filter /%, $(__clean-files)))
+
+# as clean-dirs is given relative to the current directory, this adds
+# a $(obj) prefix, except for absolute paths
+
+__clean-dirs    := $(wildcard                                               \
+                   $(addprefix $(obj)/, $(filter-out /%, $(clean-dirs)))    \
+                  $(filter /%, $(clean-dirs)))
+
+# ==========================================================================
+
+quiet_cmd_clean    = CLEAN   $(obj)
+      cmd_clean    = rm -f $(__clean-files)
+quiet_cmd_cleandir = CLEAN   $(__clean-dirs)
+      cmd_cleandir = rm -rf $(__clean-dirs)
+
+
+__clean: $(subdir-ymn)
+ifneq ($(strip $(__clean-files)),)
+       +$(call cmd,clean)
+endif
+ifneq ($(strip $(__clean-dirs)),)
+       +$(call cmd,cleandir)
+endif
+ifneq ($(strip $(clean-rule)),)
+       +$(clean-rule)
+endif
+       @:
+
+
+# ===========================================================================
+# Generic stuff
+# ===========================================================================
+
+# Descending
+# ---------------------------------------------------------------------------
+
+PHONY += $(subdir-ymn)
+$(subdir-ymn):
+       $(Q)$(MAKE) $(clean)=$@
+
+# If quiet is set, only print short version of command
+
+cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
diff --git a/kitten/scripts/Makefile.host b/kitten/scripts/Makefile.host
new file mode 100644 (file)
index 0000000..2d51970
--- /dev/null
@@ -0,0 +1,156 @@
+# ==========================================================================
+# Building binaries on the host system
+# Binaries are used during the compilation of the kernel, for example
+# to preprocess a data file.
+#
+# Both C and C++ is supported, but preferred language is C for such utilities.
+#
+# Samle syntax (see Documentation/kbuild/makefile.txt for reference)
+# hostprogs-y := bin2hex
+# Will compile bin2hex.c and create an executable named bin2hex
+#
+# hostprogs-y    := lxdialog
+# lxdialog-objs := checklist.o lxdialog.o
+# Will compile lxdialog.c and checklist.c, and then link the executable
+# lxdialog, based on checklist.o and lxdialog.o
+#
+# hostprogs-y      := qconf
+# qconf-cxxobjs   := qconf.o
+# qconf-objs      := menu.o
+# Will compile qconf as a C++ program, and menu as a C program.
+# They are linked as C++ code to the executable qconf
+
+# hostprogs-y := conf
+# conf-objs  := conf.o libkconfig.so
+# libkconfig-objs := expr.o type.o
+# Will create a shared library named libkconfig.so that consist of
+# expr.o and type.o (they are both compiled as C code and the object file
+# are made as position independent code).
+# conf.c is compiled as a c program, and conf.o is linked together with
+# libkconfig.so as the executable conf.
+# Note: Shared libraries consisting of C++ files are not supported
+
+__hostprogs := $(sort $(hostprogs-y)$(hostprogs-m))
+
+# hostprogs-y := tools/build may have been specified. Retreive directory
+obj-dirs += $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
+obj-dirs := $(strip $(sort $(filter-out ./,$(obj-dirs))))
+
+
+# C code
+# Executables compiled from a single .c file
+host-csingle   := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
+
+# C executables linked based on several .o files
+host-cmulti    := $(foreach m,$(__hostprogs),\
+                  $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
+
+# Object (.o) files compiled from .c files
+host-cobjs     := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
+
+# C++ code
+# C++ executables compiled from at least on .cc file
+# and zero or more .c files
+host-cxxmulti  := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
+
+# C++ Object (.o) files compiled from .cc files
+host-cxxobjs   := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
+
+# Shared libaries (only .c supported)
+# Shared libraries (.so) - all .so files referenced in "xxx-objs"
+host-cshlib    := $(sort $(filter %.so, $(host-cobjs)))
+# Remove .so files from "xxx-objs"
+host-cobjs     := $(filter-out %.so,$(host-cobjs))
+
+#Object (.o) files used by the shared libaries
+host-cshobjs   := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+
+__hostprogs     := $(addprefix $(obj)/,$(__hostprogs))
+host-csingle   := $(addprefix $(obj)/,$(host-csingle))
+host-cmulti    := $(addprefix $(obj)/,$(host-cmulti))
+host-cobjs     := $(addprefix $(obj)/,$(host-cobjs))
+host-cxxmulti  := $(addprefix $(obj)/,$(host-cxxmulti))
+host-cxxobjs   := $(addprefix $(obj)/,$(host-cxxobjs))
+host-cshlib    := $(addprefix $(obj)/,$(host-cshlib))
+host-cshobjs   := $(addprefix $(obj)/,$(host-cshobjs))
+obj-dirs        := $(addprefix $(obj)/,$(obj-dirs))
+
+#####
+# Handle options to gcc. Support building with separate output directory
+
+_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   $(HOSTCFLAGS_$(*F).o)
+_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) $(HOSTCXXFLAGS_$(*F).o)
+
+ifeq ($(KBUILD_SRC),)
+__hostc_flags  = $(_hostc_flags)
+__hostcxx_flags        = $(_hostcxx_flags)
+else
+__hostc_flags  = -I$(obj) $(call flags,_hostc_flags)
+__hostcxx_flags        = -I$(obj) $(call flags,_hostcxx_flags)
+endif
+
+hostc_flags    = -Wp,-MD,$(depfile) $(__hostc_flags)
+hostcxx_flags  = -Wp,-MD,$(depfile) $(__hostcxx_flags)
+
+#####
+# Compile programs on the host
+
+# Create executable from a single .c file
+# host-csingle -> Executable
+quiet_cmd_host-csingle         = HOSTCC  $@
+      cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
+               $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-csingle): %: %.c FORCE
+       $(call if_changed_dep,host-csingle)
+
+# Link an executable based on list of .o files, all plain c
+# host-cmulti -> executable
+quiet_cmd_host-cmulti  = HOSTLD  $@
+      cmd_host-cmulti  = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
+                         $(addprefix $(obj)/,$($(@F)-objs)) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cmulti)
+
+# Create .o file from a single .c file
+# host-cobjs -> .o
+quiet_cmd_host-cobjs   = HOSTCC  $@
+      cmd_host-cobjs   = $(HOSTCC) $(hostc_flags) -c -o $@ $<
+$(host-cobjs): %.o: %.c FORCE
+       $(call if_changed_dep,host-cobjs)
+
+# Link an executable based on list of .o files, a mixture of .c and .cc
+# host-cxxmulti -> executable
+quiet_cmd_host-cxxmulti        = HOSTLD  $@
+      cmd_host-cxxmulti        = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
+                         $(foreach o,objs cxxobjs,\
+                         $(addprefix $(obj)/,$($(@F)-$(o)))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cxxmulti): %: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cxxmulti)
+
+# Create .o file from a single .cc (C++) file
+quiet_cmd_host-cxxobjs = HOSTCXX $@
+      cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
+$(host-cxxobjs): %.o: %.cc FORCE
+       $(call if_changed_dep,host-cxxobjs)
+
+# Compile .c file, create position independent .o file
+# host-cshobjs -> .o
+quiet_cmd_host-cshobjs = HOSTCC  -fPIC $@
+      cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
+$(host-cshobjs): %.o: %.c FORCE
+       $(call if_changed_dep,host-cshobjs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cshlib)
+quiet_cmd_host-cshlib  = HOSTLLD -shared $@
+      cmd_host-cshlib  = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
+                         $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cshlib): %: $(host-cshobjs) FORCE
+       $(call if_changed,host-cshlib)
+
+targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) 
+
diff --git a/kitten/scripts/Makefile.lib b/kitten/scripts/Makefile.lib
new file mode 100644 (file)
index 0000000..2cb4935
--- /dev/null
@@ -0,0 +1,165 @@
+# Backward compatibility - to be removed...
+extra-y        += $(EXTRA_TARGETS)
+# Figure out what we need to build from the various variables
+# ===========================================================================
+
+# When an object is listed to be built compiled-in and modular,
+# only build the compiled-in version
+
+obj-m := $(filter-out $(obj-y),$(obj-m))
+
+# Libraries are always collected in one lib file.
+# Filter out objects already built-in
+
+lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
+
+
+# Handle objects in subdirs
+# ---------------------------------------------------------------------------
+# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o
+#   and add the directory to the list of dirs to descend into: $(subdir-y)
+# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) 
+#   and add the directory to the list of dirs to descend into: $(subdir-m)
+
+__subdir-y     := $(patsubst %/,%,$(filter %/, $(obj-y)))
+subdir-y       += $(__subdir-y)
+__subdir-m     := $(patsubst %/,%,$(filter %/, $(obj-m)))
+subdir-m       += $(__subdir-m)
+obj-y          := $(patsubst %/, %/built-in.o, $(obj-y))
+obj-m          := $(filter-out %/, $(obj-m))
+
+# Subdirectories we need to descend into
+
+subdir-ym      := $(sort $(subdir-y) $(subdir-m))
+
+# if $(foo-objs) exists, foo.o is a composite object 
+multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
+multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
+multi-used   := $(multi-used-y) $(multi-used-m)
+single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
+
+# Build list of the parts of our composite objects, our composite
+# objects depend on those (obviously)
+multi-objs-y := $(foreach m, $(multi-used-y), $($(m:.o=-objs)) $($(m:.o=-y)))
+multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
+multi-objs   := $(multi-objs-y) $(multi-objs-m)
+
+# $(subdir-obj-y) is the list of objects in $(obj-y) which do not live
+# in the local directory
+subdir-obj-y := $(foreach o,$(obj-y),$(if $(filter-out $(o),$(notdir $(o))),$(o)))
+
+# $(obj-dirs) is a list of directories that contain object files
+obj-dirs := $(dir $(multi-objs) $(subdir-obj-y))
+
+# Replace multi-part objects by their individual parts, look at local dir only
+real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y)
+real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
+
+# Add subdir path
+
+extra-y                := $(addprefix $(obj)/,$(extra-y))
+always         := $(addprefix $(obj)/,$(always))
+targets                := $(addprefix $(obj)/,$(targets))
+obj-y          := $(addprefix $(obj)/,$(obj-y))
+obj-m          := $(addprefix $(obj)/,$(obj-m))
+lib-y          := $(addprefix $(obj)/,$(lib-y))
+subdir-obj-y   := $(addprefix $(obj)/,$(subdir-obj-y))
+real-objs-y    := $(addprefix $(obj)/,$(real-objs-y))
+real-objs-m    := $(addprefix $(obj)/,$(real-objs-m))
+single-used-m  := $(addprefix $(obj)/,$(single-used-m))
+multi-used-y   := $(addprefix $(obj)/,$(multi-used-y))
+multi-used-m   := $(addprefix $(obj)/,$(multi-used-m))
+multi-objs-y   := $(addprefix $(obj)/,$(multi-objs-y))
+multi-objs-m   := $(addprefix $(obj)/,$(multi-objs-m))
+subdir-ym      := $(addprefix $(obj)/,$(subdir-ym))
+obj-dirs       := $(addprefix $(obj)/,$(obj-dirs))
+
+# These flags are needed for modversions and compiling, so we define them here
+# already
+# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will 
+# end up in (or would, if it gets compiled in)
+# Note: It's possible that one object gets potentially linked into more
+#       than one module. In that case KBUILD_MODNAME will be set to foo_bar,
+#       where foo and bar are the name of the modules.
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(*F)))"
+modname_flags  = $(if $(filter 1,$(words $(modname))),\
+                 -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+_c_flags       = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o)
+_a_flags       = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+_cpp_flags     = $(CPPFLAGS) $(EXTRA_CPPFLAGS) $(CPPFLAGS_$(@F))
+
+# If building the kernel in a separate objtree expand all occurrences
+# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/').
+
+ifeq ($(KBUILD_SRC),)
+__c_flags      = $(_c_flags)
+__a_flags      = $(_a_flags)
+__cpp_flags     = $(_cpp_flags)
+else
+
+# -I$(obj) locates generated .h files
+# $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files
+#   and locates generated .h files
+# FIXME: Replace both with specific CFLAGS* statements in the makefiles
+__c_flags      = $(call addtree,-I$(obj)) $(call flags,_c_flags)
+__a_flags      =                          $(call flags,_a_flags)
+__cpp_flags     =                          $(call flags,_cpp_flags)
+endif
+
+c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(CPPFLAGS) \
+                $(__c_flags) $(modkern_cflags) \
+                -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+
+a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(CPPFLAGS) \
+                $(__a_flags) $(modkern_aflags)
+
+cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(__cpp_flags)
+
+ld_flags       = $(LDFLAGS) $(EXTRA_LDFLAGS)
+
+# Finds the multi-part object the current object will be linked into
+modname-multi = $(sort $(foreach m,$(multi-used),\
+               $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))
+
+# Shipped files
+# ===========================================================================
+
+quiet_cmd_shipped = SHIPPED $@
+cmd_shipped = cat $< > $@
+
+$(obj)/%:: $(src)/%_shipped
+       $(call cmd,shipped)
+
+# Commands useful for building a boot image
+# ===========================================================================
+# 
+#      Use as following:
+#
+#      target: source(s) FORCE
+#              $(if_changed,ld/objcopy/gzip)
+#
+#      and add target to EXTRA_TARGETS so that we know we have to
+#      read in the saved command line
+
+# Linking
+# ---------------------------------------------------------------------------
+
+quiet_cmd_ld = LD      $@
+cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) \
+              $(filter-out FORCE,$^) -o $@ 
+
+# Objcopy
+# ---------------------------------------------------------------------------
+
+quiet_cmd_objcopy = OBJCOPY $@
+cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
+
+# Gzip
+# ---------------------------------------------------------------------------
+
+quiet_cmd_gzip = GZIP    $@
+cmd_gzip = gzip -f -9 < $< > $@
+
+
diff --git a/kitten/scripts/Makefile.modpost b/kitten/scripts/Makefile.modpost
new file mode 100644 (file)
index 0000000..0e056cf
--- /dev/null
@@ -0,0 +1,120 @@
+# ===========================================================================
+# Module versions
+# ===========================================================================
+#
+# Stage one of module building created the following:
+# a) The individual .o files used for the module
+# b) A <module>.o file which is the .o files above linked together
+# c) A <module>.mod file in $(MODVERDIR)/, listing the name of the
+#    the preliminary <module>.o file, plus all .o files
+
+# Stage 2 is handled by this file and does the following
+# 1) Find all modules from the files listed in $(MODVERDIR)/
+# 2) modpost is then used to
+# 3)  create one <module>.mod.c file pr. module
+# 4)  create one Module.symvers file with CRC for all exported symbols
+# 5) compile all <module>.mod.c files
+# 6) final link of the module to a <module.ko> file
+
+# Step 3 is used to place certain information in the module's ELF
+# section, including information such as:
+#   Version magic (see include/vermagic.h for full details)
+#     - Kernel release
+#     - SMP is CONFIG_SMP
+#     - PREEMPT is CONFIG_PREEMPT
+#     - GCC Version
+#   Module info
+#     - Module version (MODULE_VERSION)
+#     - Module alias'es (MODULE_ALIAS)
+#     - Module license (MODULE_LICENSE)
+#     - See include/linux/module.h for more details
+
+# Step 4 is solely used to allow module versioning in external modules,
+# where the CRC of each module is retrieved from the Module.symers file.
+
+PHONY := _modpost
+_modpost: __modpost
+
+include .config
+include scripts/Kbuild.include
+include scripts/Makefile.lib
+
+kernelsymfile := $(objtree)/Module.symvers
+modulesymfile := $(KBUILD_EXTMOD)/Modules.symvers
+
+# Step 1), find all modules listed in $(MODVERDIR)/
+__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+modules   := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o)))
+
+_modpost: $(modules)
+
+
+# Step 2), invoke modpost
+#  Includes step 3,4
+quiet_cmd_modpost = MODPOST
+      cmd_modpost = scripts/mod/modpost            \
+        $(if $(CONFIG_MODVERSIONS),-m)             \
+       $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,)  \
+       $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
+       $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
+       $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
+       $(filter-out FORCE,$^)
+
+PHONY += __modpost
+__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
+       $(call cmd,modpost)
+
+# Declare generated files as targets for modpost
+$(symverfile):         __modpost ;
+$(modules:.ko=.mod.c): __modpost ;
+
+
+# Step 5), compile all *.mod.c files
+
+# modname is set to make c_flags define KBUILD_MODNAME
+modname = $(*F)
+
+quiet_cmd_cc_o_c = CC      $@
+      cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE)   \
+                  -c -o $@ $<
+
+$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
+       $(call if_changed_dep,cc_o_c)
+
+targets += $(modules:.ko=.mod.o)
+
+# Step 6), final link of the modules
+quiet_cmd_ld_ko_o = LD [M]  $@
+      cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@           \
+                         $(filter-out FORCE,$^)
+
+$(modules): %.ko :%.o %.mod.o FORCE
+       $(call if_changed,ld_ko_o)
+
+targets += $(modules)
+
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  include $(cmd_files)
+endif
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
diff --git a/kitten/scripts/basic/Makefile b/kitten/scripts/basic/Makefile
new file mode 100644 (file)
index 0000000..f22e94c
--- /dev/null
@@ -0,0 +1,18 @@
+###
+# Makefile.basic list the most basic programs used during the build process.
+# The programs listed herein is what is needed to do the basic stuff,
+# such as splitting .config and fix dependency file.
+# This initial step is needed to avoid files to be recompiled
+# when kernel configuration changes (which is what happens when
+# .config is included by main Makefile.
+# ---------------------------------------------------------------------------
+# fixdep:       Used to generate dependency information during build process
+# split-include: Divide all config symbols up in a number of files in
+#                include/config/...
+# docproc:      Used in Documentation/docbook
+
+hostprogs-y    := fixdep split-include docproc
+always         := $(hostprogs-y)
+
+# fixdep is needed to compile other host programs
+$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
diff --git a/kitten/scripts/basic/docproc.c b/kitten/scripts/basic/docproc.c
new file mode 100644 (file)
index 0000000..cb02baa
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ *     docproc is a simple preprocessor for the template files
+ *      used as placeholders for the kernel internal documentation.
+ *     docproc is used for documentation-frontend and
+ *      dependency-generator.
+ *     The two usages have in common that they require
+ *     some knowledge of the .tmpl syntax, therefore they
+ *     are kept together.
+ *
+ *     documentation-frontend
+ *             Scans the template file and call kernel-doc for
+ *             all occurrences of ![EIF]file
+ *             Beforehand each referenced file are scanned for
+ *             any exported sympols "EXPORT_SYMBOL()" statements.
+ *             This is used to create proper -function and
+ *             -nofunction arguments in calls to kernel-doc.
+ *             Usage: docproc doc file.tmpl
+ *
+ *     dependency-generator:
+ *             Scans the template file and list all files
+ *             referenced in a format recognized by make.
+ *             Usage:  docproc depend file.tmpl
+ *             Writes dependency information to stdout
+ *             in the following format:
+ *             file.tmpl src.c src2.c
+ *             The filenames are obtained from the following constructs:
+ *             !Efilename
+ *             !Ifilename
+ *             !Dfilename
+ *             !Ffilename
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* exitstatus is used to keep track of any failing calls to kernel-doc,
+ * but execution continues. */
+int exitstatus = 0;
+
+typedef void DFL(char *);
+DFL *defaultline;
+
+typedef void FILEONLY(char * file);
+FILEONLY *internalfunctions;
+FILEONLY *externalfunctions;
+FILEONLY *symbolsonly;
+
+typedef void FILELINE(char * file, char * line);
+FILELINE * singlefunctions;
+FILELINE * entity_system;
+
+#define MAXLINESZ     2048
+#define MAXFILES      250
+#define KERNELDOCPATH "scripts/"
+#define KERNELDOC     "kernel-doc"
+#define DOCBOOK       "-docbook"
+#define FUNCTION      "-function"
+#define NOFUNCTION    "-nofunction"
+
+void usage (void)
+{
+       fprintf(stderr, "Usage: docproc {doc|depend} file\n");
+       fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
+       fprintf(stderr, "doc: frontend when generating kernel documentation\n");
+       fprintf(stderr, "depend: generate list of files referenced within file\n");
+}
+
+/*
+ * Execute kernel-doc with parameters givin in svec
+ */
+void exec_kernel_doc(char **svec)
+{
+       pid_t pid;
+       int ret;
+       char real_filename[PATH_MAX + 1];
+       /* Make sure output generated so far are flushed */
+       fflush(stdout);
+       switch(pid=fork()) {
+               case -1:
+                       perror("fork");
+                       exit(1);
+               case  0:
+                       memset(real_filename, 0, sizeof(real_filename));
+                       strncat(real_filename, getenv("SRCTREE"), PATH_MAX);
+                       strncat(real_filename, KERNELDOCPATH KERNELDOC,
+                                       PATH_MAX - strlen(real_filename));
+                       execvp(real_filename, svec);
+                       fprintf(stderr, "exec ");
+                       perror(real_filename);
+                       exit(1);
+               default:
+                       waitpid(pid, &ret ,0);
+       }
+       if (WIFEXITED(ret))
+               exitstatus |= WEXITSTATUS(ret);
+       else
+               exitstatus = 0xff;
+}
+
+/* Types used to create list of all exported symbols in a number of files */
+struct symbols
+{
+       char *name;
+};
+
+struct symfile
+{
+       char *filename;
+       struct symbols *symbollist;
+       int symbolcnt;
+};
+
+struct symfile symfilelist[MAXFILES];
+int symfilecnt = 0;
+
+void add_new_symbol(struct symfile *sym, char * symname)
+{
+       sym->symbollist =
+          realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+       sym->symbollist[sym->symbolcnt++].name = strdup(symname);
+}
+
+/* Add a filename to the list */
+struct symfile * add_new_file(char * filename)
+{
+       symfilelist[symfilecnt++].filename = strdup(filename);
+       return &symfilelist[symfilecnt - 1];
+}
+/* Check if file already are present in the list */
+struct symfile * filename_exist(char * filename)
+{
+       int i;
+       for (i=0; i < symfilecnt; i++)
+               if (strcmp(symfilelist[i].filename, filename) == 0)
+                       return &symfilelist[i];
+       return NULL;
+}
+
+/*
+ * List all files referenced within the template file.
+ * Files are separated by tabs.
+ */
+void adddep(char * file)                  { printf("\t%s", file); }
+void adddep2(char * file, char * line)     { line = line; adddep(file); }
+void noaction(char * line)                { line = line; }
+void noaction2(char * file, char * line)   { file = file; line = line; }
+
+/* Echo the line without further action */
+void printline(char * line)               { printf("%s", line); }
+
+/*
+ * Find all symbols exported with EXPORT_SYMBOL and EXPORT_SYMBOL_GPL
+ * in filename.
+ * All symbols located are stored in symfilelist.
+ */
+void find_export_symbols(char * filename)
+{
+       FILE * fp;
+       struct symfile *sym;
+       char line[MAXLINESZ];
+       if (filename_exist(filename) == NULL) {
+               char real_filename[PATH_MAX + 1];
+               memset(real_filename, 0, sizeof(real_filename));
+               strncat(real_filename, getenv("SRCTREE"), PATH_MAX);
+               strncat(real_filename, filename,
+                               PATH_MAX - strlen(real_filename));
+               sym = add_new_file(filename);
+               fp = fopen(real_filename, "r");
+               if (fp == NULL)
+               {
+                       fprintf(stderr, "docproc: ");
+                       perror(real_filename);
+               }
+               while(fgets(line, MAXLINESZ, fp)) {
+                       char *p;
+                       char *e;
+                       if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
+                            ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
+                               /* Skip EXPORT_SYMBOL{_GPL} */
+                               while (isalnum(*p) || *p == '_')
+                                       p++;
+                               /* Remove paranteses and additional ws */
+                               while (isspace(*p))
+                                       p++;
+                               if (*p != '(')
+                                       continue; /* Syntax error? */
+                               else
+                                       p++;
+                               while (isspace(*p))
+                                       p++;
+                               e = p;
+                               while (isalnum(*e) || *e == '_')
+                                       e++;
+                               *e = '\0';
+                               add_new_symbol(sym, p);
+                       }
+               }
+               fclose(fp);
+       }
+}
+
+/*
+ * Document all external or internal functions in a file.
+ * Call kernel-doc with following parameters:
+ * kernel-doc -docbook -nofunction function_name1 filename
+ * function names are obtained from all the the src files
+ * by find_export_symbols.
+ * intfunc uses -nofunction
+ * extfunc uses -function
+ */
+void docfunctions(char * filename, char * type)
+{
+       int i,j;
+       int symcnt = 0;
+       int idx = 0;
+       char **vec;
+
+       for (i=0; i <= symfilecnt; i++)
+               symcnt += symfilelist[i].symbolcnt;
+       vec = malloc((2 + 2 * symcnt + 2) * sizeof(char*));
+       if (vec == NULL) {
+               perror("docproc: ");
+               exit(1);
+       }
+       vec[idx++] = KERNELDOC;
+       vec[idx++] = DOCBOOK;
+       for (i=0; i < symfilecnt; i++) {
+               struct symfile * sym = &symfilelist[i];
+               for (j=0; j < sym->symbolcnt; j++) {
+                       vec[idx++]     = type;
+                       vec[idx++] = sym->symbollist[j].name;
+               }
+       }
+       vec[idx++]     = filename;
+       vec[idx] = NULL;
+       printf("<!-- %s -->\n", filename);
+       exec_kernel_doc(vec);
+       fflush(stdout);
+       free(vec);
+}
+void intfunc(char * filename) {        docfunctions(filename, NOFUNCTION); }
+void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
+
+/*
+ * Document spÃ¥ecific function(s) in a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function function1 [-function function2]
+ */
+void singfunc(char * filename, char * line)
+{
+       char *vec[200]; /* Enough for specific functions */
+        int i, idx = 0;
+        int startofsym = 1;
+       vec[idx++] = KERNELDOC;
+       vec[idx++] = DOCBOOK;
+
+        /* Split line up in individual parameters preceeded by FUNCTION */
+        for (i=0; line[i]; i++) {
+                if (isspace(line[i])) {
+                        line[i] = '\0';
+                        startofsym = 1;
+                        continue;
+                }
+                if (startofsym) {
+                        startofsym = 0;
+                        vec[idx++] = FUNCTION;
+                        vec[idx++] = &line[i];
+                }
+        }
+       vec[idx++] = filename;
+       vec[idx] = NULL;
+       exec_kernel_doc(vec);
+}
+
+/*
+ * Parse file, calling action specific functions for:
+ * 1) Lines containing !E
+ * 2) Lines containing !I
+ * 3) Lines containing !D
+ * 4) Lines containing !F
+ * 5) Default lines - lines not matching the above
+ */
+void parse_file(FILE *infile)
+{
+       char line[MAXLINESZ];
+       char * s;
+       while(fgets(line, MAXLINESZ, infile)) {
+               if (line[0] == '!') {
+                       s = line + 2;
+                       switch (line[1]) {
+                               case 'E':
+                                       while (*s && !isspace(*s)) s++;
+                                       *s = '\0';
+                                       externalfunctions(line+2);
+                                       break;
+                               case 'I':
+                                       while (*s && !isspace(*s)) s++;
+                                       *s = '\0';
+                                       internalfunctions(line+2);
+                                       break;
+                               case 'D':
+                                       while (*s && !isspace(*s)) s++;
+                                        *s = '\0';
+                                        symbolsonly(line+2);
+                                        break;
+                               case 'F':
+                                       /* filename */
+                                       while (*s && !isspace(*s)) s++;
+                                       *s++ = '\0';
+                                        /* function names */
+                                       while (isspace(*s))
+                                               s++;
+                                       singlefunctions(line +2, s);
+                                       break;
+                               default:
+                                       defaultline(line);
+                       }
+               }
+               else {
+                       defaultline(line);
+               }
+       }
+       fflush(stdout);
+}
+
+
+int main(int argc, char *argv[])
+{
+       FILE * infile;
+       if (argc != 3) {
+               usage();
+               exit(1);
+       }
+       /* Open file, exit on error */
+       infile = fopen(argv[2], "r");
+        if (infile == NULL) {
+                fprintf(stderr, "docproc: ");
+                perror(argv[2]);
+                exit(2);
+        }
+
+       if (strcmp("doc", argv[1]) == 0)
+       {
+               /* Need to do this in two passes.
+                * First pass is used to collect all symbols exported
+                * in the various files.
+                * Second pass generate the documentation.
+                * This is required because function are declared
+                * and exported in different files :-((
+                */
+               /* Collect symbols */
+               defaultline       = noaction;
+               internalfunctions = find_export_symbols;
+               externalfunctions = find_export_symbols;
+               symbolsonly       = find_export_symbols;
+               singlefunctions   = noaction2;
+               parse_file(infile);
+
+               /* Rewind to start from beginning of file again */
+               fseek(infile, 0, SEEK_SET);
+               defaultline       = printline;
+               internalfunctions = intfunc;
+               externalfunctions = extfunc;
+               symbolsonly       = printline;
+               singlefunctions   = singfunc;
+
+               parse_file(infile);
+       }
+       else if (strcmp("depend", argv[1]) == 0)
+       {
+               /* Create first part of dependency chain
+                * file.tmpl */
+               printf("%s\t", argv[2]);
+               defaultline       = noaction;
+               internalfunctions = adddep;
+               externalfunctions = adddep;
+               symbolsonly       = adddep;
+               singlefunctions   = adddep2;
+               parse_file(infile);
+               printf("\n");
+       }
+       else
+       {
+               fprintf(stderr, "Unknown option: %s\n", argv[1]);
+               exit(1);
+       }
+       fclose(infile);
+       fflush(stdout);
+       return exitstatus;
+}
+
diff --git a/kitten/scripts/basic/fixdep.c b/kitten/scripts/basic/fixdep.c
new file mode 100644 (file)
index 0000000..668a11a
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the kernel build
+ * ===========================================================================
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * Introduction:
+ *
+ * gcc produces a very nice and correct list of dependencies which
+ * tells make when to remake a file.
+ *
+ * To use this list as-is however has the drawback that virtually
+ * every file in the kernel includes <linux/config.h> which then again
+ * includes <linux/autoconf.h>
+ *
+ * If the user re-runs make *config, linux/autoconf.h will be
+ * regenerated.  make notices that and will rebuild every file which
+ * includes autoconf.h, i.e. basically all files. This is extremely
+ * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
+ *
+ * So we play the same trick that "mkdep" played before. We replace
+ * the dependency on linux/autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *
+ * To be exact, split-include populates a tree in include/config/,
+ * e.g. include/config/his/driver.h, which contains the #define/#undef
+ * for the CONFIG_HIS_DRIVER option.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+ * so most likely only his driver ;-)
+ *
+ * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
+ *
+ * So to get dependencies right, there are two issues:
+ * o if any of the files the compiler read changed, we need to rebuild
+ * o if the command line given to the compile the file changed, we
+ *   better rebuild as well.
+ *
+ * The former is handled by using the -MD output, the later by saving
+ * the command line used to compile the old object and comparing it
+ * to the one we would now use.
+ *
+ * Again, also this idea is pretty old and has been discussed on
+ * kbuild-devel a long time ago. I don't have a sensibly working
+ * internet connection right now, so I rather don't mention names
+ * without double checking.
+ *
+ * This code here has been based partially based on mkdep.c, which
+ * says the following about its history:
+ *
+ *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ *   This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ *
+ * It is invoked as
+ *
+ *   fixdep <depfile> <target> <cmdline>
+ *
+ * and will read the dependency file <depfile>
+ *
+ * The transformed dependency snipped is written to stdout.
+ *
+ * It first generates a line
+ *
+ *   cmd_<target> = <cmdline>
+ *
+ * and then basically copies the .<target>.d file to stdout, in the
+ * process filtering out the dependency on linux/autoconf.h and adding
+ * dependencies on include/config/my/option.h for every
+ * CONFIG_MY_OPTION encountered in any of the prequisites.
+ *
+ * It will also filter out all the dependencies on *.ver. We need
+ * to make sure that the generated version checksum are globally up
+ * to date before even starting the recursive build, so it's too late
+ * at this point anyway.
+ *
+ * The algorithm to grep for "CONFIG_..." is bit unusual, but should
+ * be fast ;-) We don't even try to really parse the header files, but
+ * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
+ * be picked up as well. It's not a problem with respect to
+ * correctness, since that can only give too many dependencies, thus
+ * we cannot miss a rebuild. Since people tend to not mention totally
+ * unrelated CONFIG_ options all over the place, it's not an
+ * efficiency problem either.
+ *
+ * (Note: it'd be easy to port over the complete mkdep state machine,
+ *  but I don't think the added complexity is worth it)
+ */
+/*
+ * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
+ * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
+ * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
+ * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
+ * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
+ * those files will have correct dependencies.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+
+#define INT_CONF ntohl(0x434f4e46)
+#define INT_ONFI ntohl(0x4f4e4649)
+#define INT_NFIG ntohl(0x4e464947)
+#define INT_FIG_ ntohl(0x4649475f)
+
+char *target;
+char *depfile;
+char *cmdline;
+
+void usage(void)
+
+{
+       fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+       exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+void print_cmdline(void)
+{
+       printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+char * str_config  = NULL;
+int    size_config = 0;
+int    len_config  = 0;
+
+/*
+ * Grow the configuration string to a desired length.
+ * Usually the first growth is plenty.
+ */
+void grow_config(int len)
+{
+       while (len_config + len > size_config) {
+               if (size_config == 0)
+                       size_config = 2048;
+               str_config = realloc(str_config, size_config *= 2);
+               if (str_config == NULL)
+                       { perror("fixdep:malloc"); exit(1); }
+       }
+}
+
+
+
+/*
+ * Lookup a value in the configuration string.
+ */
+int is_defined_config(const char * name, int len)
+{
+       const char * pconfig;
+       const char * plast = str_config + len_config - len;
+       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
+               if (pconfig[ -1] == '\n'
+               &&  pconfig[len] == '\n'
+               &&  !memcmp(pconfig, name, len))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Add a new value to the configuration string.
+ */
+void define_config(const char * name, int len)
+{
+       grow_config(len + 1);
+
+       memcpy(str_config+len_config, name, len);
+       len_config += len;
+       str_config[len_config++] = '\n';
+}
+
+/*
+ * Clear the set of configuration strings.
+ */
+void clear_config(void)
+{
+       len_config = 0;
+       define_config("", 0);
+}
+
+/*
+ * Record the use of a CONFIG_* word.
+ */
+void use_config(char *m, int slen)
+{
+       char s[PATH_MAX];
+       char *p;
+
+       if (is_defined_config(m, slen))
+           return;
+
+       define_config(m, slen);
+
+       memcpy(s, m, slen); s[slen] = 0;
+
+       for (p = s; p < s + slen; p++) {
+               if (*p == '_')
+                       *p = '/';
+               else
+                       *p = tolower((int)*p);
+       }
+       printf("    $(wildcard include/config/%s.h) \\\n", s);
+}
+
+void parse_config_file(char *map, size_t len)
+{
+       int *end = (int *) (map + len);
+       /* start at +1, so that p can never be < map */
+       int *m   = (int *) map + 1;
+       char *p, *q;
+
+       for (; m < end; m++) {
+               if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+               if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+               if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+               if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
+               continue;
+       conf:
+               if (p > map + len - 7)
+                       continue;
+               if (memcmp(p, "CONFIG_", 7))
+                       continue;
+               for (q = p + 7; q < map + len; q++) {
+                       if (!(isalnum(*q) || *q == '_'))
+                               goto found;
+               }
+               continue;
+
+       found:
+               use_config(p+7, q-p-7);
+       }
+}
+
+/* test is s ends in sub */
+int strrcmp(char *s, char *sub)
+{
+       int slen = strlen(s);
+       int sublen = strlen(sub);
+
+       if (sublen > slen)
+               return 1;
+
+       return memcmp(s + slen - sublen, sub, sublen);
+}
+
+void do_config_file(char *filename)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "fixdep: ");
+               perror(filename);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("fixdep: mmap");
+               close(fd);
+               return;
+       }
+
+       parse_config_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+}
+
+void parse_dep_file(void *map, size_t len)
+{
+       char *m = map;
+       char *end = m + len;
+       char *p;
+       char s[PATH_MAX];
+
+       p = strchr(m, ':');
+       if (!p) {
+               fprintf(stderr, "fixdep: parse error\n");
+               exit(1);
+       }
+       memcpy(s, m, p-m); s[p-m] = 0;
+       printf("deps_%s := \\\n", target);
+       m = p+1;
+
+       clear_config();
+
+       while (m < end) {
+               while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+                       m++;
+               p = m;
+               while (p < end && *p != ' ') p++;
+               if (p == end) {
+                       do p--; while (!isalnum(*p));
+                       p++;
+               }
+               memcpy(s, m, p-m); s[p-m] = 0;
+               if (strrcmp(s, "include/linux/autoconf.h") &&
+                   strrcmp(s, "arch/um/include/uml-config.h") &&
+                   strrcmp(s, ".ver")) {
+                       printf("  %s \\\n", s);
+                       do_config_file(s);
+               }
+               m = p + 1;
+       }
+       printf("\n%s: $(deps_%s)\n\n", target, target);
+       printf("$(deps_%s):\n", target);
+}
+
+void print_deps(void)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(depfile, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "fixdep: ");
+               perror(depfile);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               fprintf(stderr,"fixdep: %s is empty\n",depfile);
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("fixdep: mmap");
+               close(fd);
+               return;
+       }
+
+       parse_dep_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+}
+
+void traps(void)
+{
+       static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
+
+       if (*(int *)test != INT_CONF) {
+               fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
+                       *(int *)test);
+               exit(2);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       traps();
+
+       if (argc != 4)
+               usage();
+
+       depfile = argv[1];
+       target = argv[2];
+       cmdline = argv[3];
+
+       print_cmdline();
+       print_deps();
+
+       return 0;
+}
diff --git a/kitten/scripts/basic/split-include.c b/kitten/scripts/basic/split-include.c
new file mode 100644 (file)
index 0000000..459c452
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * split-include.c
+ *
+ * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ * This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ * This program takes autoconf.h as input and outputs a directory full
+ * of one-line include files, merging onto the old values.
+ *
+ * Think of the configuration options as key-value pairs.  Then there
+ * are five cases:
+ *
+ *    key      old value   new value   action
+ *
+ *    KEY-1    VALUE-1     VALUE-1     leave file alone
+ *    KEY-2    VALUE-2A    VALUE-2B    write VALUE-2B into file
+ *    KEY-3    -           VALUE-3     write VALUE-3  into file
+ *    KEY-4    VALUE-4     -           write an empty file
+ *    KEY-5    (empty)     -           leave old empty file alone
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ERROR_EXIT(strExit)                                            \
+    {                                                                  \
+       const int errnoSave = errno;                                    \
+       fprintf(stderr, "%s: ", str_my_name);                           \
+       errno = errnoSave;                                              \
+       perror((strExit));                                              \
+       exit(1);                                                        \
+    }
+
+
+
+int main(int argc, const char * argv [])
+{
+    const char * str_my_name;
+    const char * str_file_autoconf;
+    const char * str_dir_config;
+
+    FILE * fp_config;
+    FILE * fp_target;
+    FILE * fp_find;
+
+    int buffer_size;
+
+    char * line;
+    char * old_line;
+    char * list_target;
+    char * ptarget;
+
+    struct stat stat_buf;
+
+    /* Check arg count. */
+    if (argc != 3)
+    {
+       fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
+       exit(1);
+    }
+
+    str_my_name       = argv[0];
+    str_file_autoconf = argv[1];
+    str_dir_config    = argv[2];
+
+    /* Find a buffer size. */
+    if (stat(str_file_autoconf, &stat_buf) != 0)
+       ERROR_EXIT(str_file_autoconf);
+    buffer_size = 2 * stat_buf.st_size + 4096;
+
+    /* Allocate buffers. */
+    if ( (line        = malloc(buffer_size)) == NULL
+    ||   (old_line    = malloc(buffer_size)) == NULL
+    ||   (list_target = malloc(buffer_size)) == NULL )
+       ERROR_EXIT(str_file_autoconf);
+
+    /* Open autoconfig file. */
+    if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
+       ERROR_EXIT(str_file_autoconf);
+
+    /* Make output directory if needed. */
+    if (stat(str_dir_config, &stat_buf) != 0)
+    {
+       if (mkdir(str_dir_config, 0755) != 0)
+           ERROR_EXIT(str_dir_config);
+    }
+
+    /* Change to output directory. */
+    if (chdir(str_dir_config) != 0)
+       ERROR_EXIT(str_dir_config);
+
+    /* Put initial separator into target list. */
+    ptarget = list_target;
+    *ptarget++ = '\n';
+
+    /* Read config lines. */
+    while (fgets(line, buffer_size, fp_config))
+    {
+       const char * str_config;
+       int is_same;
+       int itarget;
+
+       if (line[0] != '#')
+           continue;
+       if ((str_config = strstr(line, "CONFIG_")) == NULL)
+           continue;
+
+       /* Make the output file name. */
+       str_config += sizeof("CONFIG_") - 1;
+       for (itarget = 0; !isspace(str_config[itarget]); itarget++)
+       {
+           int c = (unsigned char) str_config[itarget];
+           if (isupper(c)) c = tolower(c);
+           if (c == '_')   c = '/';
+           ptarget[itarget] = c;
+       }
+       ptarget[itarget++] = '.';
+       ptarget[itarget++] = 'h';
+       ptarget[itarget++] = '\0';
+
+       /* Check for existing file. */
+       is_same = 0;
+       if ((fp_target = fopen(ptarget, "r")) != NULL)
+       {
+           fgets(old_line, buffer_size, fp_target);
+           if (fclose(fp_target) != 0)
+               ERROR_EXIT(ptarget);
+           if (!strcmp(line, old_line))
+               is_same = 1;
+       }
+
+       if (!is_same)
+       {
+           /* Auto-create directories. */
+           int islash;
+           for (islash = 0; islash < itarget; islash++)
+           {
+               if (ptarget[islash] == '/')
+               {
+                   ptarget[islash] = '\0';
+                   if (stat(ptarget, &stat_buf) != 0
+                   &&  mkdir(ptarget, 0755)     != 0)
+                       ERROR_EXIT( ptarget );
+                   ptarget[islash] = '/';
+               }
+           }
+
+           /* Write the file. */
+           if ((fp_target = fopen(ptarget, "w" )) == NULL)
+               ERROR_EXIT(ptarget);
+           fputs(line, fp_target);
+           if (ferror(fp_target) || fclose(fp_target) != 0)
+               ERROR_EXIT(ptarget);
+       }
+
+       /* Update target list */
+       ptarget += itarget;
+       *(ptarget-1) = '\n';
+    }
+
+    /*
+     * Close autoconfig file.
+     * Terminate the target list.
+     */
+    if (fclose(fp_config) != 0)
+       ERROR_EXIT(str_file_autoconf);
+    *ptarget = '\0';
+
+    /*
+     * Fix up existing files which have no new value.
+     * This is Case 4 and Case 5.
+     *
+     * I re-read the tree and filter it against list_target.
+     * This is crude.  But it avoids data copies.  Also, list_target
+     * is compact and contiguous, so it easily fits into cache.
+     *
+     * Notice that list_target contains strings separated by \n,
+     * with a \n before the first string and after the last.
+     * fgets gives the incoming names a terminating \n.
+     * So by having an initial \n, strstr will find exact matches.
+     */
+
+    fp_find = popen("find * -type f -name \"*.h\" -print", "r");
+    if (fp_find == 0)
+       ERROR_EXIT( "find" );
+
+    line[0] = '\n';
+    while (fgets(line+1, buffer_size, fp_find))
+    {
+       if (strstr(list_target, line) == NULL)
+       {
+           /*
+            * This is an old file with no CONFIG_* flag in autoconf.h.
+            */
+
+           /* First strip the \n. */
+           line[strlen(line)-1] = '\0';
+
+           /* Grab size. */
+           if (stat(line+1, &stat_buf) != 0)
+               ERROR_EXIT(line);
+
+           /* If file is not empty, make it empty and give it a fresh date. */
+           if (stat_buf.st_size != 0)
+           {
+               if ((fp_target = fopen(line+1, "w")) == NULL)
+                   ERROR_EXIT(line);
+               if (fclose(fp_target) != 0)
+                   ERROR_EXIT(line);
+           }
+       }
+    }
+
+    if (pclose(fp_find) != 0)
+       ERROR_EXIT("find");
+
+    return 0;
+}
diff --git a/kitten/scripts/kallsyms.c b/kitten/scripts/kallsyms.c
new file mode 100644 (file)
index 0000000..48ab883
--- /dev/null
@@ -0,0 +1,507 @@
+/* Generate assembler source containing symbol information
+ *
+ * Copyright 2002       by Kai Germaschewski
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S
+ *
+ * ChangeLog:
+ *
+ * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
+ *      Changed the compression method from stem compression to "table lookup"
+ *      compression
+ *
+ *      Table compression uses all the unused char codes on the symbols and
+ *  maps these to the most used substrings (tokens). For instance, it might
+ *  map char code 0xF7 to represent "write_" and then in every symbol where
+ *  "write_" appears it can be replaced by 0xF7, saving 5 bytes.
+ *      The used codes themselves are also placed in the table so that the
+ *  decompresion can work without "special cases".
+ *      Applied to kernel symbols, this usually produces a compression ratio
+ *  of about 50%.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define KSYM_NAME_LEN          127
+
+
+struct sym_entry {
+       unsigned long long addr;
+       unsigned int len;
+       unsigned char *sym;
+};
+
+
+static struct sym_entry *table;
+static unsigned int table_size, table_cnt;
+static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
+static int all_symbols = 0;
+static char symbol_prefix_char = '\0';
+
+int token_profit[0x10000];
+
+/* the table that holds the result of the compression */
+unsigned char best_table[256][2];
+unsigned char best_table_len[256];
+
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+       exit(1);
+}
+
+/*
+ * This ignores the intensely annoying "mapping symbols" found
+ * in ARM ELF files: $a, $t and $d.
+ */
+static inline int is_arm_mapping_symbol(const char *str)
+{
+       return str[0] == '$' && strchr("atd", str[1])
+              && (str[2] == '\0' || str[2] == '.');
+}
+
+static int read_symbol(FILE *in, struct sym_entry *s)
+{
+       char str[500];
+       char *sym, stype;
+       int rc;
+
+       rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
+       if (rc != 3) {
+               if (rc != EOF) {
+                       /* skip line */
+                       fgets(str, 500, in);
+               }
+               return -1;
+       }
+
+       sym = str;
+       /* skip prefix char */
+       if (symbol_prefix_char && str[0] == symbol_prefix_char)
+               sym++;
+
+       /* Ignore most absolute/undefined (?) symbols. */
+       if (strcmp(sym, "_stext") == 0)
+               _stext = s->addr;
+       else if (strcmp(sym, "_etext") == 0)
+               _etext = s->addr;
+       else if (strcmp(sym, "_sinittext") == 0)
+               _sinittext = s->addr;
+       else if (strcmp(sym, "_einittext") == 0)
+               _einittext = s->addr;
+       else if (strcmp(sym, "_sextratext") == 0)
+               _sextratext = s->addr;
+       else if (strcmp(sym, "_eextratext") == 0)
+               _eextratext = s->addr;
+       else if (toupper(stype) == 'A')
+       {
+               /* Keep these useful absolute symbols */
+               if (strcmp(sym, "__kernel_syscall_via_break") &&
+                   strcmp(sym, "__kernel_syscall_via_epc") &&
+                   strcmp(sym, "__kernel_sigtramp") &&
+                   strcmp(sym, "__gp"))
+                       return -1;
+
+       }
+       else if (toupper(stype) == 'U' ||
+                is_arm_mapping_symbol(sym))
+               return -1;
+       /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
+       else if (str[0] == '$')
+               return -1;
+
+       /* include the type field in the symbol name, so that it gets
+        * compressed together */
+       s->len = strlen(str) + 1;
+       s->sym = malloc(s->len + 1);
+       if (!s->sym) {
+               fprintf(stderr, "kallsyms failure: "
+                       "unable to allocate required amount of memory\n");
+               exit(EXIT_FAILURE);
+       }
+       strcpy((char *)s->sym + 1, str);
+       s->sym[0] = stype;
+
+       return 0;
+}
+
+static int symbol_valid(struct sym_entry *s)
+{
+       /* Symbols which vary between passes.  Passes 1 and 2 must have
+        * identical symbol lists.  The kallsyms_* symbols below are only added
+        * after pass 1, they would be included in pass 2 when --all-symbols is
+        * specified so exclude them to get a stable symbol list.
+        */
+       static char *special_symbols[] = {
+               "kallsyms_addresses",
+               "kallsyms_num_syms",
+               "kallsyms_names",
+               "kallsyms_markers",
+               "kallsyms_token_table",
+               "kallsyms_token_index",
+
+       /* Exclude linker generated symbols which vary between passes */
+               "_SDA_BASE_",           /* ppc */
+               "_SDA2_BASE_",          /* ppc */
+               NULL };
+       int i;
+       int offset = 1;
+
+       /* skip prefix char */
+       if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
+               offset++;
+
+       /* if --all-symbols is not specified, then symbols outside the text
+        * and inittext sections are discarded */
+       if (!all_symbols) {
+               if ((s->addr < _stext || s->addr > _etext)
+                   && (s->addr < _sinittext || s->addr > _einittext)
+                   && (s->addr < _sextratext || s->addr > _eextratext))
+                       return 0;
+               /* Corner case.  Discard any symbols with the same value as
+                * _etext _einittext or _eextratext; they can move between pass
+                * 1 and 2 when the kallsyms data are added.  If these symbols
+                * move then they may get dropped in pass 2, which breaks the
+                * kallsyms rules.
+                */
+               if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
+                   (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
+                   (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
+                       return 0;
+       }
+
+       /* Exclude symbols which vary between passes. */
+       if (strstr((char *)s->sym + offset, "_compiled."))
+               return 0;
+
+       for (i = 0; special_symbols[i]; i++)
+               if( strcmp((char *)s->sym + offset, special_symbols[i]) == 0 )
+                       return 0;
+
+       return 1;
+}
+
+static void read_map(FILE *in)
+{
+       while (!feof(in)) {
+               if (table_cnt >= table_size) {
+                       table_size += 10000;
+                       table = realloc(table, sizeof(*table) * table_size);
+                       if (!table) {
+                               fprintf(stderr, "out of memory\n");
+                               exit (1);
+                       }
+               }
+               if (read_symbol(in, &table[table_cnt]) == 0)
+                       table_cnt++;
+       }
+}
+
+static void output_label(char *label)
+{
+       if (symbol_prefix_char)
+               printf(".globl %c%s\n", symbol_prefix_char, label);
+       else
+               printf(".globl %s\n", label);
+       printf("\tALGN\n");
+       if (symbol_prefix_char)
+               printf("%c%s:\n", symbol_prefix_char, label);
+       else
+               printf("%s:\n", label);
+}
+
+/* uncompress a compressed symbol. When this function is called, the best table
+ * might still be compressed itself, so the function needs to be recursive */
+static int expand_symbol(unsigned char *data, int len, char *result)
+{
+       int c, rlen, total=0;
+
+       while (len) {
+               c = *data;
+               /* if the table holds a single char that is the same as the one
+                * we are looking for, then end the search */
+               if (best_table[c][0]==c && best_table_len[c]==1) {
+                       *result++ = c;
+                       total++;
+               } else {
+                       /* if not, recurse and expand */
+                       rlen = expand_symbol(best_table[c], best_table_len[c], result);
+                       total += rlen;
+                       result += rlen;
+               }
+               data++;
+               len--;
+       }
+       *result=0;
+
+       return total;
+}
+
+static void write_src(void)
+{
+       unsigned int i, k, off;
+       unsigned int best_idx[256];
+       unsigned int *markers;
+       char buf[KSYM_NAME_LEN+1];
+
+       printf("#include <arch/types.h>\n");
+       printf("#if BITS_PER_LONG == 64\n");
+       printf("#define PTR .quad\n");
+       printf("#define ALGN .align 8\n");
+       printf("#else\n");
+       printf("#define PTR .long\n");
+       printf("#define ALGN .align 4\n");
+       printf("#endif\n");
+
+       printf(".data\n");
+
+       output_label("kallsyms_addresses");
+       for (i = 0; i < table_cnt; i++) {
+               printf("\tPTR\t%#llx\n", table[i].addr);
+       }
+       printf("\n");
+
+       output_label("kallsyms_num_syms");
+       printf("\tPTR\t%d\n", table_cnt);
+       printf("\n");
+
+       /* table of offset markers, that give the offset in the compressed stream
+        * every 256 symbols */
+       markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
+       if (!markers) {
+               fprintf(stderr, "kallsyms failure: "
+                       "unable to allocate required memory\n");
+               exit(EXIT_FAILURE);
+       }
+
+       output_label("kallsyms_names");
+       off = 0;
+       for (i = 0; i < table_cnt; i++) {
+               if ((i & 0xFF) == 0)
+                       markers[i >> 8] = off;
+
+               printf("\t.byte 0x%02x", table[i].len);
+               for (k = 0; k < table[i].len; k++)
+                       printf(", 0x%02x", table[i].sym[k]);
+               printf("\n");
+
+               off += table[i].len + 1;
+       }
+       printf("\n");
+
+       output_label("kallsyms_markers");
+       for (i = 0; i < ((table_cnt + 255) >> 8); i++)
+               printf("\tPTR\t%d\n", markers[i]);
+       printf("\n");
+
+       free(markers);
+
+       output_label("kallsyms_token_table");
+       off = 0;
+       for (i = 0; i < 256; i++) {
+               best_idx[i] = off;
+               expand_symbol(best_table[i], best_table_len[i], buf);
+               printf("\t.asciz\t\"%s\"\n", buf);
+               off += strlen(buf) + 1;
+       }
+       printf("\n");
+
+       output_label("kallsyms_token_index");
+       for (i = 0; i < 256; i++)
+               printf("\t.short\t%d\n", best_idx[i]);
+       printf("\n");
+}
+
+
+/* table lookup compression functions */
+
+/* count all the possible tokens in a symbol */
+static void learn_symbol(unsigned char *symbol, int len)
+{
+       int i;
+
+       for (i = 0; i < len - 1; i++)
+               token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
+}
+
+/* decrease the count for all the possible tokens in a symbol */
+static void forget_symbol(unsigned char *symbol, int len)
+{
+       int i;
+
+       for (i = 0; i < len - 1; i++)
+               token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
+}
+
+/* remove all the invalid symbols from the table and do the initial token count */
+static void build_initial_tok_table(void)
+{
+       unsigned int i, pos;
+
+       pos = 0;
+       for (i = 0; i < table_cnt; i++) {
+               if ( symbol_valid(&table[i]) ) {
+                       if (pos != i)
+                               table[pos] = table[i];
+                       learn_symbol(table[pos].sym, table[pos].len);
+                       pos++;
+               }
+       }
+       table_cnt = pos;
+}
+
+/* replace a given token in all the valid symbols. Use the sampled symbols
+ * to update the counts */
+static void compress_symbols(unsigned char *str, int idx)
+{
+       unsigned int i, len, size;
+       unsigned char *p1, *p2;
+
+       for (i = 0; i < table_cnt; i++) {
+
+               len = table[i].len;
+               p1 = table[i].sym;
+
+               /* find the token on the symbol */
+               p2 = memmem(p1, len, str, 2);
+               if (!p2) continue;
+
+               /* decrease the counts for this symbol's tokens */
+               forget_symbol(table[i].sym, len);
+
+               size = len;
+
+               do {
+                       *p2 = idx;
+                       p2++;
+                       size -= (p2 - p1);
+                       memmove(p2, p2 + 1, size);
+                       p1 = p2;
+                       len--;
+
+                       if (size < 2) break;
+
+                       /* find the token on the symbol */
+                       p2 = memmem(p1, size, str, 2);
+
+               } while (p2);
+
+               table[i].len = len;
+
+               /* increase the counts for this symbol's new tokens */
+               learn_symbol(table[i].sym, len);
+       }
+}
+
+/* search the token with the maximum profit */
+static int find_best_token(void)
+{
+       int i, best, bestprofit;
+
+       bestprofit=-10000;
+       best = 0;
+
+       for (i = 0; i < 0x10000; i++) {
+               if (token_profit[i] > bestprofit) {
+                       best = i;
+                       bestprofit = token_profit[i];
+               }
+       }
+       return best;
+}
+
+/* this is the core of the algorithm: calculate the "best" table */
+static void optimize_result(void)
+{
+       int i, best;
+
+       /* using the '\0' symbol last allows compress_symbols to use standard
+        * fast string functions */
+       for (i = 255; i >= 0; i--) {
+
+               /* if this table slot is empty (it is not used by an actual
+                * original char code */
+               if (!best_table_len[i]) {
+
+                       /* find the token with the breates profit value */
+                       best = find_best_token();
+
+                       /* place it in the "best" table */
+                       best_table_len[i] = 2;
+                       best_table[i][0] = best & 0xFF;
+                       best_table[i][1] = (best >> 8) & 0xFF;
+
+                       /* replace this token in all the valid symbols */
+                       compress_symbols(best_table[i], i);
+               }
+       }
+}
+
+/* start by placing the symbols that are actually used on the table */
+static void insert_real_symbols_in_table(void)
+{
+       unsigned int i, j, c;
+
+       memset(best_table, 0, sizeof(best_table));
+       memset(best_table_len, 0, sizeof(best_table_len));
+
+       for (i = 0; i < table_cnt; i++) {
+               for (j = 0; j < table[i].len; j++) {
+                       c = table[i].sym[j];
+                       best_table[c][0]=c;
+                       best_table_len[c]=1;
+               }
+       }
+}
+
+static void optimize_token_table(void)
+{
+       build_initial_tok_table();
+
+       insert_real_symbols_in_table();
+
+       /* When valid symbol is not registered, exit to error */
+       if (!table_cnt) {
+               fprintf(stderr, "No valid symbol.\n");
+               exit(1);
+       }
+
+       optimize_result();
+}
+
+
+int main(int argc, char **argv)
+{
+       if (argc >= 2) {
+               int i;
+               for (i = 1; i < argc; i++) {
+                       if(strcmp(argv[i], "--all-symbols") == 0)
+                               all_symbols = 1;
+                       else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
+                               char *p = &argv[i][16];
+                               /* skip quote */
+                               if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
+                                       p++;
+                               symbol_prefix_char = *p;
+                       } else
+                               usage();
+               }
+       } else if (argc != 1)
+               usage();
+
+       read_map(stdin);
+       optimize_token_table();
+       write_src();
+
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/Makefile b/kitten/scripts/kconfig/Makefile
new file mode 100644 (file)
index 0000000..e6499db
--- /dev/null
@@ -0,0 +1,254 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
+
+xconfig: $(obj)/qconf
+       $< arch/$(ARCH)/Kconfig
+
+gconfig: $(obj)/gconf
+       $< arch/$(ARCH)/Kconfig
+
+menuconfig: $(obj)/mconf
+       $(Q)$(MAKE) $(build)=scripts/kconfig/lxdialog
+       $< arch/$(ARCH)/Kconfig
+
+config: $(obj)/conf
+       $< arch/$(ARCH)/Kconfig
+
+oldconfig: $(obj)/conf
+       $< -o arch/$(ARCH)/Kconfig
+
+silentoldconfig: $(obj)/conf
+       $< -s arch/$(ARCH)/Kconfig
+
+update-po-config: $(obj)/kxgettext
+       xgettext --default-domain=linux \
+          --add-comments --keyword=_ --keyword=N_ \
+          --files-from=scripts/kconfig/POTFILES.in \
+          --output scripts/kconfig/config.pot
+       $(Q)ln -fs Kconfig_i386 arch/um/Kconfig_arch
+       $(Q)for i in `ls arch/`; \
+       do \
+         scripts/kconfig/kxgettext arch/$$i/Kconfig \
+           | msguniq -o scripts/kconfig/linux_$${i}.pot; \
+       done
+       $(Q)msgcat scripts/kconfig/config.pot \
+         `find scripts/kconfig/ -type f -name linux_*.pot` \
+         --output scripts/kconfig/linux_raw.pot
+       $(Q)msguniq --sort-by-file scripts/kconfig/linux_raw.pot \
+           --output scripts/kconfig/linux.pot
+       $(Q)rm -f arch/um/Kconfig_arch
+       $(Q)rm -f scripts/kconfig/linux_*.pot scripts/kconfig/config.pot
+
+PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
+
+randconfig: $(obj)/conf
+       $< -r arch/$(ARCH)/Kconfig
+
+allyesconfig: $(obj)/conf
+       $< -y arch/$(ARCH)/Kconfig
+
+allnoconfig: $(obj)/conf
+       $< -n arch/$(ARCH)/Kconfig
+
+allmodconfig: $(obj)/conf
+       $< -m arch/$(ARCH)/Kconfig
+
+defconfig: $(obj)/conf
+ifeq ($(KBUILD_DEFCONFIG),)
+       $< -d arch/$(ARCH)/Kconfig
+else
+       @echo *** Default configuration is based on '$(KBUILD_DEFCONFIG)'
+       $(Q)$< -D arch/$(ARCH)/configs/$(KBUILD_DEFCONFIG) arch/$(ARCH)/Kconfig
+endif
+
+%_defconfig: $(obj)/conf
+       $(Q)$< -D arch/$(ARCH)/configs/$@ arch/$(ARCH)/Kconfig
+
+# Help text used by make help
+help:
+       @echo  '  config          - Update current config utilising a line-oriented program'
+       @echo  '  menuconfig      - Update current config utilising a menu based program'
+       @echo  '  xconfig         - Update current config utilising a QT based front-end'
+       @echo  '  gconfig         - Update current config utilising a GTK based front-end'
+       @echo  '  oldconfig       - Update current config utilising a provided .config as base'
+       @echo  '  randconfig      - New config with random answer to all options'
+       @echo  '  defconfig       - New config with default answer to all options'
+       @echo  '  allmodconfig    - New config selecting modules when possible'
+       @echo  '  allyesconfig    - New config where all options are accepted with yes'
+       @echo  '  allnoconfig     - New config where all options are answered with no'
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf:          Used for defconfig, oldconfig and related targets
+# mconf:  Used for the mconfig target.
+#         Utilizes the lxdialog package
+# qconf:  Used for the xconfig target
+#         Based on QT which needs to be installed to compile it
+# gconf:  Used for the gconfig target
+#         Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+hostprogs-y    := conf mconf qconf gconf kxgettext
+conf-objs      := conf.o  zconf.tab.o
+mconf-objs     := mconf.o zconf.tab.o
+kxgettext-objs := kxgettext.o zconf.tab.o
+
+ifeq ($(MAKECMDGOALS),xconfig)
+       qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+       gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+endif
+
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
+                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
+subdir- += lxdialog
+
+# Needed for systems without gettext
+KBUILD_HAVE_NLS := $(shell \
+     if echo "\#include <libintl.h>" | $(HOSTCC) $(HOSTCFLAGS) -E - > /dev/null 2>&1 ; \
+     then echo yes ; \
+     else echo no ; fi)
+ifeq ($(KBUILD_HAVE_NLS),no)
+HOSTCFLAGS     += -DKBUILD_NO_NLS
+endif
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_lex.zconf.o := -I$(src)
+HOSTCFLAGS_zconf.tab.o := -I$(src)
+
+HOSTLOADLIBES_qconf    = $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
+HOSTCFLAGS_gconf.o     = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+                          -D LKC_DIRECT_LINK
+
+$(obj)/qconf.o: $(obj)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(obj)/.tmp_qtcheck: $(src)/Makefile
+-include $(obj)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(obj)/.tmp_qtcheck:
+       @set -e; echo "  CHECK   qt"; dir=""; pkg=""; \
+       pkg-config --exists qt 2> /dev/null && pkg=qt; \
+       pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+       if [ -n "$$pkg" ]; then \
+         cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+         libs="\$$(shell pkg-config $$pkg --libs)"; \
+         moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+         dir="$$(pkg-config $$pkg --variable=prefix)"; \
+       else \
+         for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+           if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+         done; \
+         if [ -z "$$dir" ]; then \
+           echo "*"; \
+           echo "* Unable to find the QT installation. Please make sure that"; \
+           echo "* the QT development package is correctly installed and"; \
+           echo "* either install pkg-config or set the QTDIR environment"; \
+           echo "* variable to the correct location."; \
+           echo "*"; \
+           false; \
+         fi; \
+         libpath=$$dir/lib; lib=qt; osdir=""; \
+         $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+           osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+         test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+         test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+         cflags="-I$$dir/include"; \
+         libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+         moc="$$dir/bin/moc"; \
+       fi; \
+       if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
+         echo "*"; \
+         echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
+         echo "*"; \
+         moc="/usr/bin/moc"; \
+       fi; \
+       echo "KC_QT_CFLAGS=$$cflags" > $@; \
+       echo "KC_QT_LIBS=$$libs" >> $@; \
+       echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(obj)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(obj)/.tmp_gtkcheck:
+       @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then               \
+               if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then                  \
+                       touch $@;                                                               \
+               else                                                                    \
+                       echo "*";                                                       \
+                       echo "* GTK+ is present but version >= 2.0.0 is required.";     \
+                       echo "*";                                                       \
+                       false;                                                          \
+               fi                                                                      \
+       else                                                                            \
+               echo "*";                                                               \
+               echo "* Unable to find the GTK+ installation. Please make sure that";   \
+               echo "* the GTK+ 2.0 development package is correctly installed...";    \
+               echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0.";                 \
+               echo "*";                                                               \
+               false;                                                                  \
+       fi
+endif
+
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
+
+$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
+
+$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+
+$(obj)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+       $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+
+###
+# The following requires flex/bison/gperf
+# By default we use the _shipped versions, uncomment the following line if
+# you are modifying the flex/bison src.
+# LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
+
+%.tab.c: %.y
+       bison -l -b $* -p $(notdir $*) $<
+       cp $@ $@_shipped
+
+lex.%.c: %.l
+       flex -L -P$(notdir $*) -o$@ $<
+       cp $@ $@_shipped
+
+%.hash.c: %.gperf
+       gperf < $< > $@
+       cp $@ $@_shipped
+
+endif
diff --git a/kitten/scripts/kconfig/POTFILES.in b/kitten/scripts/kconfig/POTFILES.in
new file mode 100644 (file)
index 0000000..cc94e46
--- /dev/null
@@ -0,0 +1,5 @@
+scripts/kconfig/mconf.c
+scripts/kconfig/conf.c
+scripts/kconfig/confdata.c
+scripts/kconfig/gconf.c
+scripts/kconfig/qconf.cc
diff --git a/kitten/scripts/kconfig/conf.c b/kitten/scripts/kconfig/conf.c
new file mode 100644 (file)
index 0000000..a108528
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum {
+       ask_all,
+       ask_new,
+       ask_silent,
+       set_default,
+       set_yes,
+       set_mod,
+       set_no,
+       set_random
+} input_mode = ask_all;
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
+
+static void strip(char *str)
+{
+       char *p = str;
+       int l;
+
+       while ((isspace(*p)))
+               p++;
+       l = strlen(p);
+       if (p != str)
+               memmove(str, p, l + 1);
+       if (!l)
+               return;
+       p = str + l - 1;
+       while ((isspace(*p)))
+               *p-- = 0;
+}
+
+static void check_stdin(void)
+{
+       if (!valid_stdin && input_mode == ask_silent) {
+               printf(_("aborted!\n\n"));
+               printf(_("Console input/output is redirected. "));
+               printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+               exit(1);
+       }
+}
+
+static char *fgets_check_stream(char *s, int size, FILE *stream)
+{
+       char *ret = fgets(s, size, stream);
+
+       if (ret == NULL && feof(stream)) {
+               printf(_("aborted!\n\n"));
+               printf(_("Console input is closed. "));
+               printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+               exit(1);
+       }
+
+       return ret;
+}
+
+static void conf_askvalue(struct symbol *sym, const char *def)
+{
+       enum symbol_type type = sym_get_type(sym);
+       tristate val;
+
+       if (!sym_has_value(sym))
+               printf("(NEW) ");
+
+       line[0] = '\n';
+       line[1] = 0;
+
+       if (!sym_is_changable(sym)) {
+               printf("%s\n", def);
+               line[0] = '\n';
+               line[1] = 0;
+               return;
+       }
+
+       switch (input_mode) {
+       case set_no:
+       case set_mod:
+       case set_yes:
+       case set_random:
+               if (sym_has_value(sym)) {
+                       printf("%s\n", def);
+                       return;
+               }
+               break;
+       case ask_new:
+       case ask_silent:
+               if (sym_has_value(sym)) {
+                       printf("%s\n", def);
+                       return;
+               }
+               check_stdin();
+       case ask_all:
+               fflush(stdout);
+               fgets_check_stream(line, 128, stdin);
+               return;
+       case set_default:
+               printf("%s\n", def);
+               return;
+       default:
+               break;
+       }
+
+       switch (type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               printf("%s\n", def);
+               return;
+       default:
+               ;
+       }
+       switch (input_mode) {
+       case set_yes:
+               if (sym_tristate_within_range(sym, yes)) {
+                       line[0] = 'y';
+                       line[1] = '\n';
+                       line[2] = 0;
+                       break;
+               }
+       case set_mod:
+               if (type == S_TRISTATE) {
+                       if (sym_tristate_within_range(sym, mod)) {
+                               line[0] = 'm';
+                               line[1] = '\n';
+                               line[2] = 0;
+                               break;
+                       }
+               } else {
+                       if (sym_tristate_within_range(sym, yes)) {
+                               line[0] = 'y';
+                               line[1] = '\n';
+                               line[2] = 0;
+                               break;
+                       }
+               }
+       case set_no:
+               if (sym_tristate_within_range(sym, no)) {
+                       line[0] = 'n';
+                       line[1] = '\n';
+                       line[2] = 0;
+                       break;
+               }
+       case set_random:
+               do {
+                       val = (tristate)(random() % 3);
+               } while (!sym_tristate_within_range(sym, val));
+               switch (val) {
+               case no: line[0] = 'n'; break;
+               case mod: line[0] = 'm'; break;
+               case yes: line[0] = 'y'; break;
+               }
+               line[1] = '\n';
+               line[2] = 0;
+               break;
+       default:
+               break;
+       }
+       printf("%s", line);
+}
+
+int conf_string(struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       const char *def, *help;
+
+       while (1) {
+               printf("%*s%s ", indent - 1, "", menu->prompt->text);
+               printf("(%s) ", sym->name);
+               def = sym_get_string_value(sym);
+               if (sym_get_string_value(sym))
+                       printf("[%s] ", def);
+               conf_askvalue(sym, def);
+               switch (line[0]) {
+               case '\n':
+                       break;
+               case '?':
+                       /* print help */
+                       if (line[1] == '\n') {
+                               help = nohelp_text;
+                               if (menu->sym->help)
+                                       help = menu->sym->help;
+                               printf("\n%s\n", menu->sym->help);
+                               def = NULL;
+                               break;
+                       }
+               default:
+                       line[strlen(line)-1] = 0;
+                       def = line;
+               }
+               if (def && sym_set_string_value(sym, def))
+                       return 0;
+       }
+}
+
+static int conf_sym(struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       int type;
+       tristate oldval, newval;
+       const char *help;
+
+       while (1) {
+               printf("%*s%s ", indent - 1, "", menu->prompt->text);
+               if (sym->name)
+                       printf("(%s) ", sym->name);
+               type = sym_get_type(sym);
+               putchar('[');
+               oldval = sym_get_tristate_value(sym);
+               switch (oldval) {
+               case no:
+                       putchar('N');
+                       break;
+               case mod:
+                       putchar('M');
+                       break;
+               case yes:
+                       putchar('Y');
+                       break;
+               }
+               if (oldval != no && sym_tristate_within_range(sym, no))
+                       printf("/n");
+               if (oldval != mod && sym_tristate_within_range(sym, mod))
+                       printf("/m");
+               if (oldval != yes && sym_tristate_within_range(sym, yes))
+                       printf("/y");
+               if (sym->help)
+                       printf("/?");
+               printf("] ");
+               conf_askvalue(sym, sym_get_string_value(sym));
+               strip(line);
+
+               switch (line[0]) {
+               case 'n':
+               case 'N':
+                       newval = no;
+                       if (!line[1] || !strcmp(&line[1], "o"))
+                               break;
+                       continue;
+               case 'm':
+               case 'M':
+                       newval = mod;
+                       if (!line[1])
+                               break;
+                       continue;
+               case 'y':
+               case 'Y':
+                       newval = yes;
+                       if (!line[1] || !strcmp(&line[1], "es"))
+                               break;
+                       continue;
+               case 0:
+                       newval = oldval;
+                       break;
+               case '?':
+                       goto help;
+               default:
+                       continue;
+               }
+               if (sym_set_tristate_value(sym, newval))
+                       return 0;
+help:
+               help = nohelp_text;
+               if (sym->help)
+                       help = sym->help;
+               printf("\n%s\n", help);
+       }
+}
+
+static int conf_choice(struct menu *menu)
+{
+       struct symbol *sym, *def_sym;
+       struct menu *child;
+       int type;
+       bool is_new;
+
+       sym = menu->sym;
+       type = sym_get_type(sym);
+       is_new = !sym_has_value(sym);
+       if (sym_is_changable(sym)) {
+               conf_sym(menu);
+               sym_calc_value(sym);
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       return 1;
+               case mod:
+                       return 0;
+               case yes:
+                       break;
+               }
+       } else {
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       return 1;
+               case mod:
+                       printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+                       return 0;
+               case yes:
+                       break;
+               }
+       }
+
+       while (1) {
+               int cnt, def;
+
+               printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+               def_sym = sym_get_choice_value(sym);
+               cnt = def = 0;
+               line[0] = 0;
+               for (child = menu->list; child; child = child->next) {
+                       if (!menu_is_visible(child))
+                               continue;
+                       if (!child->sym) {
+                               printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+                               continue;
+                       }
+                       cnt++;
+                       if (child->sym == def_sym) {
+                               def = cnt;
+                               printf("%*c", indent, '>');
+                       } else
+                               printf("%*c", indent, ' ');
+                       printf(" %d. %s", cnt, menu_get_prompt(child));
+                       if (child->sym->name)
+                               printf(" (%s)", child->sym->name);
+                       if (!sym_has_value(child->sym))
+                               printf(" (NEW)");
+                       printf("\n");
+               }
+               printf("%*schoice", indent - 1, "");
+               if (cnt == 1) {
+                       printf("[1]: 1\n");
+                       goto conf_childs;
+               }
+               printf("[1-%d", cnt);
+               if (sym->help)
+                       printf("?");
+               printf("]: ");
+               switch (input_mode) {
+               case ask_new:
+               case ask_silent:
+                       if (!is_new) {
+                               cnt = def;
+                               printf("%d\n", cnt);
+                               break;
+                       }
+                       check_stdin();
+               case ask_all:
+                       fflush(stdout);
+                       fgets_check_stream(line, 128, stdin);
+                       strip(line);
+                       if (line[0] == '?') {
+                               printf("\n%s\n", menu->sym->help ?
+                                       menu->sym->help : nohelp_text);
+                               continue;
+                       }
+                       if (!line[0])
+                               cnt = def;
+                       else if (isdigit(line[0]))
+                               cnt = atoi(line);
+                       else
+                               continue;
+                       break;
+               case set_random:
+                       def = (random() % cnt) + 1;
+               case set_default:
+               case set_yes:
+               case set_mod:
+               case set_no:
+                       cnt = def;
+                       printf("%d\n", cnt);
+                       break;
+               }
+
+       conf_childs:
+               for (child = menu->list; child; child = child->next) {
+                       if (!child->sym || !menu_is_visible(child))
+                               continue;
+                       if (!--cnt)
+                               break;
+               }
+               if (!child)
+                       continue;
+               if (line[strlen(line) - 1] == '?') {
+                       printf("\n%s\n", child->sym->help ?
+                               child->sym->help : nohelp_text);
+                       continue;
+               }
+               sym_set_choice_value(sym, child->sym);
+               if (child->list) {
+                       indent += 2;
+                       conf(child->list);
+                       indent -= 2;
+               }
+               return 1;
+       }
+}
+
+static void conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       if (prop) {
+               const char *prompt;
+
+               switch (prop->type) {
+               case P_MENU:
+                       if (input_mode == ask_silent && rootEntry != menu) {
+                               check_conf(menu);
+                               return;
+                       }
+               case P_COMMENT:
+                       prompt = menu_get_prompt(menu);
+                       if (prompt)
+                               printf("%*c\n%*c %s\n%*c\n",
+                                       indent, '*',
+                                       indent, '*', prompt,
+                                       indent, '*');
+               default:
+                       ;
+               }
+       }
+
+       if (!sym)
+               goto conf_childs;
+
+       if (sym_is_choice(sym)) {
+               conf_choice(menu);
+               if (sym->curr.tri != mod)
+                       return;
+               goto conf_childs;
+       }
+
+       switch (sym->type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               conf_string(menu);
+               break;
+       default:
+               conf_sym(menu);
+               break;
+       }
+
+conf_childs:
+       if (sym)
+               indent += 2;
+       for (child = menu->list; child; child = child->next)
+               conf(child);
+       if (sym)
+               indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct menu *child;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       if (sym && !sym_has_value(sym)) {
+               if (sym_is_changable(sym) ||
+                   (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+                       if (!conf_cnt++)
+                               printf(_("*\n* Restart config...\n*\n"));
+                       rootEntry = menu_get_parent_menu(menu);
+                       conf(rootEntry);
+               }
+       }
+
+       for (child = menu->list; child; child = child->next)
+               check_conf(child);
+}
+
+int main(int ac, char **av)
+{
+       int i = 1;
+       const char *name;
+       struct stat tmpstat;
+
+       if (ac > i && av[i][0] == '-') {
+               switch (av[i++][1]) {
+               case 'o':
+                       input_mode = ask_new;
+                       break;
+               case 's':
+                       input_mode = ask_silent;
+                       valid_stdin = isatty(0) && isatty(1) && isatty(2);
+                       break;
+               case 'd':
+                       input_mode = set_default;
+                       break;
+               case 'D':
+                       input_mode = set_default;
+                       defconfig_file = av[i++];
+                       if (!defconfig_file) {
+                               printf(_("%s: No default config file specified\n"),
+                                       av[0]);
+                               exit(1);
+                       }
+                       break;
+               case 'n':
+                       input_mode = set_no;
+                       break;
+               case 'm':
+                       input_mode = set_mod;
+                       break;
+               case 'y':
+                       input_mode = set_yes;
+                       break;
+               case 'r':
+                       input_mode = set_random;
+                       srandom(time(NULL));
+                       break;
+               case 'h':
+               case '?':
+                       fprintf(stderr, "See README for usage info\n");
+                       exit(0);
+               }
+       }
+       name = av[i];
+       if (!name) {
+               printf(_("%s: Kconfig file missing\n"), av[0]);
+       }
+       conf_parse(name);
+       //zconfdump(stdout);
+       switch (input_mode) {
+       case set_default:
+               if (!defconfig_file)
+                       defconfig_file = conf_get_default_confname();
+               if (conf_read(defconfig_file)) {
+                       printf("***\n"
+                               "*** Can't find default configuration \"%s\"!\n"
+                               "***\n", defconfig_file);
+                       exit(1);
+               }
+               break;
+       case ask_silent:
+               if (stat(".config", &tmpstat)) {
+                       printf(_("***\n"
+                               "*** You have not yet configured your kernel!\n"
+                               "***\n"
+                               "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+                               "*** \"make menuconfig\" or \"make xconfig\").\n"
+                               "***\n"));
+                       exit(1);
+               }
+       case ask_all:
+       case ask_new:
+               conf_read(NULL);
+               break;
+       case set_no:
+       case set_mod:
+       case set_yes:
+       case set_random:
+               name = getenv("KCONFIG_ALLCONFIG");
+               if (name && !stat(name, &tmpstat)) {
+                       conf_read_simple(name);
+                       break;
+               }
+               switch (input_mode) {
+               case set_no:     name = "allno.config"; break;
+               case set_mod:    name = "allmod.config"; break;
+               case set_yes:    name = "allyes.config"; break;
+               case set_random: name = "allrandom.config"; break;
+               default: break;
+               }
+               if (!stat(name, &tmpstat))
+                       conf_read_simple(name);
+               else if (!stat("all.config", &tmpstat))
+                       conf_read_simple("all.config");
+               break;
+       default:
+               break;
+       }
+
+       if (input_mode != ask_silent) {
+               rootEntry = &rootmenu;
+               conf(&rootmenu);
+               if (input_mode == ask_all) {
+                       input_mode = ask_silent;
+                       valid_stdin = 1;
+               }
+       }
+       do {
+               conf_cnt = 0;
+               check_conf(&rootmenu);
+       } while (conf_cnt);
+       if (conf_write(NULL)) {
+               fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+               return 1;
+       }
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/confdata.c b/kitten/scripts/kconfig/confdata.c
new file mode 100644 (file)
index 0000000..dc330ce
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_def_filename[] = ".config";
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+const char *conf_confnames[] = {
+       ".config",
+       conf_defname,
+       NULL,
+};
+
+static void conf_warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       conf_warnings++;
+}
+
+static char *conf_expand_value(const char *in)
+{
+       struct symbol *sym;
+       const char *src;
+       static char res_value[SYMBOL_MAXLENGTH];
+       char *dst, name[SYMBOL_MAXLENGTH];
+
+       res_value[0] = 0;
+       dst = name;
+       while ((src = strchr(in, '$'))) {
+               strncat(res_value, in, src - in);
+               src++;
+               dst = name;
+               while (isalnum(*src) || *src == '_')
+                       *dst++ = *src++;
+               *dst = 0;
+               sym = sym_lookup(name, 0);
+               sym_calc_value(sym);
+               strcat(res_value, sym_get_string_value(sym));
+               in = src;
+       }
+       strcat(res_value, in);
+
+       return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+       struct stat buf;
+       static char fullname[PATH_MAX+1];
+       char *env, *name;
+
+       name = conf_expand_value(conf_defname);
+       env = getenv(SRCTREE);
+       if (env) {
+               sprintf(fullname, "%s/%s", env, name);
+               if (!stat(fullname, &buf))
+                       return fullname;
+       }
+       return name;
+}
+
+int conf_read_simple(const char *name)
+{
+       FILE *in = NULL;
+       char line[1024];
+       char *p, *p2;
+       struct symbol *sym;
+       int i;
+
+       if (name) {
+               in = zconf_fopen(name);
+       } else {
+               const char **names = conf_confnames;
+               while ((name = *names++)) {
+                       name = conf_expand_value(name);
+                       in = zconf_fopen(name);
+                       if (in) {
+                               printf(_("#\n"
+                                        "# using defaults found in %s\n"
+                                        "#\n"), name);
+                               break;
+                       }
+               }
+       }
+       if (!in)
+               return 1;
+
+       conf_filename = name;
+       conf_lineno = 0;
+       conf_warnings = 0;
+       conf_unsaved = 0;
+
+       for_all_symbols(i, sym) {
+               sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
+               if (sym_is_choice(sym))
+                       sym->flags &= ~SYMBOL_NEW;
+               sym->flags &= ~SYMBOL_VALID;
+               switch (sym->type) {
+               case S_INT:
+               case S_HEX:
+               case S_STRING:
+                       if (sym->user.val)
+                               free(sym->user.val);
+               default:
+                       sym->user.val = NULL;
+                       sym->user.tri = no;
+               }
+       }
+
+       while (fgets(line, sizeof(line), in)) {
+               conf_lineno++;
+               sym = NULL;
+               switch (line[0]) {
+               case '#':
+                       if (memcmp(line + 2, "CONFIG_", 7))
+                               continue;
+                       p = strchr(line + 9, ' ');
+                       if (!p)
+                               continue;
+                       *p++ = 0;
+                       if (strncmp(p, "is not set", 10))
+                               continue;
+                       sym = sym_find(line + 9);
+                       if (!sym) {
+                               conf_warning("trying to assign nonexistent symbol %s", line + 9);
+                               break;
+                       } else if (!(sym->flags & SYMBOL_NEW)) {
+                               conf_warning("trying to reassign symbol %s", sym->name);
+                               break;
+                       }
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               sym->user.tri = no;
+                               sym->flags &= ~SYMBOL_NEW;
+                               break;
+                       default:
+                               ;
+                       }
+                       break;
+               case 'C':
+                       if (memcmp(line, "CONFIG_", 7)) {
+                               conf_warning("unexpected data");
+                               continue;
+                       }
+                       p = strchr(line + 7, '=');
+                       if (!p)
+                               continue;
+                       *p++ = 0;
+                       p2 = strchr(p, '\n');
+                       if (p2)
+                               *p2 = 0;
+                       sym = sym_find(line + 7);
+                       if (!sym) {
+                               conf_warning("trying to assign nonexistent symbol %s", line + 7);
+                               break;
+                       } else if (!(sym->flags & SYMBOL_NEW)) {
+                               conf_warning("trying to reassign symbol %s", sym->name);
+                               break;
+                       }
+                       switch (sym->type) {
+                       case S_TRISTATE:
+                               if (p[0] == 'm') {
+                                       sym->user.tri = mod;
+                                       sym->flags &= ~SYMBOL_NEW;
+                                       break;
+                               }
+                       case S_BOOLEAN:
+                               if (p[0] == 'y') {
+                                       sym->user.tri = yes;
+                                       sym->flags &= ~SYMBOL_NEW;
+                                       break;
+                               }
+                               if (p[0] == 'n') {
+                                       sym->user.tri = no;
+                                       sym->flags &= ~SYMBOL_NEW;
+                                       break;
+                               }
+                               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                               break;
+                       case S_STRING:
+                               if (*p++ != '"')
+                                       break;
+                               for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+                                       if (*p2 == '"') {
+                                               *p2 = 0;
+                                               break;
+                                       }
+                                       memmove(p2, p2 + 1, strlen(p2));
+                               }
+                               if (!p2) {
+                                       conf_warning("invalid string found");
+                                       continue;
+                               }
+                       case S_INT:
+                       case S_HEX:
+                               if (sym_string_valid(sym, p)) {
+                                       sym->user.val = strdup(p);
+                                       sym->flags &= ~SYMBOL_NEW;
+                               } else {
+                                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                                       continue;
+                               }
+                               break;
+                       default:
+                               ;
+                       }
+                       break;
+               case '\n':
+                       break;
+               default:
+                       conf_warning("unexpected data");
+                       continue;
+               }
+               if (sym && sym_is_choice_value(sym)) {
+                       struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+                       switch (sym->user.tri) {
+                       case no:
+                               break;
+                       case mod:
+                               if (cs->user.tri == yes) {
+                                       conf_warning("%s creates inconsistent choice state", sym->name);
+                                       cs->flags |= SYMBOL_NEW;
+                               }
+                               break;
+                       case yes:
+                               if (cs->user.tri != no) {
+                                       conf_warning("%s creates inconsistent choice state", sym->name);
+                                       cs->flags |= SYMBOL_NEW;
+                               } else
+                                       cs->user.val = sym;
+                               break;
+                       }
+                       cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
+               }
+       }
+       fclose(in);
+
+       if (modules_sym)
+               sym_calc_value(modules_sym);
+       return 0;
+}
+
+int conf_read(const char *name)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct expr *e;
+       int i;
+
+       if (conf_read_simple(name))
+               return 1;
+
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+                       goto sym_ok;
+               if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+                       /* check that calculated value agrees with saved value */
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               if (sym->user.tri != sym_get_tristate_value(sym))
+                                       break;
+                               if (!sym_is_choice(sym))
+                                       goto sym_ok;
+                       default:
+                               if (!strcmp(sym->curr.val, sym->user.val))
+                                       goto sym_ok;
+                               break;
+                       }
+               } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+                       /* no previous value and not saved */
+                       goto sym_ok;
+               conf_unsaved++;
+               /* maybe print value in verbose mode... */
+       sym_ok:
+               if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+                       if (sym->visible == no)
+                               sym->flags |= SYMBOL_NEW;
+                       switch (sym->type) {
+                       case S_STRING:
+                       case S_INT:
+                       case S_HEX:
+                               if (!sym_string_within_range(sym, sym->user.val)) {
+                                       sym->flags |= SYMBOL_NEW;
+                                       sym->flags &= ~SYMBOL_VALID;
+                               }
+                       default:
+                               break;
+                       }
+               }
+               if (!sym_is_choice(sym))
+                       continue;
+               prop = sym_get_choice_prop(sym);
+               for (e = prop->expr; e; e = e->left.expr)
+                       if (e->right.sym->visible != no)
+                               sym->flags |= e->right.sym->flags & SYMBOL_NEW;
+       }
+
+       sym_change_count = conf_warnings || conf_unsaved;
+
+       return 0;
+}
+
+int conf_write(const char *name)
+{
+       FILE *out, *out_h;
+       struct symbol *sym;
+       struct menu *menu;
+       const char *basename;
+       char dirname[128], tmpname[128], newname[128];
+       int type, l;
+       const char *str;
+       time_t now;
+       int use_timestamp = 1;
+       char *env;
+
+       dirname[0] = 0;
+       if (name && name[0]) {
+               struct stat st;
+               char *slash;
+
+               if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+                       strcpy(dirname, name);
+                       strcat(dirname, "/");
+                       basename = conf_def_filename;
+               } else if ((slash = strrchr(name, '/'))) {
+                       int size = slash - name + 1;
+                       memcpy(dirname, name, size);
+                       dirname[size] = 0;
+                       if (slash[1])
+                               basename = slash + 1;
+                       else
+                               basename = conf_def_filename;
+               } else
+                       basename = name;
+       } else
+               basename = conf_def_filename;
+
+       sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
+       out = fopen(newname, "w");
+       if (!out)
+               return 1;
+       out_h = NULL;
+       if (!name) {
+               out_h = fopen(".tmpconfig.h", "w");
+               if (!out_h)
+                       return 1;
+               file_write_dep(NULL);
+       }
+       sym = sym_lookup("KERNELVERSION", 0);
+       sym_calc_value(sym);
+       time(&now);
+       env = getenv("KCONFIG_NOTIMESTAMP");
+       if (env && *env)
+               use_timestamp = 0;
+
+       fprintf(out, _("#\n"
+                      "# Automatically generated make config: don't edit\n"
+                      "# LWK kernel version: %s\n"
+                      "%s%s"
+                      "#\n"),
+                    sym_get_string_value(sym),
+                    use_timestamp ? "# " : "",
+                    use_timestamp ? ctime(&now) : "");
+       if (out_h)
+               fprintf(out_h, "/*\n"
+                              " * Automatically generated C config: don't edit\n"
+                              " * LWK kernel version: %s\n"
+                              "%s%s"
+                              " */\n"
+                              "#define AUTOCONF_INCLUDED\n",
+                              sym_get_string_value(sym),
+                              use_timestamp ? " * " : "",
+                              use_timestamp ? ctime(&now) : "");
+
+       if (!sym_change_count)
+               sym_clear_all_valid();
+
+       menu = rootmenu.list;
+       while (menu) {
+               sym = menu->sym;
+               if (!sym) {
+                       if (!menu_is_visible(menu))
+                               goto next;
+                       str = menu_get_prompt(menu);
+                       fprintf(out, "\n"
+                                    "#\n"
+                                    "# %s\n"
+                                    "#\n", str);
+                       if (out_h)
+                               fprintf(out_h, "\n"
+                                              "/*\n"
+                                              " * %s\n"
+                                              " */\n", str);
+               } else if (!(sym->flags & SYMBOL_CHOICE)) {
+                       sym_calc_value(sym);
+                       if (!(sym->flags & SYMBOL_WRITE))
+                               goto next;
+                       sym->flags &= ~SYMBOL_WRITE;
+                       type = sym->type;
+                       if (type == S_TRISTATE) {
+                               sym_calc_value(modules_sym);
+                               if (modules_sym->curr.tri == no)
+                                       type = S_BOOLEAN;
+                       }
+                       switch (type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               switch (sym_get_tristate_value(sym)) {
+                               case no:
+                                       fprintf(out, "# CONFIG_%s is not set\n", sym->name);
+                                       if (out_h)
+                                               fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
+                                       break;
+                               case mod:
+                                       fprintf(out, "CONFIG_%s=m\n", sym->name);
+                                       if (out_h)
+                                               fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
+                                       break;
+                               case yes:
+                                       fprintf(out, "CONFIG_%s=y\n", sym->name);
+                                       if (out_h)
+                                               fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
+                                       break;
+                               }
+                               break;
+                       case S_STRING:
+                               // fix me
+                               str = sym_get_string_value(sym);
+                               fprintf(out, "CONFIG_%s=\"", sym->name);
+                               if (out_h)
+                                       fprintf(out_h, "#define CONFIG_%s \"", sym->name);
+                               do {
+                                       l = strcspn(str, "\"\\");
+                                       if (l) {
+                                               fwrite(str, l, 1, out);
+                                               if (out_h)
+                                                       fwrite(str, l, 1, out_h);
+                                       }
+                                       str += l;
+                                       while (*str == '\\' || *str == '"') {
+                                               fprintf(out, "\\%c", *str);
+                                               if (out_h)
+                                                       fprintf(out_h, "\\%c", *str);
+                                               str++;
+                                       }
+                               } while (*str);
+                               fputs("\"\n", out);
+                               if (out_h)
+                                       fputs("\"\n", out_h);
+                               break;
+                       case S_HEX:
+                               str = sym_get_string_value(sym);
+                               if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+                                       fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+                                       if (out_h)
+                                               fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
+                                       break;
+                               }
+                       case S_INT:
+                               str = sym_get_string_value(sym);
+                               fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+                               if (out_h)
+                                       fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
+                               break;
+                       }
+               }
+
+       next:
+               if (menu->list) {
+                       menu = menu->list;
+                       continue;
+               }
+               if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+       fclose(out);
+       if (out_h) {
+               fclose(out_h);
+               rename(".tmpconfig.h", "include/lwk/autoconf.h");
+       }
+       if (!name || basename != conf_def_filename) {
+               if (!name)
+                       name = conf_def_filename;
+               sprintf(tmpname, "%s.old", name);
+               rename(name, tmpname);
+       }
+       sprintf(tmpname, "%s%s", dirname, basename);
+       if (rename(newname, tmpname))
+               return 1;
+
+       sym_change_count = 0;
+
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/expr.c b/kitten/scripts/kconfig/expr.c
new file mode 100644 (file)
index 0000000..30e4f9d
--- /dev/null
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR     0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = E_SYMBOL;
+       e->left.sym = sym;
+       return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.expr = ce;
+       return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.expr = e1;
+       e->right.expr = e2;
+       return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.sym = s1;
+       e->right.sym = s2;
+       return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+       if (!e1)
+               return e2;
+       return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+       if (!e1)
+               return e2;
+       return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(struct expr *org)
+{
+       struct expr *e;
+
+       if (!org)
+               return NULL;
+
+       e = malloc(sizeof(*org));
+       memcpy(e, org, sizeof(*org));
+       switch (org->type) {
+       case E_SYMBOL:
+               e->left = org->left;
+               break;
+       case E_NOT:
+               e->left.expr = expr_copy(org->left.expr);
+               break;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               e->left.sym = org->left.sym;
+               e->right.sym = org->right.sym;
+               break;
+       case E_AND:
+       case E_OR:
+       case E_CHOICE:
+               e->left.expr = expr_copy(org->left.expr);
+               e->right.expr = expr_copy(org->right.expr);
+               break;
+       default:
+               printf("can't copy type %d\n", e->type);
+               free(e);
+               e = NULL;
+               break;
+       }
+
+       return e;
+}
+
+void expr_free(struct expr *e)
+{
+       if (!e)
+               return;
+
+       switch (e->type) {
+       case E_SYMBOL:
+               break;
+       case E_NOT:
+               expr_free(e->left.expr);
+               return;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               break;
+       case E_OR:
+       case E_AND:
+               expr_free(e->left.expr);
+               expr_free(e->right.expr);
+               break;
+       default:
+               printf("how to free type %d?\n", e->type);
+               break;
+       }
+       free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+       if (e1->type == type) {
+               __expr_eliminate_eq(type, &e1->left.expr, &e2);
+               __expr_eliminate_eq(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               __expr_eliminate_eq(type, &e1, &e2->left.expr);
+               __expr_eliminate_eq(type, &e1, &e2->right.expr);
+               return;
+       }
+       if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+           e1->left.sym == e2->left.sym && (e1->left.sym->flags & (SYMBOL_YES|SYMBOL_NO)))
+               return;
+       if (!expr_eq(e1, e2))
+               return;
+       trans_count++;
+       expr_free(e1); expr_free(e2);
+       switch (type) {
+       case E_OR:
+               e1 = expr_alloc_symbol(&symbol_no);
+               e2 = expr_alloc_symbol(&symbol_no);
+               break;
+       case E_AND:
+               e1 = expr_alloc_symbol(&symbol_yes);
+               e2 = expr_alloc_symbol(&symbol_yes);
+               break;
+       default:
+               ;
+       }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+       if (!e1 || !e2)
+               return;
+       switch (e1->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e1->type, ep1, ep2);
+       default:
+               ;
+       }
+       if (e1->type != e2->type) switch (e2->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e2->type, ep1, ep2);
+       default:
+               ;
+       }
+       e1 = expr_eliminate_yn(e1);
+       e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+       int res, old_count;
+
+       if (e1->type != e2->type)
+               return 0;
+       switch (e1->type) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+               return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+       case E_SYMBOL:
+               return e1->left.sym == e2->left.sym;
+       case E_NOT:
+               return expr_eq(e1->left.expr, e2->left.expr);
+       case E_AND:
+       case E_OR:
+               e1 = expr_copy(e1);
+               e2 = expr_copy(e2);
+               old_count = trans_count;
+               expr_eliminate_eq(&e1, &e2);
+               res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+                      e1->left.sym == e2->left.sym);
+               expr_free(e1);
+               expr_free(e2);
+               trans_count = old_count;
+               return res;
+       case E_CHOICE:
+       case E_RANGE:
+       case E_NONE:
+               /* panic */;
+       }
+
+       if (DEBUG_EXPR) {
+               expr_fprint(e1, stdout);
+               printf(" = ");
+               expr_fprint(e2, stdout);
+               printf(" ?\n");
+       }
+
+       return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+       struct expr *tmp;
+
+       if (e) switch (e->type) {
+       case E_AND:
+               e->left.expr = expr_eliminate_yn(e->left.expr);
+               e->right.expr = expr_eliminate_yn(e->right.expr);
+               if (e->left.expr->type == E_SYMBOL) {
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               e->right.expr = NULL;
+                               return e;
+                       } else if (e->left.expr->left.sym == &symbol_yes) {
+                               free(e->left.expr);
+                               tmp = e->right.expr;
+                               *e = *(e->right.expr);
+                               free(tmp);
+                               return e;
+                       }
+               }
+               if (e->right.expr->type == E_SYMBOL) {
+                       if (e->right.expr->left.sym == &symbol_no) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               e->right.expr = NULL;
+                               return e;
+                       } else if (e->right.expr->left.sym == &symbol_yes) {
+                               free(e->right.expr);
+                               tmp = e->left.expr;
+                               *e = *(e->left.expr);
+                               free(tmp);
+                               return e;
+                       }
+               }
+               break;
+       case E_OR:
+               e->left.expr = expr_eliminate_yn(e->left.expr);
+               e->right.expr = expr_eliminate_yn(e->right.expr);
+               if (e->left.expr->type == E_SYMBOL) {
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               free(e->left.expr);
+                               tmp = e->right.expr;
+                               *e = *(e->right.expr);
+                               free(tmp);
+                               return e;
+                       } else if (e->left.expr->left.sym == &symbol_yes) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               e->right.expr = NULL;
+                               return e;
+                       }
+               }
+               if (e->right.expr->type == E_SYMBOL) {
+                       if (e->right.expr->left.sym == &symbol_no) {
+                               free(e->right.expr);
+                               tmp = e->left.expr;
+                               *e = *(e->left.expr);
+                               free(tmp);
+                               return e;
+                       } else if (e->right.expr->left.sym == &symbol_yes) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               e->right.expr = NULL;
+                               return e;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_AND:
+       case E_OR:
+       case E_NOT:
+               e->left.expr = expr_trans_bool(e->left.expr);
+               e->right.expr = expr_trans_bool(e->right.expr);
+               break;
+       case E_UNEQUAL:
+               // FOO!=n -> FOO
+               if (e->left.sym->type == S_TRISTATE) {
+                       if (e->right.sym == &symbol_no) {
+                               e->type = E_SYMBOL;
+                               e->right.sym = NULL;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+       struct expr *tmp;
+       struct symbol *sym1, *sym2;
+
+       if (expr_eq(e1, e2))
+               return expr_copy(e1);
+       if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+               return NULL;
+       if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+               return NULL;
+       if (e1->type == E_NOT) {
+               tmp = e1->left.expr;
+               if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+                       return NULL;
+               sym1 = tmp->left.sym;
+       } else
+               sym1 = e1->left.sym;
+       if (e2->type == E_NOT) {
+               if (e2->left.expr->type != E_SYMBOL)
+                       return NULL;
+               sym2 = e2->left.expr->left.sym;
+       } else
+               sym2 = e2->left.sym;
+       if (sym1 != sym2)
+               return NULL;
+       if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+               return NULL;
+       if (sym1->type == S_TRISTATE) {
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+                    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+                       // (a='y') || (a='m') -> (a!='n')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+               }
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+                    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+                       // (a='y') || (a='n') -> (a!='m')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+               }
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+                    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+                       // (a='m') || (a='n') -> (a!='y')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+               }
+       }
+       if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+               if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+                   (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+                       return expr_alloc_symbol(&symbol_yes);
+       }
+
+       if (DEBUG_EXPR) {
+               printf("optimize (");
+               expr_fprint(e1, stdout);
+               printf(") || (");
+               expr_fprint(e2, stdout);
+               printf(")?\n");
+       }
+       return NULL;
+}
+
+struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+       struct expr *tmp;
+       struct symbol *sym1, *sym2;
+
+       if (expr_eq(e1, e2))
+               return expr_copy(e1);
+       if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+               return NULL;
+       if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+               return NULL;
+       if (e1->type == E_NOT) {
+               tmp = e1->left.expr;
+               if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+                       return NULL;
+               sym1 = tmp->left.sym;
+       } else
+               sym1 = e1->left.sym;
+       if (e2->type == E_NOT) {
+               if (e2->left.expr->type != E_SYMBOL)
+                       return NULL;
+               sym2 = e2->left.expr->left.sym;
+       } else
+               sym2 = e2->left.sym;
+       if (sym1 != sym2)
+               return NULL;
+       if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+               return NULL;
+
+       if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+           (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+               // (a) && (a='y') -> (a='y')
+               return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+       if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+           (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+               // (a) && (a!='n') -> (a)
+               return expr_alloc_symbol(sym1);
+
+       if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+           (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+               // (a) && (a!='m') -> (a='y')
+               return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+       if (sym1->type == S_TRISTATE) {
+               if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+                       sym2 = e1->right.sym;
+                       if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+                               return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+                                                            : expr_alloc_symbol(&symbol_no);
+               }
+               if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+                       sym2 = e2->right.sym;
+                       if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+                               return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+                                                            : expr_alloc_symbol(&symbol_no);
+               }
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+                           (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+                       // (a!='y') && (a!='n') -> (a='m')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+                           (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+                       // (a!='y') && (a!='m') -> (a='n')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+                           (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+                       // (a!='m') && (a!='n') -> (a='m')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+               if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+                   (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+                   (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+                   (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+                       return NULL;
+       }
+
+       if (DEBUG_EXPR) {
+               printf("optimize (");
+               expr_fprint(e1, stdout);
+               printf(") && (");
+               expr_fprint(e2, stdout);
+               printf(")?\n");
+       }
+       return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       struct expr *tmp;
+
+       if (e1->type == type) {
+               expr_eliminate_dups1(type, &e1->left.expr, &e2);
+               expr_eliminate_dups1(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_eliminate_dups1(type, &e1, &e2->left.expr);
+               expr_eliminate_dups1(type, &e1, &e2->right.expr);
+               return;
+       }
+       if (e1 == e2)
+               return;
+
+       switch (e1->type) {
+       case E_OR: case E_AND:
+               expr_eliminate_dups1(e1->type, &e1, &e1);
+       default:
+               ;
+       }
+
+       switch (type) {
+       case E_OR:
+               tmp = expr_join_or(e1, e2);
+               if (tmp) {
+                       expr_free(e1); expr_free(e2);
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       e2 = tmp;
+                       trans_count++;
+               }
+               break;
+       case E_AND:
+               tmp = expr_join_and(e1, e2);
+               if (tmp) {
+                       expr_free(e1); expr_free(e2);
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       e2 = tmp;
+                       trans_count++;
+               }
+               break;
+       default:
+               ;
+       }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       struct expr *tmp, *tmp1, *tmp2;
+
+       if (e1->type == type) {
+               expr_eliminate_dups2(type, &e1->left.expr, &e2);
+               expr_eliminate_dups2(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_eliminate_dups2(type, &e1, &e2->left.expr);
+               expr_eliminate_dups2(type, &e1, &e2->right.expr);
+       }
+       if (e1 == e2)
+               return;
+
+       switch (e1->type) {
+       case E_OR:
+               expr_eliminate_dups2(e1->type, &e1, &e1);
+               // (FOO || BAR) && (!FOO && !BAR) -> n
+               tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+               tmp2 = expr_copy(e2);
+               tmp = expr_extract_eq_and(&tmp1, &tmp2);
+               if (expr_is_yes(tmp1)) {
+                       expr_free(e1);
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       trans_count++;
+               }
+               expr_free(tmp2);
+               expr_free(tmp1);
+               expr_free(tmp);
+               break;
+       case E_AND:
+               expr_eliminate_dups2(e1->type, &e1, &e1);
+               // (FOO && BAR) || (!FOO || !BAR) -> y
+               tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+               tmp2 = expr_copy(e2);
+               tmp = expr_extract_eq_or(&tmp1, &tmp2);
+               if (expr_is_no(tmp1)) {
+                       expr_free(e1);
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       trans_count++;
+               }
+               expr_free(tmp2);
+               expr_free(tmp1);
+               expr_free(tmp);
+               break;
+       default:
+               ;
+       }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+       int oldcount;
+       if (!e)
+               return e;
+
+       oldcount = trans_count;
+       while (1) {
+               trans_count = 0;
+               switch (e->type) {
+               case E_OR: case E_AND:
+                       expr_eliminate_dups1(e->type, &e, &e);
+                       expr_eliminate_dups2(e->type, &e, &e);
+               default:
+                       ;
+               }
+               if (!trans_count)
+                       break;
+               e = expr_eliminate_yn(e);
+       }
+       trans_count = oldcount;
+       return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+       struct expr *tmp;
+
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+       case E_SYMBOL:
+       case E_CHOICE:
+               break;
+       default:
+               e->left.expr = expr_transform(e->left.expr);
+               e->right.expr = expr_transform(e->right.expr);
+       }
+
+       switch (e->type) {
+       case E_EQUAL:
+               if (e->left.sym->type != S_BOOLEAN)
+                       break;
+               if (e->right.sym == &symbol_no) {
+                       e->type = E_NOT;
+                       e->left.expr = expr_alloc_symbol(e->left.sym);
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_mod) {
+                       printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+                       e->type = E_SYMBOL;
+                       e->left.sym = &symbol_no;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_yes) {
+                       e->type = E_SYMBOL;
+                       e->right.sym = NULL;
+                       break;
+               }
+               break;
+       case E_UNEQUAL:
+               if (e->left.sym->type != S_BOOLEAN)
+                       break;
+               if (e->right.sym == &symbol_no) {
+                       e->type = E_SYMBOL;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_mod) {
+                       printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+                       e->type = E_SYMBOL;
+                       e->left.sym = &symbol_yes;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_yes) {
+                       e->type = E_NOT;
+                       e->left.expr = expr_alloc_symbol(e->left.sym);
+                       e->right.sym = NULL;
+                       break;
+               }
+               break;
+       case E_NOT:
+               switch (e->left.expr->type) {
+               case E_NOT:
+                       // !!a -> a
+                       tmp = e->left.expr->left.expr;
+                       free(e->left.expr);
+                       free(e);
+                       e = tmp;
+                       e = expr_transform(e);
+                       break;
+               case E_EQUAL:
+               case E_UNEQUAL:
+                       // !a='x' -> a!='x'
+                       tmp = e->left.expr;
+                       free(e);
+                       e = tmp;
+                       e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+                       break;
+               case E_OR:
+                       // !(a || b) -> !a && !b
+                       tmp = e->left.expr;
+                       e->type = E_AND;
+                       e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+                       tmp->type = E_NOT;
+                       tmp->right.expr = NULL;
+                       e = expr_transform(e);
+                       break;
+               case E_AND:
+                       // !(a && b) -> !a || !b
+                       tmp = e->left.expr;
+                       e->type = E_OR;
+                       e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+                       tmp->type = E_NOT;
+                       tmp->right.expr = NULL;
+                       e = expr_transform(e);
+                       break;
+               case E_SYMBOL:
+                       if (e->left.expr->left.sym == &symbol_yes) {
+                               // !'y' -> 'n'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               break;
+                       }
+                       if (e->left.expr->left.sym == &symbol_mod) {
+                               // !'m' -> 'm'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_mod;
+                               break;
+                       }
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               // !'n' -> 'y'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               break;
+                       }
+                       break;
+               default:
+                       ;
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+       if (!dep)
+               return 0;
+
+       switch (dep->type) {
+       case E_AND:
+       case E_OR:
+               return expr_contains_symbol(dep->left.expr, sym) ||
+                      expr_contains_symbol(dep->right.expr, sym);
+       case E_SYMBOL:
+               return dep->left.sym == sym;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               return dep->left.sym == sym ||
+                      dep->right.sym == sym;
+       case E_NOT:
+               return expr_contains_symbol(dep->left.expr, sym);
+       default:
+               ;
+       }
+       return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+       if (!dep)
+               return false;
+
+       switch (dep->type) {
+       case E_AND:
+               return expr_depends_symbol(dep->left.expr, sym) ||
+                      expr_depends_symbol(dep->right.expr, sym);
+       case E_SYMBOL:
+               return dep->left.sym == sym;
+       case E_EQUAL:
+               if (dep->left.sym == sym) {
+                       if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+                               return true;
+               }
+               break;
+       case E_UNEQUAL:
+               if (dep->left.sym == sym) {
+                       if (dep->right.sym == &symbol_no)
+                               return true;
+               }
+               break;
+       default:
+               ;
+       }
+       return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+       struct expr *tmp = NULL;
+       expr_extract_eq(E_AND, &tmp, ep1, ep2);
+       if (tmp) {
+               *ep1 = expr_eliminate_yn(*ep1);
+               *ep2 = expr_eliminate_yn(*ep2);
+       }
+       return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+       struct expr *tmp = NULL;
+       expr_extract_eq(E_OR, &tmp, ep1, ep2);
+       if (tmp) {
+               *ep1 = expr_eliminate_yn(*ep1);
+               *ep2 = expr_eliminate_yn(*ep2);
+       }
+       return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       if (e1->type == type) {
+               expr_extract_eq(type, ep, &e1->left.expr, &e2);
+               expr_extract_eq(type, ep, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_extract_eq(type, ep, ep1, &e2->left.expr);
+               expr_extract_eq(type, ep, ep1, &e2->right.expr);
+               return;
+       }
+       if (expr_eq(e1, e2)) {
+               *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+               expr_free(e2);
+               if (type == E_AND) {
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       e2 = expr_alloc_symbol(&symbol_yes);
+               } else if (type == E_OR) {
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       e2 = expr_alloc_symbol(&symbol_no);
+               }
+       }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+       struct expr *e1, *e2;
+
+       if (!e) {
+               e = expr_alloc_symbol(sym);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       }
+       switch (e->type) {
+       case E_AND:
+               e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+               e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+               if (sym == &symbol_yes)
+                       e = expr_alloc_two(E_AND, e1, e2);
+               if (sym == &symbol_no)
+                       e = expr_alloc_two(E_OR, e1, e2);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       case E_OR:
+               e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+               e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+               if (sym == &symbol_yes)
+                       e = expr_alloc_two(E_OR, e1, e2);
+               if (sym == &symbol_no)
+                       e = expr_alloc_two(E_AND, e1, e2);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       case E_NOT:
+               return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+       case E_UNEQUAL:
+       case E_EQUAL:
+               if (type == E_EQUAL) {
+                       if (sym == &symbol_yes)
+                               return expr_copy(e);
+                       if (sym == &symbol_mod)
+                               return expr_alloc_symbol(&symbol_no);
+                       if (sym == &symbol_no)
+                               return expr_alloc_one(E_NOT, expr_copy(e));
+               } else {
+                       if (sym == &symbol_yes)
+                               return expr_alloc_one(E_NOT, expr_copy(e));
+                       if (sym == &symbol_mod)
+                               return expr_alloc_symbol(&symbol_yes);
+                       if (sym == &symbol_no)
+                               return expr_copy(e);
+               }
+               break;
+       case E_SYMBOL:
+               return expr_alloc_comp(type, e->left.sym, sym);
+       case E_CHOICE:
+       case E_RANGE:
+       case E_NONE:
+               /* panic */;
+       }
+       return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+       tristate val1, val2;
+       const char *str1, *str2;
+
+       if (!e)
+               return yes;
+
+       switch (e->type) {
+       case E_SYMBOL:
+               sym_calc_value(e->left.sym);
+               return e->left.sym->curr.tri;
+       case E_AND:
+               val1 = expr_calc_value(e->left.expr);
+               val2 = expr_calc_value(e->right.expr);
+               return E_AND(val1, val2);
+       case E_OR:
+               val1 = expr_calc_value(e->left.expr);
+               val2 = expr_calc_value(e->right.expr);
+               return E_OR(val1, val2);
+       case E_NOT:
+               val1 = expr_calc_value(e->left.expr);
+               return E_NOT(val1);
+       case E_EQUAL:
+               sym_calc_value(e->left.sym);
+               sym_calc_value(e->right.sym);
+               str1 = sym_get_string_value(e->left.sym);
+               str2 = sym_get_string_value(e->right.sym);
+               return !strcmp(str1, str2) ? yes : no;
+       case E_UNEQUAL:
+               sym_calc_value(e->left.sym);
+               sym_calc_value(e->right.sym);
+               str1 = sym_get_string_value(e->left.sym);
+               str2 = sym_get_string_value(e->right.sym);
+               return !strcmp(str1, str2) ? no : yes;
+       default:
+               printf("expr_calc_value: %d?\n", e->type);
+               return no;
+       }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+       return 1;
+#else
+       if (t1 == t2)
+               return 0;
+       switch (t1) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+               if (t2 == E_NOT)
+                       return 1;
+       case E_NOT:
+               if (t2 == E_AND)
+                       return 1;
+       case E_AND:
+               if (t2 == E_OR)
+                       return 1;
+       case E_OR:
+               if (t2 == E_CHOICE)
+                       return 1;
+       case E_CHOICE:
+               if (t2 == 0)
+                       return 1;
+       default:
+               return -1;
+       }
+       printf("[%dgt%d?]", t1, t2);
+       return 0;
+#endif
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken)
+{
+       if (!e) {
+               fn(data, "y");
+               return;
+       }
+
+       if (expr_compare_type(prevtoken, e->type) > 0)
+               fn(data, "(");
+       switch (e->type) {
+       case E_SYMBOL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym->name);
+               else
+                       fn(data, "<choice>");
+               break;
+       case E_NOT:
+               fn(data, "!");
+               expr_print(e->left.expr, fn, data, E_NOT);
+               break;
+       case E_EQUAL:
+               fn(data, e->left.sym->name);
+               fn(data, "=");
+               fn(data, e->right.sym->name);
+               break;
+       case E_UNEQUAL:
+               fn(data, e->left.sym->name);
+               fn(data, "!=");
+               fn(data, e->right.sym->name);
+               break;
+       case E_OR:
+               expr_print(e->left.expr, fn, data, E_OR);
+               fn(data, " || ");
+               expr_print(e->right.expr, fn, data, E_OR);
+               break;
+       case E_AND:
+               expr_print(e->left.expr, fn, data, E_AND);
+               fn(data, " && ");
+               expr_print(e->right.expr, fn, data, E_AND);
+               break;
+       case E_CHOICE:
+               fn(data, e->right.sym->name);
+               if (e->left.expr) {
+                       fn(data, " ^ ");
+                       expr_print(e->left.expr, fn, data, E_CHOICE);
+               }
+               break;
+       case E_RANGE:
+               fn(data, "[");
+               fn(data, e->left.sym->name);
+               fn(data, " ");
+               fn(data, e->right.sym->name);
+               fn(data, "]");
+               break;
+       default:
+         {
+               char buf[32];
+               sprintf(buf, "<unknown type %d>", e->type);
+               fn(data, buf);
+               break;
+         }
+       }
+       if (expr_compare_type(prevtoken, e->type) > 0)
+               fn(data, ")");
+}
+
+static void expr_print_file_helper(void *data, const char *str)
+{
+       fwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+       expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, const char *str)
+{
+       str_append((struct gstr*)data, str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+       expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/kitten/scripts/kconfig/expr.h b/kitten/scripts/kconfig/expr.h
new file mode 100644 (file)
index 0000000..1b36ef1
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+       struct file *next;
+       struct file *parent;
+       char *name;
+       int lineno;
+       int flags;
+};
+
+#define FILE_BUSY              0x0001
+#define FILE_SCANNED           0x0002
+#define FILE_PRINTED           0x0004
+
+typedef enum tristate {
+       no, mod, yes
+} tristate;
+
+enum expr_type {
+       E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+       struct expr *expr;
+       struct symbol *sym;
+};
+
+struct expr {
+       enum expr_type type;
+       union expr_data left, right;
+};
+
+#define E_OR(dep1, dep2)       (((dep1)>(dep2))?(dep1):(dep2))
+#define E_AND(dep1, dep2)      (((dep1)<(dep2))?(dep1):(dep2))
+#define E_NOT(dep)             (2-(dep))
+
+struct expr_value {
+       struct expr *expr;
+       tristate tri;
+};
+
+struct symbol_value {
+       void *val;
+       tristate tri;
+};
+
+enum symbol_type {
+       S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+struct symbol {
+       struct symbol *next;
+       char *name;
+       char *help;
+       enum symbol_type type;
+       struct symbol_value curr, user;
+       tristate visible;
+       int flags;
+       struct property *prop;
+       struct expr *dep, *dep2;
+       struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_YES             0x0001
+#define SYMBOL_MOD             0x0002
+#define SYMBOL_NO              0x0004
+#define SYMBOL_CONST           0x0007
+#define SYMBOL_CHECK           0x0008
+#define SYMBOL_CHOICE          0x0010
+#define SYMBOL_CHOICEVAL       0x0020
+#define SYMBOL_PRINTED         0x0040
+#define SYMBOL_VALID           0x0080
+#define SYMBOL_OPTIONAL                0x0100
+#define SYMBOL_WRITE           0x0200
+#define SYMBOL_CHANGED         0x0400
+#define SYMBOL_NEW             0x0800
+#define SYMBOL_AUTO            0x1000
+#define SYMBOL_CHECKED         0x2000
+#define SYMBOL_WARNED          0x8000
+
+#define SYMBOL_MAXLENGTH       256
+#define SYMBOL_HASHSIZE                257
+#define SYMBOL_HASHMASK                0xff
+
+enum prop_type {
+       P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
+};
+
+struct property {
+       struct property *next;
+       struct symbol *sym;
+       enum prop_type type;
+       const char *text;
+       struct expr_value visible;
+       struct expr *expr;
+       struct menu *menu;
+       struct file *file;
+       int lineno;
+};
+
+#define for_all_properties(sym, st, tok) \
+       for (st = sym->prop; st; st = st->next) \
+               if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+       for (st = sym->prop; st; st = st->next) \
+               if (st->text)
+
+struct menu {
+       struct menu *next;
+       struct menu *parent;
+       struct menu *list;
+       struct symbol *sym;
+       struct property *prompt;
+       struct expr *dep;
+       unsigned int flags;
+       //char *help;
+       struct file *file;
+       int lineno;
+       void *data;
+};
+
+#define MENU_CHANGED           0x0001
+#define MENU_ROOT              0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+       return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+       return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/kitten/scripts/kconfig/gconf.c b/kitten/scripts/kconfig/gconf.c
new file mode 100644 (file)
index 0000000..8495362
--- /dev/null
@@ -0,0 +1,1645 @@
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+
+//#define DEBUG
+
+enum {
+       SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean show_all = FALSE;
+static gboolean show_debug = FALSE;
+static gboolean resizeable = FALSE;
+
+static gboolean config_changed = FALSE;
+
+static char nohelp_text[] =
+    N_("Sorry, no help available for this option yet.\n");
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL;     // left  frame
+GtkWidget *tree2_w = NULL;     // right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+       COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+       COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+       COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+       COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+
+
+/* Helping/Debugging Functions */
+
+
+const char *dbg_print_stype(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val == S_UNKNOWN)
+               strcpy(buf, "unknown");
+       if (val == S_BOOLEAN)
+               strcpy(buf, "boolean");
+       if (val == S_TRISTATE)
+               strcpy(buf, "tristate");
+       if (val == S_INT)
+               strcpy(buf, "int");
+       if (val == S_HEX)
+               strcpy(buf, "hex");
+       if (val == S_STRING)
+               strcpy(buf, "string");
+       if (val == S_OTHER)
+               strcpy(buf, "other");
+
+#ifdef DEBUG
+       printf("%s", buf);
+#endif
+
+       return buf;
+}
+
+const char *dbg_print_flags(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val & SYMBOL_YES)
+               strcat(buf, "yes/");
+       if (val & SYMBOL_MOD)
+               strcat(buf, "mod/");
+       if (val & SYMBOL_NO)
+               strcat(buf, "no/");
+       if (val & SYMBOL_CONST)
+               strcat(buf, "const/");
+       if (val & SYMBOL_CHECK)
+               strcat(buf, "check/");
+       if (val & SYMBOL_CHOICE)
+               strcat(buf, "choice/");
+       if (val & SYMBOL_CHOICEVAL)
+               strcat(buf, "choiceval/");
+       if (val & SYMBOL_PRINTED)
+               strcat(buf, "printed/");
+       if (val & SYMBOL_VALID)
+               strcat(buf, "valid/");
+       if (val & SYMBOL_OPTIONAL)
+               strcat(buf, "optional/");
+       if (val & SYMBOL_WRITE)
+               strcat(buf, "write/");
+       if (val & SYMBOL_CHANGED)
+               strcat(buf, "changed/");
+       if (val & SYMBOL_NEW)
+               strcat(buf, "new/");
+       if (val & SYMBOL_AUTO)
+               strcat(buf, "auto/");
+
+       buf[strlen(buf) - 1] = '\0';
+#ifdef DEBUG
+       printf("%s", buf);
+#endif
+
+       return buf;
+}
+
+const char *dbg_print_ptype(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val == P_UNKNOWN)
+               strcpy(buf, "unknown");
+       if (val == P_PROMPT)
+               strcpy(buf, "prompt");
+       if (val == P_COMMENT)
+               strcpy(buf, "comment");
+       if (val == P_MENU)
+               strcpy(buf, "menu");
+       if (val == P_DEFAULT)
+               strcpy(buf, "default");
+       if (val == P_CHOICE)
+               strcpy(buf, "choice");
+
+#ifdef DEBUG
+       printf("%s", buf);
+#endif
+
+       return buf;
+}
+
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+                        GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+       GdkPixmap *pixmap;
+       GdkBitmap *mask;
+       GtkToolButton *button;
+       GtkWidget *image;
+
+       pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+                                             &style->bg[GTK_STATE_NORMAL],
+                                             xpm);
+
+       button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+       image = gtk_image_new_from_pixmap(pixmap, mask);
+       gtk_widget_show(image);
+       gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+       GladeXML *xml;
+       GtkWidget *widget;
+       GtkTextBuffer *txtbuf;
+       char title[256];
+       GtkStyle *style;
+
+       xml = glade_xml_new(glade_file, "window1", NULL);
+       if (!xml)
+               g_error(_("GUI loading failed !\n"));
+       glade_xml_signal_autoconnect(xml);
+
+       main_wnd = glade_xml_get_widget(xml, "window1");
+       hpaned = glade_xml_get_widget(xml, "hpaned1");
+       vpaned = glade_xml_get_widget(xml, "vpaned1");
+       tree1_w = glade_xml_get_widget(xml, "treeview1");
+       tree2_w = glade_xml_get_widget(xml, "treeview2");
+       text_w = glade_xml_get_widget(xml, "textview3");
+
+       back_btn = glade_xml_get_widget(xml, "button1");
+       gtk_widget_set_sensitive(back_btn, FALSE);
+
+       widget = glade_xml_get_widget(xml, "show_name1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_name);
+
+       widget = glade_xml_get_widget(xml, "show_range1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_range);
+
+       widget = glade_xml_get_widget(xml, "show_data1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_value);
+
+       style = gtk_widget_get_style(main_wnd);
+       widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0  /* Use stock Gtk icons instead */
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button1", (gchar **) xpm_back);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button2", (gchar **) xpm_load);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button3", (gchar **) xpm_save);
+#endif
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button4", (gchar **) xpm_single_view);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button5", (gchar **) xpm_split_view);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button6", (gchar **) xpm_tree_view);
+
+#if 0
+       switch (view_mode) {
+       case SINGLE_VIEW:
+               widget = glade_xml_get_widget(xml, "button4");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       case SPLIT_VIEW:
+               widget = glade_xml_get_widget(xml, "button5");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       case FULL_VIEW:
+               widget = glade_xml_get_widget(xml, "button6");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       }
+#endif
+       txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+                                         "foreground", "red",
+                                         "weight", PANGO_WEIGHT_BOLD,
+                                         NULL);
+       tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+                                         /*"style", PANGO_STYLE_OBLIQUE, */
+                                         NULL);
+
+       sprintf(title, _("LWK Kernel v%s Configuration"),
+               getenv("KERNELVERSION"));
+       gtk_window_set_title(GTK_WINDOW(main_wnd), title);
+
+       gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+       gint i;
+
+       tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_POINTER, GDK_TYPE_COLOR,
+                                         G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                         G_TYPE_BOOLEAN);
+       model2 = GTK_TREE_MODEL(tree2);
+
+       for (parents[0] = NULL, i = 1; i < 256; i++)
+               parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+       tree1 = gtk_tree_store_new(COL_NUMBER,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_POINTER, GDK_TYPE_COLOR,
+                                  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+                                  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                  G_TYPE_BOOLEAN);
+       model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *sel;
+       GtkTreeViewColumn *column;
+
+       gtk_tree_view_set_model(view, model1);
+       gtk_tree_view_set_headers_visible(view, TRUE);
+       gtk_tree_view_set_rules_hint(view, FALSE);
+
+       column = gtk_tree_view_column_new();
+       gtk_tree_view_append_column(view, column);
+       gtk_tree_view_column_set_title(column, _("Options"));
+
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "active", COL_BTNACT,
+                                           "inconsistent", COL_BTNINC,
+                                           "visible", COL_BTNVIS,
+                                           "radio", COL_BTNRAD, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "text", COL_OPTION,
+                                           "foreground-gdk",
+                                           COL_COLOR, NULL);
+
+       sel = gtk_tree_view_get_selection(view);
+       gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+       gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+                           const gchar * path_string,
+                           const gchar * new_text, gpointer user_data);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+                            gchar * arg1, gpointer user_data);
+
+void init_right_tree(void)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *sel;
+       GtkTreeViewColumn *column;
+       gint i;
+
+       gtk_tree_view_set_model(view, model2);
+       gtk_tree_view_set_headers_visible(view, TRUE);
+       gtk_tree_view_set_rules_hint(view, FALSE);
+
+       column = gtk_tree_view_column_new();
+       gtk_tree_view_append_column(view, column);
+       gtk_tree_view_column_set_title(column, _("Options"));
+
+       renderer = gtk_cell_renderer_pixbuf_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "pixbuf", COL_PIXBUF,
+                                           "visible", COL_PIXVIS, NULL);
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "active", COL_BTNACT,
+                                           "inconsistent", COL_BTNINC,
+                                           "visible", COL_BTNVIS,
+                                           "radio", COL_BTNRAD, NULL);
+       /*g_signal_connect(G_OBJECT(renderer), "toggled",
+          G_CALLBACK(renderer_toggled), NULL); */
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "text", COL_OPTION,
+                                           "foreground-gdk",
+                                           COL_COLOR, NULL);
+
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   _("Name"), renderer,
+                                                   "text", COL_NAME,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "N", renderer,
+                                                   "text", COL_NO,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "M", renderer,
+                                                   "text", COL_MOD,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "Y", renderer,
+                                                   "text", COL_YES,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   _("Value"), renderer,
+                                                   "text", COL_VALUE,
+                                                   "editable",
+                                                   COL_EDIT,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       g_signal_connect(G_OBJECT(renderer), "edited",
+                        G_CALLBACK(renderer_edited), NULL);
+
+       column = gtk_tree_view_get_column(view, COL_NAME);
+       gtk_tree_view_column_set_visible(column, show_name);
+       column = gtk_tree_view_get_column(view, COL_NO);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_MOD);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_YES);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_VALUE);
+       gtk_tree_view_column_set_visible(column, show_value);
+
+       if (resizeable) {
+               for (i = 0; i < COL_VALUE; i++) {
+                       column = gtk_tree_view_get_column(view, i);
+                       gtk_tree_view_column_set_resizable(column, TRUE);
+               }
+       }
+
+       sel = gtk_tree_view_get_selection(view);
+       gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       const char *prompt = menu_get_prompt(menu);
+       gchar *name;
+       const char *help = _(nohelp_text);
+
+       if (!menu->sym)
+               help = "";
+       else if (menu->sym->help)
+               help = _(menu->sym->help);
+
+       if (menu->sym && menu->sym->name)
+               name = g_strdup_printf(_(menu->sym->name));
+       else
+               name = g_strdup("");
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       gtk_text_buffer_get_bounds(buffer, &start, &end);
+       gtk_text_buffer_delete(buffer, &start, &end);
+       gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
+                                        NULL);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       const char *msg = message;
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       gtk_text_buffer_get_bounds(buffer, &start, &end);
+       gtk_text_buffer_delete(buffer, &start, &end);
+       gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+                                        NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+                                gpointer user_data)
+{
+       GtkWidget *dialog, *label;
+       gint result;
+
+       if (config_changed == FALSE)
+               return FALSE;
+
+       dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+                                            GTK_WINDOW(main_wnd),
+                                            (GtkDialogFlags)
+                                            (GTK_DIALOG_MODAL |
+                                             GTK_DIALOG_DESTROY_WITH_PARENT),
+                                            GTK_STOCK_OK,
+                                            GTK_RESPONSE_YES,
+                                            GTK_STOCK_NO,
+                                            GTK_RESPONSE_NO,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL, NULL);
+       gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+                                       GTK_RESPONSE_CANCEL);
+
+       label = gtk_label_new(_("\nSave configuration ?\n"));
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+       gtk_widget_show(label);
+
+       result = gtk_dialog_run(GTK_DIALOG(dialog));
+       switch (result) {
+       case GTK_RESPONSE_YES:
+               on_save1_activate(NULL, NULL);
+               return FALSE;
+       case GTK_RESPONSE_NO:
+               return FALSE;
+       case GTK_RESPONSE_CANCEL:
+       case GTK_RESPONSE_DELETE_EVENT:
+       default:
+               gtk_widget_destroy(dialog);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+       gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+                       GtkRequisition * requisition, gpointer user_data)
+{
+       static gint old_h;
+       gint w, h;
+
+       if (widget->window == NULL)
+               gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+       else
+               gdk_window_get_size(widget->window, &w, &h);
+
+       if (h == old_h)
+               return;
+       old_h = h;
+
+       gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+       const gchar *fn;
+
+       fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+                                            (user_data));
+
+       if (conf_read(fn))
+               text_insert_msg(_("Error"), _("Unable to load configuration !"));
+       else
+               display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *fs;
+
+       fs = gtk_file_selection_new(_("Load file..."));
+       g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+                        "clicked",
+                        G_CALLBACK(load_filename), (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->ok_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->cancel_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       gtk_widget_show(fs);
+}
+
+
+void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       if (conf_write(NULL))
+               text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+       config_changed = FALSE;
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+       const gchar *fn;
+
+       fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+                                            (user_data));
+
+       if (conf_write(fn))
+               text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+       gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *fs;
+
+       fs = gtk_file_selection_new(_("Save file as..."));
+       g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+                        "clicked",
+                        G_CALLBACK(store_filename), (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->ok_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->cancel_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       if (!on_window1_delete_event(NULL, NULL, NULL))
+               gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
+
+       gtk_tree_store_clear(tree2);
+       display_tree(&rootmenu);        // instead of update_tree to speed-up
+}
+
+
+void
+on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       update_tree(&rootmenu, NULL);
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *intro_text = _(
+           "Welcome to gkc, the GTK+ graphical kernel configuration tool\n"
+           "for LWK.\n"
+           "For each option, a blank box indicates the feature is disabled, a\n"
+           "check indicates it is enabled, and a dot indicates that it is to\n"
+           "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
+           "\n"
+           "If you do not see an option (e.g., a device driver) that you\n"
+           "believe should be present, try turning on Show All Options\n"
+           "under the Options menu.\n"
+           "Although there is no cross reference yet to help you figure out\n"
+           "what other options must be enabled to support the option you\n"
+           "are interested in, you can still view the help of a grayed-out\n"
+           "option.\n"
+           "\n"
+           "Toggling Show Debug Info under the Options menu will show \n"
+           "the dependencies, which you can then match by examining other options.");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, intro_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *about_text =
+           _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+             "Based on the source code from Roman Zippel.\n");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, about_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *license_text =
+           _("gkc is released under the terms of the GNU GPL v2.\n"
+             "For more information, please see the source code or\n"
+             "visit http://www.fsf.org/licenses/licenses.html\n");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, license_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+       enum prop_type ptype;
+
+       current = current->parent;
+       ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+       if (ptype != P_MENU)
+               current = current->parent;
+       display_tree_part();
+
+       if (current == &rootmenu)
+               gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+       on_load1_activate(NULL, user_data);
+}
+
+
+void on_save_clicked(GtkButton * button, gpointer user_data)
+{
+       on_save1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+       view_mode = SINGLE_VIEW;
+       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+       gtk_widget_hide(tree1_w);
+       current = &rootmenu;
+       display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+       gint w, h;
+       view_mode = SPLIT_VIEW;
+       gtk_widget_show(tree1_w);
+       gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+       gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       display_list();
+
+       /* Disable back btn, like in full mode. */
+       gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+       view_mode = FULL_VIEW;
+       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+       gtk_widget_hide(tree1_w);
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       display_tree(&rootmenu);
+       gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+       gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+                           const gchar * path_string,
+                           const gchar * new_text, gpointer user_data)
+{
+       GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+       GtkTreeIter iter;
+       const char *old_def, *new_def;
+       struct menu *menu;
+       struct symbol *sym;
+
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return;
+
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+       sym = menu->sym;
+
+       gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+       new_def = new_text;
+
+       sym_set_string_value(sym, new_def);
+
+       config_changed = TRUE;
+       update_tree(&rootmenu, NULL);
+
+       gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+       struct symbol *sym = menu->sym;
+       tristate oldval, newval;
+
+       if (!sym)
+               return;
+
+       if (col == COL_NO)
+               newval = no;
+       else if (col == COL_MOD)
+               newval = mod;
+       else if (col == COL_YES)
+               newval = yes;
+       else
+               return;
+
+       switch (sym_get_type(sym)) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldval = sym_get_tristate_value(sym);
+               if (!sym_tristate_within_range(sym, newval))
+                       newval = yes;
+               sym_set_tristate_value(sym, newval);
+               config_changed = TRUE;
+               if (view_mode == FULL_VIEW)
+                       update_tree(&rootmenu, NULL);
+               else if (view_mode == SPLIT_VIEW) {
+                       update_tree(browsed, NULL);
+                       display_list();
+               }
+               else if (view_mode == SINGLE_VIEW)
+                       display_tree_part();    //fixme: keep exp/coll
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+       default:
+               break;
+       }
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+       if (!menu->sym)
+               return;
+
+       sym_toggle_tristate_value(menu->sym);
+       if (view_mode == FULL_VIEW)
+               update_tree(&rootmenu, NULL);
+       else if (view_mode == SPLIT_VIEW) {
+               update_tree(browsed, NULL);
+               display_list();
+       }
+       else if (view_mode == SINGLE_VIEW)
+               display_tree_part();    //fixme: keep exp/coll
+}
+
+static void renderer_toggled(GtkCellRendererToggle * cell,
+                            gchar * path_string, gpointer user_data)
+{
+       GtkTreePath *path, *sel_path = NULL;
+       GtkTreeIter iter, sel_iter;
+       GtkTreeSelection *sel;
+       struct menu *menu;
+
+       path = gtk_tree_path_new_from_string(path_string);
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return;
+
+       sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+       if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+               sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+       if (!sel_path)
+               goto out1;
+       if (gtk_tree_path_compare(path, sel_path))
+               goto out2;
+
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+       toggle_sym_value(menu);
+
+      out2:
+       gtk_tree_path_free(sel_path);
+      out1:
+       gtk_tree_path_free(path);
+}
+
+static gint column2index(GtkTreeViewColumn * column)
+{
+       gint i;
+
+       for (i = 0; i < COL_NUMBER; i++) {
+               GtkTreeViewColumn *col;
+
+               col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+               if (col == column)
+                       return i;
+       }
+
+       return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+                               GdkEventButton * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+       gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+       gint tx = (gint) event->x;
+       gint ty = (gint) event->y;
+       gint cx, cy;
+
+       gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+                                     &cy);
+#else
+       gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+       if (path == NULL)
+               return FALSE;
+
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return FALSE;
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+       col = column2index(column);
+       if (event->type == GDK_2BUTTON_PRESS) {
+               enum prop_type ptype;
+               ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+               if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+                       // goes down into menu
+                       current = menu;
+                       display_tree_part();
+                       gtk_widget_set_sensitive(back_btn, TRUE);
+               } else if ((col == COL_OPTION)) {
+                       toggle_sym_value(menu);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               }
+       } else {
+               if (col == COL_VALUE) {
+                       toggle_sym_value(menu);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               } else if (col == COL_NO || col == COL_MOD
+                          || col == COL_YES) {
+                       change_sym_value(menu, col);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               }
+       }
+
+       return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+                            GdkEventKey * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+       gint col;
+
+       gtk_tree_view_get_cursor(view, &path, &column);
+       if (path == NULL)
+               return FALSE;
+
+       if (event->keyval == GDK_space) {
+               if (gtk_tree_view_row_expanded(view, path))
+                       gtk_tree_view_collapse_row(view, path);
+               else
+                       gtk_tree_view_expand_row(view, path, FALSE);
+               return TRUE;
+       }
+       if (event->keyval == GDK_KP_Enter) {
+       }
+       if (widget == tree1_w)
+               return FALSE;
+
+       gtk_tree_model_get_iter(model2, &iter, path);
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+       if (!strcasecmp(event->string, "n"))
+               col = COL_NO;
+       else if (!strcasecmp(event->string, "m"))
+               col = COL_MOD;
+       else if (!strcasecmp(event->string, "y"))
+               col = COL_YES;
+       else
+               col = -1;
+       change_sym_value(menu, col);
+
+       return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       struct menu *menu;
+
+       selection = gtk_tree_view_get_selection(treeview);
+       if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+               gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+               text_insert_help(menu);
+       }
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+                               GdkEventButton * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+
+       gint tx = (gint) event->x;
+       gint ty = (gint) event->y;
+       gint cx, cy;
+
+       gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+                                     &cy);
+       if (path == NULL)
+               return FALSE;
+
+       gtk_tree_model_get_iter(model1, &iter, path);
+       gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+       if (event->type == GDK_2BUTTON_PRESS) {
+               toggle_sym_value(menu);
+               current = menu;
+               display_tree_part();
+       } else {
+               browsed = menu;
+               display_tree_part();
+       }
+
+       gtk_widget_realize(tree2_w);
+       gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+       gtk_widget_grab_focus(tree2_w);
+
+       return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+       static gchar *row[COL_NUMBER];
+       struct symbol *sym = menu->sym;
+       const char *def;
+       int stype;
+       tristate val;
+       enum prop_type ptype;
+       int i;
+
+       for (i = COL_OPTION; i <= COL_COLOR; i++)
+               g_free(row[i]);
+       bzero(row, sizeof(row));
+
+       row[COL_OPTION] =
+           g_strdup_printf("%s %s", menu_get_prompt(menu),
+                           sym ? (sym->
+                                  flags & SYMBOL_NEW ? "(NEW)" : "") :
+                           "");
+
+       if (show_all && !menu_is_visible(menu))
+               row[COL_COLOR] = g_strdup("DarkGray");
+       else
+               row[COL_COLOR] = g_strdup("Black");
+
+       ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       switch (ptype) {
+       case P_MENU:
+               row[COL_PIXBUF] = (gchar *) xpm_menu;
+               if (view_mode == SINGLE_VIEW)
+                       row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       case P_COMMENT:
+               row[COL_PIXBUF] = (gchar *) xpm_void;
+               row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       default:
+               row[COL_PIXBUF] = (gchar *) xpm_void;
+               row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+               break;
+       }
+
+       if (!sym)
+               return row;
+       row[COL_NAME] = g_strdup(sym->name);
+
+       sym_calc_value(sym);
+       sym->flags &= ~SYMBOL_CHANGED;
+
+       if (sym_is_choice(sym)) {       // parse childs for getting final value
+               struct menu *child;
+               struct symbol *def_sym = sym_get_choice_value(sym);
+               struct menu *def_menu = NULL;
+
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+               for (child = menu->list; child; child = child->next) {
+                       if (menu_is_visible(child)
+                           && child->sym == def_sym)
+                               def_menu = child;
+               }
+
+               if (def_menu)
+                       row[COL_VALUE] =
+                           g_strdup(menu_get_prompt(def_menu));
+       }
+       if (sym->flags & SYMBOL_CHOICEVAL)
+               row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+       stype = sym_get_type(sym);
+       switch (stype) {
+       case S_BOOLEAN:
+               if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+                       row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+               if (sym_is_choice(sym))
+                       break;
+       case S_TRISTATE:
+               val = sym_get_tristate_value(sym);
+               switch (val) {
+               case no:
+                       row[COL_NO] = g_strdup("N");
+                       row[COL_VALUE] = g_strdup("N");
+                       row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+                       row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+                       break;
+               case mod:
+                       row[COL_MOD] = g_strdup("M");
+                       row[COL_VALUE] = g_strdup("M");
+                       row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+                       break;
+               case yes:
+                       row[COL_YES] = g_strdup("Y");
+                       row[COL_VALUE] = g_strdup("Y");
+                       row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+                       row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+                       break;
+               }
+
+               if (val != no && sym_tristate_within_range(sym, no))
+                       row[COL_NO] = g_strdup("_");
+               if (val != mod && sym_tristate_within_range(sym, mod))
+                       row[COL_MOD] = g_strdup("_");
+               if (val != yes && sym_tristate_within_range(sym, yes))
+                       row[COL_YES] = g_strdup("_");
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               def = sym_get_string_value(sym);
+               row[COL_VALUE] = g_strdup(def);
+               row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       }
+
+       return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+       GdkColor color;
+       gboolean success;
+       GdkPixbuf *pix;
+
+       pix = gdk_pixbuf_new_from_xpm_data((const char **)
+                                          row[COL_PIXBUF]);
+
+       gdk_color_parse(row[COL_COLOR], &color);
+       gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+                                 FALSE, FALSE, &success);
+
+       gtk_tree_store_set(tree, node,
+                          COL_OPTION, row[COL_OPTION],
+                          COL_NAME, row[COL_NAME],
+                          COL_NO, row[COL_NO],
+                          COL_MOD, row[COL_MOD],
+                          COL_YES, row[COL_YES],
+                          COL_VALUE, row[COL_VALUE],
+                          COL_MENU, (gpointer) menu,
+                          COL_COLOR, &color,
+                          COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+                          COL_PIXBUF, pix,
+                          COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+                          COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+                          COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+                          COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+                          COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+                          -1);
+
+       g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+       GtkTreeIter *parent = parents[indent - 1];
+       GtkTreeIter *node = parents[indent];
+
+       gtk_tree_store_append(tree, node, parent);
+       set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+                                   struct menu *tofind)
+{
+       GtkTreeIter iter;
+       GtkTreeIter *child = &iter;
+       gboolean valid;
+       GtkTreeIter *ret;
+
+       valid = gtk_tree_model_iter_children(model2, child, parent);
+       while (valid) {
+               struct menu *menu;
+
+               gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+               if (menu == tofind) {
+                       memcpy(&found, child, sizeof(GtkTreeIter));
+                       return &found;
+               }
+
+               ret = gtktree_iter_find_node(child, tofind);
+               if (ret)
+                       return ret;
+
+               valid = gtk_tree_model_iter_next(model2, child);
+       }
+
+       return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+       struct menu *child1;
+       GtkTreeIter iter, tmp;
+       GtkTreeIter *child2 = &iter;
+       gboolean valid;
+       GtkTreeIter *sibling;
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *menu1, *menu2;
+
+       if (src == &rootmenu)
+               indent = 1;
+
+       valid = gtk_tree_model_iter_children(model2, child2, dst);
+       for (child1 = src->list; child1; child1 = child1->next) {
+
+               prop = child1->prompt;
+               sym = child1->sym;
+
+             reparse:
+               menu1 = child1;
+               if (valid)
+                       gtk_tree_model_get(model2, child2, COL_MENU,
+                                          &menu2, -1);
+               else
+                       menu2 = NULL;   // force adding of a first child
+
+#ifdef DEBUG
+               printf("%*c%s | %s\n", indent, ' ',
+                      menu1 ? menu_get_prompt(menu1) : "nil",
+                      menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+               if (!menu_is_visible(child1) && !show_all) {    // remove node
+                       if (gtktree_iter_find_node(dst, menu1) != NULL) {
+                               memcpy(&tmp, child2, sizeof(GtkTreeIter));
+                               valid = gtk_tree_model_iter_next(model2,
+                                                                child2);
+                               gtk_tree_store_remove(tree2, &tmp);
+                               if (!valid)
+                                       return; // next parent
+                               else
+                                       goto reparse;   // next child
+                       } else
+                               continue;
+               }
+
+               if (menu1 != menu2) {
+                       if (gtktree_iter_find_node(dst, menu1) == NULL) {       // add node
+                               if (!valid && !menu2)
+                                       sibling = NULL;
+                               else
+                                       sibling = child2;
+                               gtk_tree_store_insert_before(tree2,
+                                                            child2,
+                                                            dst, sibling);
+                               set_node(child2, menu1, fill_row(menu1));
+                               if (menu2 == NULL)
+                                       valid = TRUE;
+                       } else {        // remove node
+                               memcpy(&tmp, child2, sizeof(GtkTreeIter));
+                               valid = gtk_tree_model_iter_next(model2,
+                                                                child2);
+                               gtk_tree_store_remove(tree2, &tmp);
+                               if (!valid)
+                                       return; // next parent
+                               else
+                                       goto reparse;   // next child
+                       }
+               } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+                       set_node(child2, menu1, fill_row(menu1));
+               }
+
+               indent++;
+               update_tree(child1, child2);
+               indent--;
+
+               valid = gtk_tree_model_iter_next(model2, child2);
+       }
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+       enum prop_type ptype;
+
+       if (menu == &rootmenu) {
+               indent = 1;
+               current = &rootmenu;
+       }
+
+       for (child = menu->list; child; child = child->next) {
+               prop = child->prompt;
+               sym = child->sym;
+               ptype = prop ? prop->type : P_UNKNOWN;
+
+               if (sym)
+                       sym->flags &= ~SYMBOL_CHANGED;
+
+               if ((view_mode == SPLIT_VIEW)
+                   && !(child->flags & MENU_ROOT) && (tree == tree1))
+                       continue;
+
+               if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+                   && (tree == tree2))
+                       continue;
+
+               if (menu_is_visible(child) || show_all)
+                       place_node(child, fill_row(child));
+#ifdef DEBUG
+               printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+               printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+               dbg_print_ptype(ptype);
+               printf(" | ");
+               if (sym) {
+                       dbg_print_stype(sym->type);
+                       printf(" | ");
+                       dbg_print_flags(sym->flags);
+                       printf("\n");
+               } else
+                       printf("\n");
+#endif
+               if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+                   && (tree == tree2))
+                       continue;
+/*
+                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+                   || (view_mode == FULL_VIEW)
+                   || (view_mode == SPLIT_VIEW))*/
+               if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+                   || (view_mode == FULL_VIEW)
+                   || (view_mode == SPLIT_VIEW)) {
+                       indent++;
+                       display_tree(child);
+                       indent--;
+               }
+       }
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       if (view_mode == SINGLE_VIEW)
+               display_tree(current);
+       else if (view_mode == SPLIT_VIEW)
+               display_tree(browsed);
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+       if (tree1)
+               gtk_tree_store_clear(tree1);
+
+       tree = tree1;
+       display_tree(&rootmenu);
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+       tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+       struct menu *child;
+       static int menu_cnt = 0;
+
+       menu->flags |= MENU_ROOT;
+       for (child = menu->list; child; child = child->next) {
+               if (child->prompt && child->prompt->type == P_MENU) {
+                       menu_cnt++;
+                       fixup_rootmenu(child);
+                       menu_cnt--;
+               } else if (!menu_cnt)
+                       fixup_rootmenu(child);
+       }
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+       const char *name;
+       char *env;
+       gchar *glade_file;
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       bind_textdomain_codeset(PACKAGE, "UTF-8");
+       textdomain(PACKAGE);
+
+       /* GTK stuffs */
+       gtk_set_locale();
+       gtk_init(&ac, &av);
+       glade_init();
+
+       //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+       //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+       /* Determine GUI path */
+       env = getenv(SRCTREE);
+       if (env)
+               glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
+       else if (av[0][0] == '/')
+               glade_file = g_strconcat(av[0], ".glade", NULL);
+       else
+               glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+       /* Load the interface and connect signals */
+       init_main_window(glade_file);
+       init_tree_model();
+       init_left_tree();
+       init_right_tree();
+
+       /* Conf stuffs */
+       if (ac > 1 && av[1][0] == '-') {
+               switch (av[1][1]) {
+               case 'a':
+                       //showAll = 1;
+                       break;
+               case 'h':
+               case '?':
+                       printf("%s <config>\n", av[0]);
+                       exit(0);
+               }
+               name = av[2];
+       } else
+               name = av[1];
+
+       conf_parse(name);
+       fixup_rootmenu(&rootmenu);
+       conf_read(NULL);
+
+       switch (view_mode) {
+       case SINGLE_VIEW:
+               display_tree_part();
+               break;
+       case SPLIT_VIEW:
+               display_list();
+               break;
+       case FULL_VIEW:
+               display_tree(&rootmenu);
+               break;
+       }
+
+       gtk_main();
+
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/gconf.glade b/kitten/scripts/kconfig/gconf.glade
new file mode 100644 (file)
index 0000000..f8744ed
--- /dev/null
@@ -0,0 +1,648 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Gtk Kernel Configurator</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="default_width">640</property>
+  <property name="default_height">480</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+  <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+  <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkMenuBar" id="menubar1">
+         <property name="visible">True</property>
+
+         <child>
+           <widget class="GtkMenuItem" id="file1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_File</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="file1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="load1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Load a config file</property>
+                     <property name="label" translatable="yes">_Load</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_load1_activate"/>
+                     <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image39">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-open</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Save the config in .config</property>
+                     <property name="label" translatable="yes">_Save</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_save1_activate"/>
+                     <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image40">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-save</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save_as1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Save the config in a file</property>
+                     <property name="label" translatable="yes">Save _as</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_save_as1_activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image41">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-save-as</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separator1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="quit1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_Quit</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_quit1_activate"/>
+                     <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image42">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-quit</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="options1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Options</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="options1_menu">
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_name1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show name</property>
+                     <property name="label" translatable="yes">Show _name</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_name1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_range1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+                     <property name="label" translatable="yes">Show _range</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_range1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_data1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show value of the option</property>
+                     <property name="label" translatable="yes">Show _data</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_data1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separator2">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_all_options1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show all options</property>
+                     <property name="label" translatable="yes">Show all _options</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_all_options1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_debug_info1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show masked options</property>
+                     <property name="label" translatable="yes">Show _debug info</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_debug_info1_activate"/>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="help1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Help</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="help1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="introduction1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_Introduction</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+                     <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image43">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-dialog-question</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="about1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_About</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+                     <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image44">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-properties</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="license1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_License</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image45">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-justify-fill</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHandleBox" id="handlebox1">
+         <property name="visible">True</property>
+         <property name="shadow_type">GTK_SHADOW_OUT</property>
+         <property name="handle_position">GTK_POS_LEFT</property>
+         <property name="snap_edge">GTK_POS_TOP</property>
+
+         <child>
+           <widget class="GtkToolbar" id="toolbar1">
+             <property name="visible">True</property>
+             <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+             <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+             <property name="tooltips">True</property>
+             <property name="show_arrow">True</property>
+
+             <child>
+               <widget class="GtkToolButton" id="button1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+                 <property name="label" translatable="yes">Back</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-undo</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_back_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem1">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button2">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Load a config file</property>
+                 <property name="label" translatable="yes">Load</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-open</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_load_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button3">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Save a config file</property>
+                 <property name="label" translatable="yes">Save</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-save</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_save_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem2">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator2">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button4">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Single view</property>
+                 <property name="label" translatable="yes">Single</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button5">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Split view</property>
+                 <property name="label" translatable="yes">Split</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button6">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Full view</property>
+                 <property name="label" translatable="yes">Full</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem3">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator3">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button7">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+                 <property name="label" translatable="yes">Collapse</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-remove</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_collapse_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button8">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+                 <property name="label" translatable="yes">Expand</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-add</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_expand_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHPaned" id="hpaned1">
+         <property name="width_request">1</property>
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="position">0</property>
+
+         <child>
+           <widget class="GtkScrolledWindow" id="scrolledwindow1">
+             <property name="visible">True</property>
+             <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="shadow_type">GTK_SHADOW_IN</property>
+             <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+             <child>
+               <widget class="GtkTreeView" id="treeview1">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="headers_visible">True</property>
+                 <property name="rules_hint">False</property>
+                 <property name="reorderable">False</property>
+                 <property name="enable_search">True</property>
+                 <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
+                 <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
+                 <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
+               </widget>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkVPaned" id="vpaned1">
+             <property name="visible">True</property>
+             <property name="can_focus">True</property>
+             <property name="position">0</property>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow2">
+                 <property name="visible">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTreeView" id="treeview2">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="has_focus">True</property>
+                     <property name="headers_visible">True</property>
+                     <property name="rules_hint">False</property>
+                     <property name="reorderable">False</property>
+                     <property name="enable_search">True</property>
+                     <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
+                     <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
+                     <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="shrink">True</property>
+                 <property name="resize">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow3">
+                 <property name="visible">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTextView" id="textview3">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">False</property>
+                     <property name="overwrite">False</property>
+                     <property name="accepts_tab">True</property>
+                     <property name="justification">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap_mode">GTK_WRAP_WORD</property>
+                     <property name="cursor_visible">True</property>
+                     <property name="pixels_above_lines">0</property>
+                     <property name="pixels_below_lines">0</property>
+                     <property name="pixels_inside_wrap">0</property>
+                     <property name="left_margin">0</property>
+                     <property name="right_margin">0</property>
+                     <property name="indent">0</property>
+                     <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="shrink">True</property>
+                 <property name="resize">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/kitten/scripts/kconfig/images.c b/kitten/scripts/kconfig/images.c
new file mode 100644 (file)
index 0000000..d4f84bd
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .      . . ",
+" .     .. . ",
+" . .  ..  . ",
+" . ....   . ",
+" .  ..    . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" . ..     . ",
+" . ....   . ",
+" . ...... . ",
+" . ...... . ",
+" . ....   . ",
+" . ..     . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .......... ",
+" ..  ...... ",
+" ..    .... ",
+" ..      .. ",
+" ..      .. ",
+" ..    .... ",
+" ..  ...... ",
+" .......... ",
+" .......... ",
+"            "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .     .. . ",
+" .   .... . ",
+" . ...... . ",
+" . ...... . ",
+" .   .... . ",
+" .     .. . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            "};
diff --git a/kitten/scripts/kconfig/kconfig_load.c b/kitten/scripts/kconfig/kconfig_load.c
new file mode 100644 (file)
index 0000000..dbdcaad
--- /dev/null
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+
+#define P(name,type,arg)       type (*name ## _p) arg
+#include "lkc_proto.h"
+#undef P
+
+void kconfig_load(void)
+{
+       void *handle;
+       char *error;
+
+       handle = dlopen("./libkconfig.so", RTLD_LAZY);
+       if (!handle) {
+               handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY);
+               if (!handle) {
+                       fprintf(stderr, "%s\n", dlerror());
+                       exit(1);
+               }
+       }
+
+#define P(name,type,arg)                       \
+{                                              \
+       name ## _p = dlsym(handle, #name);      \
+        if ((error = dlerror()))  {            \
+                fprintf(stderr, "%s\n", error);        \
+               exit(1);                        \
+       }                                       \
+}
+#include "lkc_proto.h"
+#undef P
+}
diff --git a/kitten/scripts/kconfig/kxgettext.c b/kitten/scripts/kconfig/kxgettext.c
new file mode 100644 (file)
index 0000000..abee55c
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+       char *bfp = bf;
+       int multiline = strchr(text, '\n') != NULL;
+       int eol = 0;
+       int textlen = strlen(text);
+
+       if ((textlen > 0) && (text[textlen-1] == '\n'))
+               eol = 1;
+
+       *bfp++ = '"';
+       --len;
+
+       if (multiline) {
+               *bfp++ = '"';
+               *bfp++ = '\n';
+               *bfp++ = '"';
+               len -= 3;
+       }
+
+       while (*text != '\0' && len > 1) {
+               if (*text == '"')
+                       *bfp++ = '\\';
+               else if (*text == '\n') {
+                       *bfp++ = '\\';
+                       *bfp++ = 'n';
+                       *bfp++ = '"';
+                       *bfp++ = '\n';
+                       *bfp++ = '"';
+                       len -= 5;
+                       ++text;
+                       goto next;
+               }
+               *bfp++ = *text++;
+next:
+               --len;
+       }
+
+       if (multiline && eol)
+               bfp -= 3;
+
+       *bfp++ = '"';
+       *bfp = '\0';
+
+       return bf;
+}
+
+struct file_line {
+       struct file_line *next;
+       char*            file;
+       int              lineno;
+};
+
+static struct file_line *file_line__new(char *file, int lineno)
+{
+       struct file_line *self = malloc(sizeof(*self));
+
+       if (self == NULL)
+               goto out;
+
+       self->file   = file;
+       self->lineno = lineno;
+       self->next   = NULL;
+out:
+       return self;
+}
+
+struct message {
+       const char       *msg;
+       const char       *option;
+       struct message   *next;
+       struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option, char *file, int lineno)
+{
+       struct message *self = malloc(sizeof(*self));
+
+       if (self == NULL)
+               goto out;
+
+       self->files = file_line__new(file, lineno);
+       if (self->files == NULL)
+               goto out_fail;
+
+       self->msg = strdup(msg);
+       if (self->msg == NULL)
+               goto out_fail_msg;
+
+       self->option = option;
+       self->next = NULL;
+out:
+       return self;
+out_fail_msg:
+       free(self->files);
+out_fail:
+       free(self);
+       self = NULL;
+       goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+       struct message *m = message__list;
+
+       while (m != NULL) {
+               if (strcmp(m->msg, msg) == 0)
+                       break;
+               m = m->next;
+       }
+
+       return m;
+}
+
+static int message__add_file_line(struct message *self, char *file, int lineno)
+{
+       int rc = -1;
+       struct file_line *fl = file_line__new(file, lineno);
+
+       if (fl == NULL)
+               goto out;
+
+       fl->next    = self->files;
+       self->files = fl;
+       rc = 0;
+out:
+       return rc;
+}
+
+static int message__add(const char *msg, char *option, char *file, int lineno)
+{
+       int rc = 0;
+       char bf[16384];
+       char *escaped = escape(msg, bf, sizeof(bf));
+       struct message *m = mesage__find(escaped);
+
+       if (m != NULL)
+               rc = message__add_file_line(m, file, lineno);
+       else {
+               m = message__new(escaped, option, file, lineno);
+
+               if (m != NULL) {
+                       m->next       = message__list;
+                       message__list = m;
+               } else
+                       rc = -1;
+       }
+       return rc;
+}
+
+void menu_build_message_list(struct menu *menu)
+{
+       struct menu *child;
+
+       message__add(menu_get_prompt(menu), NULL,
+                    menu->file == NULL ? "Root Menu" : menu->file->name,
+                    menu->lineno);
+
+       if (menu->sym != NULL && menu->sym->help != NULL)
+               message__add(menu->sym->help, menu->sym->name,
+                            menu->file == NULL ? "Root Menu" : menu->file->name,
+                            menu->lineno);
+
+       for (child = menu->list; child != NULL; child = child->next)
+               if (child->prompt != NULL)
+                       menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+       struct file_line *fl = self->files;
+
+       putchar('\n');
+       if (self->option != NULL)
+               printf("# %s:00000\n", self->option);
+
+       printf("#: %s:%d", fl->file, fl->lineno);
+       fl = fl->next;
+
+       while (fl != NULL) {
+               printf(", %s:%d", fl->file, fl->lineno);
+               fl = fl->next;
+       }
+
+       putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+       message__print_file_lineno(self);
+
+       printf("msgid %s\n"
+              "msgstr \"\"\n", self->msg);
+}
+
+void menu__xgettext(void)
+{
+       struct message *m = message__list;
+
+       while (m != NULL) {
+               message__print_gettext_msgid_msgstr(m);
+               m = m->next;
+       }
+}
+
+int main(int ac, char **av)
+{
+       conf_parse(av[1]);
+
+       menu_build_message_list(menu_get_root_menu(NULL));
+       menu__xgettext();
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/lex.zconf.c_shipped b/kitten/scripts/kconfig/lex.zconf.c_shipped
new file mode 100644 (file)
index 0000000..24e3c8c
--- /dev/null
@@ -0,0 +1,2317 @@
+
+#line 3 "scripts/kconfig/lex.zconf.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               *yy_cp = (yy_hold_char); \
+               YY_RESTORE_YY_MORE_OFFSET \
+               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via zconfrestart()), so that the user can continue scanning by
+        * just pointing zconfin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+
+       };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file  );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  );
+void zconf_delete_buffer (YY_BUFFER_STATE b  );
+void zconf_flush_buffer (YY_BUFFER_STATE b  );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len  );
+
+void *zconfalloc (yy_size_t  );
+void *zconfrealloc (void *,yy_size_t  );
+void zconffree (void *  );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        zconfensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){\
+        zconfensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       (yytext_ptr) = yy_bp; \
+       zconfleng = (size_t) (yy_cp - yy_bp); \
+       (yy_hold_char) = *yy_cp; \
+       *yy_cp = '\0'; \
+       (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+       {
+       flex_int32_t yy_verify;
+       flex_int32_t yy_nxt;
+       };
+static yyconst flex_int16_t yy_accept[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE  16
+
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+       text = malloc(START_STRSIZE);
+       text_asize = START_STRSIZE;
+       text_size = 0;
+       *text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+       int new_size = text_size + size + 1;
+       if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
+               text = realloc(text, new_size);
+               text_asize = new_size;
+       }
+       memcpy(text + text_size, str, size);
+       text_size += size;
+       text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+       text = malloc(size + 1);
+       memcpy(text, str, size);
+       text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( zconftext, zconfleng, 1, zconfout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       errno=0; \
+       while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+       { \
+               if( errno != EINTR) \
+               { \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+                       break; \
+               } \
+               errno=0; \
+               clearerr(zconfin); \
+       }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+    
+       int str = 0;
+       int ts, i;
+
+       if ( (yy_init) )
+               {
+               (yy_init) = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! (yy_start) )
+                       (yy_start) = 1; /* first start state */
+
+               if ( ! zconfin )
+                       zconfin = stdin;
+
+               if ( ! zconfout )
+                       zconfout = stdout;
+
+               if ( ! YY_CURRENT_BUFFER ) {
+                       zconfensure_buffer_stack ();
+                       YY_CURRENT_BUFFER_LVALUE =
+                               zconf_create_buffer(zconfin,YY_BUF_SIZE );
+               }
+
+               zconf_load_buffer_state( );
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = (yy_c_buf_p);
+
+               /* Support of zconftext. */
+               *yy_cp = (yy_hold_char);
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = (yy_start);
+yy_match:
+               while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+                       ++yy_cp;
+
+               yy_current_state = -yy_current_state;
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+
+               YY_DO_BEFORE_ACTION;
+
+do_action:     /* This label is used only to access EOF actions. */
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+       current_file->lineno++;
+       return T_EOL;
+}
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+       BEGIN(COMMAND);
+}
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+       unput(zconftext[0]);
+       BEGIN(COMMAND);
+}
+       YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+               struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(zconftext, zconfleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+       YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
+       YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+               str = zconftext[0];
+               new_string();
+               BEGIN(STRING);
+       }
+       YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+               struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(zconftext, zconfleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+       YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+       YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+               BEGIN(INITIAL);
+       }
+       YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+               append_string(zconftext, zconfleng);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+               append_string(zconftext, zconfleng);
+       }
+       YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+               append_string(zconftext + 1, zconfleng - 1);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+               append_string(zconftext + 1, zconfleng - 1);
+       }
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+               if (str == zconftext[0]) {
+                       BEGIN(PARAM);
+                       zconflval.string = text;
+                       return T_WORD_QUOTE;
+               } else
+                       append_string(zconftext, 1);
+       }
+       YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+               printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+               current_file->lineno++;
+               BEGIN(INITIAL);
+               return T_EOL;
+       }
+       YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+               BEGIN(INITIAL);
+       }
+       YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+               ts = 0;
+               for (i = 0; i < zconfleng; i++) {
+                       if (zconftext[i] == '\t')
+                               ts = (ts & ~7) + 8;
+                       else
+                               ts++;
+               }
+               last_ts = ts;
+               if (first_ts) {
+                       if (ts < first_ts) {
+                               zconf_endhelp();
+                               return T_HELPTEXT;
+                       }
+                       ts -= first_ts;
+                       while (ts > 8) {
+                               append_string("        ", 8);
+                               ts -= 8;
+                       }
+                       append_string("        ", ts);
+               }
+       }
+       YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+               current_file->lineno++;
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+               current_file->lineno++;
+               append_string("\n", 1);
+       }
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+               append_string(zconftext, zconfleng);
+               if (!first_ts)
+                       first_ts = last_ts;
+       }
+       YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+       if (current_file) {
+               zconf_endfile();
+               return T_EOL;
+       }
+       fclose(zconfin);
+       yyterminate();
+}
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+       YY_BREAK
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = (yy_hold_char);
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed zconfin at a new source and called
+                        * zconflex().  If so, then we have to assure
+                        * consistency between YY_CURRENT_BUFFER and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state(  );
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++(yy_c_buf_p);
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = (yy_c_buf_p);
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer(  ) )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               (yy_did_buffer_switch_on_eof) = 0;
+
+                               if ( zconfwrap( ) )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * zconftext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               (yy_c_buf_p) =
+                                       (yytext_ptr) + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               (yy_c_buf_p) =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+                               yy_current_state = yy_get_previous_state(  );
+
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = (yytext_ptr);
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+       else
+               {
+                       size_t num_to_read =
+                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+                       int yy_c_buf_p_offset =
+                               (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+                                               number_to_move - 1;
+
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+                       (yy_n_chars), num_to_read );
+
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       if ( (yy_n_chars) == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       zconfrestart(zconfin  );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       (yy_n_chars) += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+       (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+       return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+    
+       yy_current_state = (yy_start);
+
+       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+               {
+               yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+               }
+
+       return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+       register int yy_is_jam;
+    
+       yy_current_state = yy_nxt[yy_current_state][1];
+       yy_is_jam = (yy_current_state <= 0);
+
+       return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+       register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+       /* undo effects of setting up zconftext */
+       *yy_cp = (yy_hold_char);
+
+       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = (yy_n_chars) + 2;
+               register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+               register char *source =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+       (yytext_ptr) = yy_bp;
+       (yy_hold_char) = *yy_cp;
+       (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+       int c;
+    
+       *(yy_c_buf_p) = (yy_hold_char);
+
+       if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+                       /* This was really a NUL. */
+                       *(yy_c_buf_p) = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
+                       ++(yy_c_buf_p);
+
+                       switch ( yy_get_next_buffer(  ) )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       zconfrestart(zconfin );
+
+                                       /*FALLTHROUGH*/
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( zconfwrap( ) )
+                                               return EOF;
+
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       (yy_c_buf_p) = (yytext_ptr) + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
+       *(yy_c_buf_p) = '\0';   /* preserve zconftext */
+       (yy_hold_char) = *++(yy_c_buf_p);
+
+       return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void zconfrestart  (FILE * input_file )
+{
+    
+       if ( ! YY_CURRENT_BUFFER ){
+        zconfensure_buffer_stack ();
+               YY_CURRENT_BUFFER_LVALUE =
+            zconf_create_buffer(zconfin,YY_BUF_SIZE );
+       }
+
+       zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+       zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              zconfpop_buffer_state();
+        *              zconfpush_buffer_state(new_buffer);
+     */
+       zconfensure_buffer_stack ();
+       if ( YY_CURRENT_BUFFER == new_buffer )
+               return;
+
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       zconf_load_buffer_state( );
+
+       /* We don't actually know whether we did this switch during
+        * EOF (zconfwrap()) processing, but the only time this flag
+        * is looked at is after zconfwrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state  (void)
+{
+       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size )
+{
+       YY_BUFFER_STATE b;
+    
+       b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2  );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       zconf_init_buffer(b,file );
+
+       return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ * 
+ */
+    void zconf_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+       if ( ! b )
+               return;
+
+       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               zconffree((void *) b->yy_ch_buf  );
+
+       zconffree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+       int oerrno = errno;
+    
+       zconf_flush_buffer(b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then zconf_init_buffer was _probably_
+     * called from zconfrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+       errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void zconf_flush_buffer (YY_BUFFER_STATE  b )
+{
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == YY_CURRENT_BUFFER )
+               zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+       if (new_buffer == NULL)
+               return;
+
+       zconfensure_buffer_stack();
+
+       /* This block is copied from zconf_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               (yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from zconf_switch_to_buffer. */
+       zconf_load_buffer_state( );
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void zconfpop_buffer_state (void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       zconf_delete_buffer(YY_CURRENT_BUFFER );
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if ((yy_buffer_stack_top) > 0)
+               --(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               zconf_load_buffer_state( );
+               (yy_did_buffer_switch_on_eof) = 1;
+       }
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+       int num_to_alloc;
+    
+       if (!(yy_buffer_stack)) {
+
+               /* First allocation is just for 2 elements, since we don't know if this
+                * scanner will even need a stack. We use 2 instead of 1 to avoid an
+                * immediate realloc on the next call.
+         */
+               num_to_alloc = 1;
+               (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               
+               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               (yy_buffer_stack_max) = num_to_alloc;
+               (yy_buffer_stack_top) = 0;
+               return;
+       }
+
+       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = (yy_buffer_stack_max) + grow_size;
+               (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+                                                               ((yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+
+               /* zero only the new slots.*/
+               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               (yy_buffer_stack_max) = num_to_alloc;
+       }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
+{
+       YY_BUFFER_STATE b;
+    
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       zconf_switch_to_buffer(b  );
+
+       return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yy_str a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yy_str )
+{
+    
+       return zconf_scan_bytes(yy_str,strlen(yy_str) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * bytes, int  len )
+{
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+    
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = len + 2;
+       buf = (char *) zconfalloc(n  );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+       for ( i = 0; i < len; ++i )
+               buf[i] = bytes[i];
+
+       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = zconf_scan_buffer(buf,n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               zconftext[zconfleng] = (yy_hold_char); \
+               (yy_c_buf_p) = zconftext + yyless_macro_arg; \
+               (yy_hold_char) = *(yy_c_buf_p); \
+               *(yy_c_buf_p) = '\0'; \
+               zconfleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int zconfget_lineno  (void)
+{
+        
+    return zconflineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *zconfget_in  (void)
+{
+        return zconfin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *zconfget_out  (void)
+{
+        return zconfout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int zconfget_leng  (void)
+{
+        return zconfleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *zconfget_text  (void)
+{
+        return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void zconfset_lineno (int  line_number )
+{
+    
+    zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE *  in_str )
+{
+        zconfin = in_str ;
+}
+
+void zconfset_out (FILE *  out_str )
+{
+        zconfout = out_str ;
+}
+
+int zconfget_debug  (void)
+{
+        return zconf_flex_debug;
+}
+
+void zconfset_debug (int  bdebug )
+{
+        zconf_flex_debug = bdebug ;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               zconf_delete_buffer(YY_CURRENT_BUFFER  );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               zconfpop_buffer_state();
+       }
+
+       /* Destroy the stack itself. */
+       zconffree((yy_buffer_stack) );
+       (yy_buffer_stack) = NULL;
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t  size )
+{
+       return (void *) malloc( size );
+}
+
+void *zconfrealloc  (void * ptr, yy_size_t  size )
+{
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+       free( (char *) ptr );   /* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+void zconf_starthelp(void)
+{
+       new_string();
+       last_ts = first_ts = 0;
+       BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+       zconflval.string = text;
+       BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+       char *env, fullname[PATH_MAX+1];
+       FILE *f;
+
+       f = fopen(name, "r");
+       if (!f && name[0] != '/') {
+               env = getenv(SRCTREE);
+               if (env) {
+                       sprintf(fullname, "%s/%s", env, name);
+                       f = fopen(fullname, "r");
+               }
+       }
+       return f;
+}
+
+void zconf_initscan(const char *name)
+{
+       zconfin = zconf_fopen(name);
+       if (!zconfin) {
+               printf("can't find file %s\n", name);
+               exit(1);
+       }
+
+       current_buf = malloc(sizeof(*current_buf));
+       memset(current_buf, 0, sizeof(*current_buf));
+
+       current_file = file_lookup(name);
+       current_file->lineno = 1;
+       current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+       struct file *file = file_lookup(name);
+       struct buffer *buf = malloc(sizeof(*buf));
+       memset(buf, 0, sizeof(*buf));
+
+       current_buf->state = YY_CURRENT_BUFFER;
+       zconfin = zconf_fopen(name);
+       if (!zconfin) {
+               printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+               exit(1);
+       }
+       zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+       buf->parent = current_buf;
+       current_buf = buf;
+
+       if (file->flags & FILE_BUSY) {
+               printf("recursive scan (%s)?\n", name);
+               exit(1);
+       }
+       if (file->flags & FILE_SCANNED) {
+               printf("file %s already scanned?\n", name);
+               exit(1);
+       }
+       file->flags |= FILE_BUSY;
+       file->lineno = 1;
+       file->parent = current_file;
+       current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+       struct buffer *parent;
+
+       current_file->flags |= FILE_SCANNED;
+       current_file->flags &= ~FILE_BUSY;
+       current_file = current_file->parent;
+
+       parent = current_buf->parent;
+       if (parent) {
+               fclose(zconfin);
+               zconf_delete_buffer(YY_CURRENT_BUFFER);
+               zconf_switch_to_buffer(parent->state);
+       }
+       free(current_buf);
+       current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+       return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+       return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/kitten/scripts/kconfig/lkc.h b/kitten/scripts/kconfig/lkc.h
new file mode 100644 (file)
index 0000000..527f60c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg)       extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg)       extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#define PACKAGE "linux"
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+
+#define TF_COMMAND     0x0001
+#define TF_PARAM       0x0002
+
+struct kconf_id {
+       int name;
+       int token;
+       unsigned int flags;
+       enum symbol_type stype;
+};
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+
+extern int zconfdebug;
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+char *zconf_curname(void);
+
+/* confdata.c */
+extern const char conf_def_filename[];
+
+char *conf_get_default_confname(void);
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void menu_init(void);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+       size_t len;
+       char  *s;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+       return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+       return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+       return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+       return sym->flags & SYMBOL_NEW ? false : true;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/kitten/scripts/kconfig/lkc_proto.h b/kitten/scripts/kconfig/lkc_proto.h
new file mode 100644 (file)
index 0000000..b6a389c
--- /dev/null
@@ -0,0 +1,41 @@
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name));
+P(conf_write,int,(const char *name));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible,bool,(struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+P(sym_change_count,int,);
+
+P(sym_lookup,struct symbol *,(const char *name, int isconst));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken));
diff --git a/kitten/scripts/kconfig/lxdialog/BIG.FAT.WARNING b/kitten/scripts/kconfig/lxdialog/BIG.FAT.WARNING
new file mode 100644 (file)
index 0000000..a8999d8
--- /dev/null
@@ -0,0 +1,4 @@
+This is NOT the official version of dialog.  This version has been
+significantly modified from the original.  It is for use by the Linux
+kernel configuration script.  Please do not bother Savio Lam with 
+questions about this program.
diff --git a/kitten/scripts/kconfig/lxdialog/Makefile b/kitten/scripts/kconfig/lxdialog/Makefile
new file mode 100644 (file)
index 0000000..a8b0263
--- /dev/null
@@ -0,0 +1,21 @@
+# Makefile to build lxdialog package
+#
+
+check-lxdialog  := $(srctree)/$(src)/check-lxdialog.sh
+
+# Use reursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
+HOST_LOADLIBES   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOST_EXTRACFLAGS += -DLOCALE
+
+PHONY += dochecklxdialog
+$(obj)/dochecklxdialog:
+       $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_LOADLIBES)
+
+hostprogs-y    := lxdialog
+always         := $(hostprogs-y) dochecklxdialog
+
+lxdialog-objs := checklist.o menubox.o textbox.o yesno.o inputbox.o \
+                util.o lxdialog.o msgbox.o
diff --git a/kitten/scripts/kconfig/lxdialog/check-lxdialog.sh b/kitten/scripts/kconfig/lxdialog/check-lxdialog.sh
new file mode 100644 (file)
index 0000000..120d624
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+       $cc -print-file-name=libncursesw.so | grep -q /
+       if [ $? -eq 0 ]; then
+               echo '-lncursesw'
+               exit
+       fi
+       $cc -print-file-name=libncurses.so | grep -q /
+       if [ $? -eq 0 ]; then
+               echo '-lncurses'
+               exit
+       fi
+       $cc -print-file-name=libcurses.so | grep -q /
+       if [ $? -eq 0 ]; then
+               echo '-lcurses'
+               exit
+       fi
+       exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+       if [ -f /usr/include/ncurses/ncurses.h ]; then
+               echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+       elif [ -f /usr/include/ncurses/curses.h ]; then
+               echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+       elif [ -f /usr/include/ncurses.h ]; then
+               echo '-DCURSES_LOC="<ncurses.h>"'
+       else
+               echo '-DCURSES_LOC="<curses.h>"'
+       fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+       echo "main() {}" | $cc -xc - -o $tmp 2> /dev/null
+       if [ $? != 0 ]; then
+               echo " *** Unable to find the ncurses libraries."          1>&2
+               echo " *** make menuconfig require the ncurses libraries"  1>&2
+               echo " *** "                                               1>&2
+               echo " *** Install ncurses (ncurses-devel) and try again"  1>&2
+               echo " *** "                                               1>&2
+               exit 1
+       fi
+}
+
+usage() {
+       printf "Usage: $0 [-check compiler options|-header|-library]\n"
+}
+
+if [ $# == 0 ]; then
+       usage
+       exit 1
+fi
+
+cc=""
+case "$1" in
+       "-check")
+               shift
+               cc="$@"
+               check
+               ;;
+       "-ccflags")
+               ccflags
+               ;;
+       "-ldflags")
+               shift
+               cc="$@"
+               ldflags
+               ;;
+       "*")
+               usage
+               exit 1
+               ;;
+esac
diff --git a/kitten/scripts/kconfig/lxdialog/checklist.c b/kitten/scripts/kconfig/lxdialog/checklist.c
new file mode 100644 (file)
index 0000000..be0200e
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, const char *item, int status, int choice,
+                      int selected)
+{
+       int i;
+
+       /* Clear 'residue' of last item */
+       wattrset(win, menubox_attr);
+       wmove(win, choice, 0);
+       for (i = 0; i < list_width; i++)
+               waddch(win, ' ');
+
+       wmove(win, choice, check_x);
+       wattrset(win, selected ? check_selected_attr : check_attr);
+       wprintw(win, "(%c)", status ? 'X' : ' ');
+
+       wattrset(win, selected ? tag_selected_attr : tag_attr);
+       mvwaddch(win, choice, item_x, item[0]);
+       wattrset(win, selected ? item_selected_attr : item_attr);
+       waddstr(win, (char *)item + 1);
+       if (selected) {
+               wmove(win, choice, check_x + 1);
+               wrefresh(win);
+       }
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+            int y, int x, int height)
+{
+       wmove(win, y, x);
+
+       if (scroll > 0) {
+               wattrset(win, uarrow_attr);
+               waddch(win, ACS_UARROW);
+               waddstr(win, "(-)");
+       } else {
+               wattrset(win, menubox_attr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+
+       y = y + height + 1;
+       wmove(win, y, x);
+
+       if ((height < item_no) && (scroll + choice < item_no - 1)) {
+               wattrset(win, darrow_attr);
+               waddch(win, ACS_DARROW);
+               waddstr(win, "(+)");
+       } else {
+               wattrset(win, menubox_border_attr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+       int x = width / 2 - 11;
+       int y = height - 2;
+
+       print_button(dialog, "Select", y, x, selected == 0);
+       print_button(dialog, " Help ", y, x + 14, selected == 1);
+
+       wmove(dialog, y, x + 1 + 14 * selected);
+       wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+                    int width, int list_height, int item_no,
+                    const char *const *items)
+{
+       int i, x, y, box_x, box_y;
+       int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
+       WINDOW *dialog, *list;
+
+       /* Allocate space for storing item on/off status */
+       if ((status = malloc(sizeof(int) * item_no)) == NULL) {
+               endwin();
+               fprintf(stderr,
+                       "\nCan't allocate memory in dialog_checklist().\n");
+               exit(-1);
+       }
+
+       /* Initializes status */
+       for (i = 0; i < item_no; i++) {
+               status[i] = !strcasecmp(items[i * 3 + 2], "on");
+               if ((!choice && status[i])
+                   || !strcasecmp(items[i * 3 + 2], "selected"))
+                       choice = i + 1;
+       }
+       if (choice)
+               choice--;
+
+       max_choice = MIN(list_height, item_no);
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+       wattrset(dialog, border_attr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dialog_attr);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dialog_attr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       list_width = width - 6;
+       box_y = height - list_height - 5;
+       box_x = (width - list_width) / 2 - 1;
+
+       /* create new window for the list */
+       list = subwin(dialog, list_height, list_width, y + box_y + 1,
+                     x + box_x + 1);
+
+       keypad(list, TRUE);
+
+       /* draw a box around the list items */
+       draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+                menubox_border_attr, menubox_attr);
+
+       /* Find length of longest item in order to center checklist */
+       check_x = 0;
+       for (i = 0; i < item_no; i++)
+               check_x = MAX(check_x, +strlen(items[i * 3 + 1]) + 4);
+
+       check_x = (list_width - check_x) / 2;
+       item_x = check_x + 4;
+
+       if (choice >= list_height) {
+               scroll = choice - list_height + 1;
+               choice -= scroll;
+       }
+
+       /* Print the list */
+       for (i = 0; i < max_choice; i++) {
+               print_item(list, items[(scroll + i) * 3 + 1],
+                          status[i + scroll], i, i == choice);
+       }
+
+       print_arrows(dialog, choice, item_no, scroll,
+                    box_y, box_x + check_x + 5, list_height);
+
+       print_buttons(dialog, height, width, 0);
+
+       wnoutrefresh(dialog);
+       wnoutrefresh(list);
+       doupdate();
+
+       while (key != ESC) {
+               key = wgetch(dialog);
+
+               for (i = 0; i < max_choice; i++)
+                       if (toupper(key) ==
+                           toupper(items[(scroll + i) * 3 + 1][0]))
+                               break;
+
+               if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+                   key == '+' || key == '-') {
+                       if (key == KEY_UP || key == '-') {
+                               if (!choice) {
+                                       if (!scroll)
+                                               continue;
+                                       /* Scroll list down */
+                                       if (list_height > 1) {
+                                               /* De-highlight current first item */
+                                               print_item(list, items[scroll * 3 + 1],
+                                                          status[scroll], 0, FALSE);
+                                               scrollok(list, TRUE);
+                                               wscrl(list, -1);
+                                               scrollok(list, FALSE);
+                                       }
+                                       scroll--;
+                                       print_item(list, items[scroll * 3 + 1], status[scroll], 0, TRUE);
+                                       print_arrows(dialog, choice, item_no,
+                                                    scroll, box_y, box_x + check_x + 5, list_height);
+
+                                       wnoutrefresh(dialog);
+                                       wrefresh(list);
+
+                                       continue;       /* wait for another key press */
+                               } else
+                                       i = choice - 1;
+                       } else if (key == KEY_DOWN || key == '+') {
+                               if (choice == max_choice - 1) {
+                                       if (scroll + choice >= item_no - 1)
+                                               continue;
+                                       /* Scroll list up */
+                                       if (list_height > 1) {
+                                               /* De-highlight current last item before scrolling up */
+                                               print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
+                                                          status[scroll + max_choice - 1],
+                                                          max_choice - 1, FALSE);
+                                               scrollok(list, TRUE);
+                                               wscrl(list, 1);
+                                               scrollok(list, FALSE);
+                                       }
+                                       scroll++;
+                                       print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
+                                                  status[scroll + max_choice - 1], max_choice - 1, TRUE);
+
+                                       print_arrows(dialog, choice, item_no,
+                                                    scroll, box_y, box_x + check_x + 5, list_height);
+
+                                       wnoutrefresh(dialog);
+                                       wrefresh(list);
+
+                                       continue;       /* wait for another key press */
+                               } else
+                                       i = choice + 1;
+                       }
+                       if (i != choice) {
+                               /* De-highlight current item */
+                               print_item(list, items[(scroll + choice) * 3 + 1],
+                                          status[scroll + choice], choice, FALSE);
+                               /* Highlight new item */
+                               choice = i;
+                               print_item(list, items[(scroll + choice) * 3 + 1],
+                                          status[scroll + choice], choice, TRUE);
+                               wnoutrefresh(dialog);
+                               wrefresh(list);
+                       }
+                       continue;       /* wait for another key press */
+               }
+               switch (key) {
+               case 'H':
+               case 'h':
+               case '?':
+                       fprintf(stderr, "%s", items[(scroll + choice) * 3]);
+                       delwin(dialog);
+                       free(status);
+                       return 1;
+               case TAB:
+               case KEY_LEFT:
+               case KEY_RIGHT:
+                       button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                           ? 1 : (button > 1 ? 0 : button);
+
+                       print_buttons(dialog, height, width, button);
+                       wrefresh(dialog);
+                       break;
+               case 'S':
+               case 's':
+               case ' ':
+               case '\n':
+                       if (!button) {
+                               if (!status[scroll + choice]) {
+                                       for (i = 0; i < item_no; i++)
+                                               status[i] = 0;
+                                       status[scroll + choice] = 1;
+                                       for (i = 0; i < max_choice; i++)
+                                               print_item(list, items[(scroll + i) * 3 + 1],
+                                                          status[scroll + i], i, i == choice);
+                               }
+                               wnoutrefresh(dialog);
+                               wrefresh(list);
+
+                               for (i = 0; i < item_no; i++)
+                                       if (status[i])
+                                               fprintf(stderr, "%s", items[i * 3]);
+                       } else
+                               fprintf(stderr, "%s", items[(scroll + choice) * 3]);
+                       delwin(dialog);
+                       free(status);
+                       return button;
+               case 'X':
+               case 'x':
+                       key = ESC;
+               case ESC:
+                       break;
+               }
+
+               /* Now, update everything... */
+               doupdate();
+       }
+
+       delwin(dialog);
+       free(status);
+       return -1;              /* ESC pressed */
+}
diff --git a/kitten/scripts/kconfig/lxdialog/colors.h b/kitten/scripts/kconfig/lxdialog/colors.h
new file mode 100644 (file)
index 0000000..db071df
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *  colors.h -- color attribute definitions
+ *
+ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *   Default color definitions
+ *
+ *   *_FG = foreground
+ *   *_BG = background
+ *   *_HL = highlight?
+ */
+#define SCREEN_FG                    COLOR_CYAN
+#define SCREEN_BG                    COLOR_BLUE
+#define SCREEN_HL                    TRUE
+
+#define SHADOW_FG                    COLOR_BLACK
+#define SHADOW_BG                    COLOR_BLACK
+#define SHADOW_HL                    TRUE
+
+#define DIALOG_FG                    COLOR_BLACK
+#define DIALOG_BG                    COLOR_WHITE
+#define DIALOG_HL                    FALSE
+
+#define TITLE_FG                     COLOR_YELLOW
+#define TITLE_BG                     COLOR_WHITE
+#define TITLE_HL                     TRUE
+
+#define BORDER_FG                    COLOR_WHITE
+#define BORDER_BG                    COLOR_WHITE
+#define BORDER_HL                    TRUE
+
+#define BUTTON_ACTIVE_FG             COLOR_WHITE
+#define BUTTON_ACTIVE_BG             COLOR_BLUE
+#define BUTTON_ACTIVE_HL             TRUE
+
+#define BUTTON_INACTIVE_FG           COLOR_BLACK
+#define BUTTON_INACTIVE_BG           COLOR_WHITE
+#define BUTTON_INACTIVE_HL           FALSE
+
+#define BUTTON_KEY_ACTIVE_FG         COLOR_WHITE
+#define BUTTON_KEY_ACTIVE_BG         COLOR_BLUE
+#define BUTTON_KEY_ACTIVE_HL         TRUE
+
+#define BUTTON_KEY_INACTIVE_FG       COLOR_RED
+#define BUTTON_KEY_INACTIVE_BG       COLOR_WHITE
+#define BUTTON_KEY_INACTIVE_HL       FALSE
+
+#define BUTTON_LABEL_ACTIVE_FG       COLOR_YELLOW
+#define BUTTON_LABEL_ACTIVE_BG       COLOR_BLUE
+#define BUTTON_LABEL_ACTIVE_HL       TRUE
+
+#define BUTTON_LABEL_INACTIVE_FG     COLOR_BLACK
+#define BUTTON_LABEL_INACTIVE_BG     COLOR_WHITE
+#define BUTTON_LABEL_INACTIVE_HL     TRUE
+
+#define INPUTBOX_FG                  COLOR_BLACK
+#define INPUTBOX_BG                  COLOR_WHITE
+#define INPUTBOX_HL                  FALSE
+
+#define INPUTBOX_BORDER_FG           COLOR_BLACK
+#define INPUTBOX_BORDER_BG           COLOR_WHITE
+#define INPUTBOX_BORDER_HL           FALSE
+
+#define SEARCHBOX_FG                 COLOR_BLACK
+#define SEARCHBOX_BG                 COLOR_WHITE
+#define SEARCHBOX_HL                 FALSE
+
+#define SEARCHBOX_TITLE_FG           COLOR_YELLOW
+#define SEARCHBOX_TITLE_BG           COLOR_WHITE
+#define SEARCHBOX_TITLE_HL           TRUE
+
+#define SEARCHBOX_BORDER_FG          COLOR_WHITE
+#define SEARCHBOX_BORDER_BG          COLOR_WHITE
+#define SEARCHBOX_BORDER_HL          TRUE
+
+#define POSITION_INDICATOR_FG        COLOR_YELLOW
+#define POSITION_INDICATOR_BG        COLOR_WHITE
+#define POSITION_INDICATOR_HL        TRUE
+
+#define MENUBOX_FG                   COLOR_BLACK
+#define MENUBOX_BG                   COLOR_WHITE
+#define MENUBOX_HL                   FALSE
+
+#define MENUBOX_BORDER_FG            COLOR_WHITE
+#define MENUBOX_BORDER_BG            COLOR_WHITE
+#define MENUBOX_BORDER_HL            TRUE
+
+#define ITEM_FG                      COLOR_BLACK
+#define ITEM_BG                      COLOR_WHITE
+#define ITEM_HL                      FALSE
+
+#define ITEM_SELECTED_FG             COLOR_WHITE
+#define ITEM_SELECTED_BG             COLOR_BLUE
+#define ITEM_SELECTED_HL             TRUE
+
+#define TAG_FG                       COLOR_YELLOW
+#define TAG_BG                       COLOR_WHITE
+#define TAG_HL                       TRUE
+
+#define TAG_SELECTED_FG              COLOR_YELLOW
+#define TAG_SELECTED_BG              COLOR_BLUE
+#define TAG_SELECTED_HL              TRUE
+
+#define TAG_KEY_FG                   COLOR_YELLOW
+#define TAG_KEY_BG                   COLOR_WHITE
+#define TAG_KEY_HL                   TRUE
+
+#define TAG_KEY_SELECTED_FG          COLOR_YELLOW
+#define TAG_KEY_SELECTED_BG          COLOR_BLUE
+#define TAG_KEY_SELECTED_HL          TRUE
+
+#define CHECK_FG                     COLOR_BLACK
+#define CHECK_BG                     COLOR_WHITE
+#define CHECK_HL                     FALSE
+
+#define CHECK_SELECTED_FG            COLOR_WHITE
+#define CHECK_SELECTED_BG            COLOR_BLUE
+#define CHECK_SELECTED_HL            TRUE
+
+#define UARROW_FG                    COLOR_GREEN
+#define UARROW_BG                    COLOR_WHITE
+#define UARROW_HL                    TRUE
+
+#define DARROW_FG                    COLOR_GREEN
+#define DARROW_BG                    COLOR_WHITE
+#define DARROW_HL                    TRUE
+
+/* End of default color definitions */
+
+#define C_ATTR(x,y)                  ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
+#define COLOR_NAME_LEN               10
+#define COLOR_COUNT                  8
+
+/*
+ * Global variables
+ */
+
+extern int color_table[][3];
diff --git a/kitten/scripts/kconfig/lxdialog/dialog.h b/kitten/scripts/kconfig/lxdialog/dialog.h
new file mode 100644 (file)
index 0000000..af3cf71
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)          /*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/*
+ * Attribute names
+ */
+#define screen_attr                   attributes[0]
+#define shadow_attr                   attributes[1]
+#define dialog_attr                   attributes[2]
+#define title_attr                    attributes[3]
+#define border_attr                   attributes[4]
+#define button_active_attr            attributes[5]
+#define button_inactive_attr          attributes[6]
+#define button_key_active_attr        attributes[7]
+#define button_key_inactive_attr      attributes[8]
+#define button_label_active_attr      attributes[9]
+#define button_label_inactive_attr    attributes[10]
+#define inputbox_attr                 attributes[11]
+#define inputbox_border_attr          attributes[12]
+#define searchbox_attr                attributes[13]
+#define searchbox_title_attr          attributes[14]
+#define searchbox_border_attr         attributes[15]
+#define position_indicator_attr       attributes[16]
+#define menubox_attr                  attributes[17]
+#define menubox_border_attr           attributes[18]
+#define item_attr                     attributes[19]
+#define item_selected_attr            attributes[20]
+#define tag_attr                      attributes[21]
+#define tag_selected_attr             attributes[22]
+#define tag_key_attr                  attributes[23]
+#define tag_key_selected_attr         attributes[24]
+#define check_attr                    attributes[25]
+#define check_selected_attr           attributes[26]
+#define uarrow_attr                   attributes[27]
+#define darrow_attr                   attributes[28]
+
+/* number of attributes */
+#define ATTRIBUTE_COUNT               29
+
+/*
+ * Global variables
+ */
+extern bool use_colors;
+extern bool use_shadow;
+
+extern chtype attributes[];
+
+extern const char *backtitle;
+
+/*
+ * Function prototypes
+ */
+extern void create_rc(const char *filename);
+extern int parse_rc(void);
+
+void init_dialog(void);
+void end_dialog(void);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void color_setup(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+             chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+                 int width, int pause);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+int dialog_menu(const char *title, const char *prompt, int height, int width,
+               int menu_height, const char *choice, int item_no,
+               const char *const *items);
+int dialog_checklist(const char *title, const char *prompt, int height,
+                    int width, int list_height, int item_no,
+                    const char *const *items);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+                   int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
diff --git a/kitten/scripts/kconfig/lxdialog/inputbox.c b/kitten/scripts/kconfig/lxdialog/inputbox.c
new file mode 100644 (file)
index 0000000..7795037
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+       int x = width / 2 - 11;
+       int y = height - 2;
+
+       print_button(dialog, "  Ok  ", y, x, selected == 0);
+       print_button(dialog, " Help ", y, x + 14, selected == 1);
+
+       wmove(dialog, y, x + 1 + 14 * selected);
+       wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+                    const char *init)
+{
+       int i, x, y, box_y, box_x, box_width;
+       int input_x = 0, scroll = 0, key = 0, button = -1;
+       char *instr = dialog_input_result;
+       WINDOW *dialog;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+       wattrset(dialog, border_attr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dialog_attr);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dialog_attr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       /* Draw the input field box */
+       box_width = width - 6;
+       getyx(dialog, y, x);
+       box_y = y + 2;
+       box_x = (width - box_width) / 2;
+       draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, border_attr, dialog_attr);
+
+       print_buttons(dialog, height, width, 0);
+
+       /* Set up the initial value */
+       wmove(dialog, box_y, box_x);
+       wattrset(dialog, inputbox_attr);
+
+       if (!init)
+               instr[0] = '\0';
+       else
+               strcpy(instr, init);
+
+       input_x = strlen(instr);
+
+       if (input_x >= box_width) {
+               scroll = input_x - box_width + 1;
+               input_x = box_width - 1;
+               for (i = 0; i < box_width - 1; i++)
+                       waddch(dialog, instr[scroll + i]);
+       } else {
+               waddstr(dialog, instr);
+       }
+
+       wmove(dialog, box_y, box_x + input_x);
+
+       wrefresh(dialog);
+
+       while (key != ESC) {
+               key = wgetch(dialog);
+
+               if (button == -1) {     /* Input box selected */
+                       switch (key) {
+                       case TAB:
+                       case KEY_UP:
+                       case KEY_DOWN:
+                               break;
+                       case KEY_LEFT:
+                               continue;
+                       case KEY_RIGHT:
+                               continue;
+                       case KEY_BACKSPACE:
+                       case 127:
+                               if (input_x || scroll) {
+                                       wattrset(dialog, inputbox_attr);
+                                       if (!input_x) {
+                                               scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+                                               wmove(dialog, box_y, box_x);
+                                               for (i = 0; i < box_width; i++)
+                                                       waddch(dialog,
+                                                              instr[scroll + input_x + i] ?
+                                                              instr[scroll + input_x + i] : ' ');
+                                               input_x = strlen(instr) - scroll;
+                                       } else
+                                               input_x--;
+                                       instr[scroll + input_x] = '\0';
+                                       mvwaddch(dialog, box_y, input_x + box_x, ' ');
+                                       wmove(dialog, box_y, input_x + box_x);
+                                       wrefresh(dialog);
+                               }
+                               continue;
+                       default:
+                               if (key < 0x100 && isprint(key)) {
+                                       if (scroll + input_x < MAX_LEN) {
+                                               wattrset(dialog, inputbox_attr);
+                                               instr[scroll + input_x] = key;
+                                               instr[scroll + input_x + 1] = '\0';
+                                               if (input_x == box_width - 1) {
+                                                       scroll++;
+                                                       wmove(dialog, box_y, box_x);
+                                                       for (i = 0; i < box_width - 1; i++)
+                                                               waddch(dialog, instr [scroll + i]);
+                                               } else {
+                                                       wmove(dialog, box_y, input_x++ + box_x);
+                                                       waddch(dialog, key);
+                                               }
+                                               wrefresh(dialog);
+                                       } else
+                                               flash();        /* Alarm user about overflow */
+                                       continue;
+                               }
+                       }
+               }
+               switch (key) {
+               case 'O':
+               case 'o':
+                       delwin(dialog);
+                       return 0;
+               case 'H':
+               case 'h':
+                       delwin(dialog);
+                       return 1;
+               case KEY_UP:
+               case KEY_LEFT:
+                       switch (button) {
+                       case -1:
+                               button = 1;     /* Indicates "Cancel" button is selected */
+                               print_buttons(dialog, height, width, 1);
+                               break;
+                       case 0:
+                               button = -1;    /* Indicates input box is selected */
+                               print_buttons(dialog, height, width, 0);
+                               wmove(dialog, box_y, box_x + input_x);
+                               wrefresh(dialog);
+                               break;
+                       case 1:
+                               button = 0;     /* Indicates "OK" button is selected */
+                               print_buttons(dialog, height, width, 0);
+                               break;
+                       }
+                       break;
+               case TAB:
+               case KEY_DOWN:
+               case KEY_RIGHT:
+                       switch (button) {
+                       case -1:
+                               button = 0;     /* Indicates "OK" button is selected */
+                               print_buttons(dialog, height, width, 0);
+                               break;
+                       case 0:
+                               button = 1;     /* Indicates "Cancel" button is selected */
+                               print_buttons(dialog, height, width, 1);
+                               break;
+                       case 1:
+                               button = -1;    /* Indicates input box is selected */
+                               print_buttons(dialog, height, width, 0);
+                               wmove(dialog, box_y, box_x + input_x);
+                               wrefresh(dialog);
+                               break;
+                       }
+                       break;
+               case ' ':
+               case '\n':
+                       delwin(dialog);
+                       return (button == -1 ? 0 : button);
+               case 'X':
+               case 'x':
+                       key = ESC;
+               case ESC:
+                       break;
+               }
+       }
+
+       delwin(dialog);
+       return -1;              /* ESC pressed */
+}
diff --git a/kitten/scripts/kconfig/lxdialog/lxdialog.c b/kitten/scripts/kconfig/lxdialog/lxdialog.c
new file mode 100644 (file)
index 0000000..79f6c5f
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *  dialog - Display simple dialog boxes from shell scripts
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void Usage(const char *name);
+
+typedef int (jumperFn) (const char *title, int argc, const char *const *argv);
+
+struct Mode {
+       char *name;
+       int argmin, argmax, argmod;
+       jumperFn *jumper;
+};
+
+jumperFn j_menu, j_radiolist, j_yesno, j_textbox, j_inputbox;
+jumperFn j_msgbox, j_infobox;
+
+static struct Mode modes[] = {
+       {"--menu", 9, 0, 3, j_menu},
+       {"--radiolist", 9, 0, 3, j_radiolist},
+       {"--yesno", 5, 5, 1, j_yesno},
+       {"--textbox", 5, 5, 1, j_textbox},
+       {"--inputbox", 5, 6, 1, j_inputbox},
+       {"--msgbox", 5, 5, 1, j_msgbox},
+       {"--infobox", 5, 5, 1, j_infobox},
+       {NULL, 0, 0, 0, NULL}
+};
+
+static struct Mode *modePtr;
+
+#ifdef LOCALE
+#include <locale.h>
+#endif
+
+int main(int argc, const char *const *argv)
+{
+       int offset = 0, opt_clear = 0, end_common_opts = 0, retval;
+       const char *title = NULL;
+
+#ifdef LOCALE
+       (void)setlocale(LC_ALL, "");
+#endif
+
+#ifdef TRACE
+       trace(TRACE_CALLS | TRACE_UPDATE);
+#endif
+       if (argc < 2) {
+               Usage(argv[0]);
+               exit(-1);
+       }
+
+       while (offset < argc - 1 && !end_common_opts) { /* Common options */
+               if (!strcmp(argv[offset + 1], "--title")) {
+                       if (argc - offset < 3 || title != NULL) {
+                               Usage(argv[0]);
+                               exit(-1);
+                       } else {
+                               title = argv[offset + 2];
+                               offset += 2;
+                       }
+               } else if (!strcmp(argv[offset + 1], "--backtitle")) {
+                       if (backtitle != NULL) {
+                               Usage(argv[0]);
+                               exit(-1);
+                       } else {
+                               backtitle = argv[offset + 2];
+                               offset += 2;
+                       }
+               } else if (!strcmp(argv[offset + 1], "--clear")) {
+                       if (opt_clear) {        /* Hey, "--clear" can't appear twice! */
+                               Usage(argv[0]);
+                               exit(-1);
+                       } else if (argc == 2) { /* we only want to clear the screen */
+                               init_dialog();
+                               refresh();      /* init_dialog() will clear the screen for us */
+                               end_dialog();
+                               return 0;
+                       } else {
+                               opt_clear = 1;
+                               offset++;
+                       }
+               } else          /* no more common options */
+                       end_common_opts = 1;
+       }
+
+       if (argc - 1 == offset) {       /* no more options */
+               Usage(argv[0]);
+               exit(-1);
+       }
+       /* use a table to look for the requested mode, to avoid code duplication */
+
+       for (modePtr = modes; modePtr->name; modePtr++) /* look for the mode */
+               if (!strcmp(argv[offset + 1], modePtr->name))
+                       break;
+
+       if (!modePtr->name)
+               Usage(argv[0]);
+       if (argc - offset < modePtr->argmin)
+               Usage(argv[0]);
+       if (modePtr->argmax && argc - offset > modePtr->argmax)
+               Usage(argv[0]);
+
+       init_dialog();
+       retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset);
+
+       if (opt_clear) {        /* clear screen before exit */
+               attr_clear(stdscr, LINES, COLS, screen_attr);
+               refresh();
+       }
+       end_dialog();
+
+       exit(retval);
+}
+
+/*
+ * Print program usage
+ */
+static void Usage(const char *name)
+{
+       fprintf(stderr, "\
+\ndialog, by Savio Lam (lam836@cs.cuhk.hk).\
+\n  patched by Stuart Herbert (S.Herbert@shef.ac.uk)\
+\n  modified/gutted for use as a Linux kernel config tool by \
+\n  William Roadcap (roadcapw@cfw.com)\
+\n\
+\n* Display dialog boxes from shell scripts *\
+\n\
+\nUsage: %s --clear\
+\n       %s [--title <title>] [--backtitle <backtitle>] --clear <Box options>\
+\n\
+\nBox options:\
+\n\
+\n  --menu      <text> <height> <width> <menu height> <tag1> <item1>...\
+\n  --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
+\n  --textbox   <file> <height> <width>\
+\n  --inputbox  <text> <height> <width> [<init>]\
+\n  --yesno     <text> <height> <width>\
+\n", name, name);
+       exit(-1);
+}
+
+/*
+ * These are the program jumpers
+ */
+
+int j_menu(const char *t, int ac, const char *const *av)
+{
+       return dialog_menu(t, av[2], atoi(av[3]), atoi(av[4]),
+                          atoi(av[5]), av[6], (ac - 6) / 2, av + 7);
+}
+
+int j_radiolist(const char *t, int ac, const char *const *av)
+{
+       return dialog_checklist(t, av[2], atoi(av[3]), atoi(av[4]),
+                               atoi(av[5]), (ac - 6) / 3, av + 6);
+}
+
+int j_textbox(const char *t, int ac, const char *const *av)
+{
+       return dialog_textbox(t, av[2], atoi(av[3]), atoi(av[4]));
+}
+
+int j_yesno(const char *t, int ac, const char *const *av)
+{
+       return dialog_yesno(t, av[2], atoi(av[3]), atoi(av[4]));
+}
+
+int j_inputbox(const char *t, int ac, const char *const *av)
+{
+       int ret = dialog_inputbox(t, av[2], atoi(av[3]), atoi(av[4]),
+                                 ac == 6 ? av[5] : (char *)NULL);
+       if (ret == 0)
+               fprintf(stderr, dialog_input_result);
+       return ret;
+}
+
+int j_msgbox(const char *t, int ac, const char *const *av)
+{
+       return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 1);
+}
+
+int j_infobox(const char *t, int ac, const char *const *av)
+{
+       return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 0);
+}
diff --git a/kitten/scripts/kconfig/lxdialog/menubox.c b/kitten/scripts/kconfig/lxdialog/menubox.c
new file mode 100644 (file)
index 0000000..bf8052f
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god@clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int choice,
+                          int selected, int hotkey)
+{
+       int j;
+       char *menu_item = malloc(menu_width + 1);
+
+       strncpy(menu_item, item, menu_width - item_x);
+       menu_item[menu_width] = 0;
+       j = first_alpha(menu_item, "YyNnMmHh");
+
+       /* Clear 'residue' of last item */
+       wattrset(win, menubox_attr);
+       wmove(win, choice, 0);
+#if OLD_NCURSES
+       {
+               int i;
+               for (i = 0; i < menu_width; i++)
+                       waddch(win, ' ');
+       }
+#else
+       wclrtoeol(win);
+#endif
+       wattrset(win, selected ? item_selected_attr : item_attr);
+       mvwaddstr(win, choice, item_x, menu_item);
+       if (hotkey) {
+               wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
+               mvwaddch(win, choice, item_x + j, menu_item[j]);
+       }
+       if (selected) {
+               wmove(win, choice, item_x + 1);
+       }
+       free(menu_item);
+       wrefresh(win);
+}
+
+#define print_item(index, choice, selected) \
+do {\
+       int hotkey = (items[(index) * 2][0] != ':'); \
+       do_print_item(menu, items[(index) * 2 + 1], choice, selected, hotkey); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+                        int height)
+{
+       int cur_y, cur_x;
+
+       getyx(win, cur_y, cur_x);
+
+       wmove(win, y, x);
+
+       if (scroll > 0) {
+               wattrset(win, uarrow_attr);
+               waddch(win, ACS_UARROW);
+               waddstr(win, "(-)");
+       } else {
+               wattrset(win, menubox_attr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+
+       y = y + height + 1;
+       wmove(win, y, x);
+       wrefresh(win);
+
+       if ((height < item_no) && (scroll + height < item_no)) {
+               wattrset(win, darrow_attr);
+               waddch(win, ACS_DARROW);
+               waddstr(win, "(+)");
+       } else {
+               wattrset(win, menubox_border_attr);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+               waddch(win, ACS_HLINE);
+       }
+
+       wmove(win, cur_y, cur_x);
+       wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+       int x = width / 2 - 16;
+       int y = height - 2;
+
+       print_button(win, "Select", y, x, selected == 0);
+       print_button(win, " Exit ", y, x + 12, selected == 1);
+       print_button(win, " Help ", y, x + 24, selected == 2);
+
+       wmove(win, y, x + 1 + 12 * selected);
+       wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+       /* Scroll menu up */
+       scrollok(win, TRUE);
+       wscrl(win, n);
+       scrollok(win, FALSE);
+       *scroll = *scroll + n;
+       wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt, int height, int width,
+                int menu_height, const char *current, int item_no,
+                const char *const *items)
+{
+       int i, j, x, y, box_x, box_y;
+       int key = 0, button = 0, scroll = 0, choice = 0;
+       int first_item =  0, max_choice;
+       WINDOW *dialog, *menu;
+       FILE *f;
+
+       max_choice = MIN(menu_height, item_no);
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+       wattrset(dialog, border_attr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dialog_attr);
+       wbkgdset(dialog, dialog_attr & A_COLOR);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dialog_attr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       menu_width = width - 6;
+       box_y = height - menu_height - 5;
+       box_x = (width - menu_width) / 2 - 1;
+
+       /* create new window for the menu */
+       menu = subwin(dialog, menu_height, menu_width,
+                     y + box_y + 1, x + box_x + 1);
+       keypad(menu, TRUE);
+
+       /* draw a box around the menu items */
+       draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+                menubox_border_attr, menubox_attr);
+
+       item_x = (menu_width - 70) / 2;
+
+       /* Set choice to default item */
+       for (i = 0; i < item_no; i++)
+               if (strcmp(current, items[i * 2]) == 0)
+                       choice = i;
+
+       /* get the scroll info from the temp file */
+       if ((f = fopen("lxdialog.scrltmp", "r")) != NULL) {
+               if ((fscanf(f, "%d\n", &scroll) == 1) && (scroll <= choice) &&
+                   (scroll + max_choice > choice) && (scroll >= 0) &&
+                   (scroll + max_choice <= item_no)) {
+                       first_item = scroll;
+                       choice = choice - scroll;
+                       fclose(f);
+               } else {
+                       scroll = 0;
+                       remove("lxdialog.scrltmp");
+                       fclose(f);
+                       f = NULL;
+               }
+       }
+       if ((choice >= max_choice) || (f == NULL && choice >= max_choice / 2)) {
+               if (choice >= item_no - max_choice / 2)
+                       scroll = first_item = item_no - max_choice;
+               else
+                       scroll = first_item = choice - max_choice / 2;
+               choice = choice - scroll;
+       }
+
+       /* Print the menu */
+       for (i = 0; i < max_choice; i++) {
+               print_item(first_item + i, i, i == choice);
+       }
+
+       wnoutrefresh(menu);
+
+       print_arrows(dialog, item_no, scroll,
+                    box_y, box_x + item_x + 1, menu_height);
+
+       print_buttons(dialog, height, width, 0);
+       wmove(menu, choice, item_x + 1);
+       wrefresh(menu);
+
+       while (key != ESC) {
+               key = wgetch(menu);
+
+               if (key < 256 && isalpha(key))
+                       key = tolower(key);
+
+               if (strchr("ynmh", key))
+                       i = max_choice;
+               else {
+                       for (i = choice + 1; i < max_choice; i++) {
+                               j = first_alpha(items[(scroll + i) * 2 + 1], "YyNnMmHh");
+                               if (key == tolower(items[(scroll + i) * 2 + 1][j]))
+                                       break;
+                       }
+                       if (i == max_choice)
+                               for (i = 0; i < max_choice; i++) {
+                                       j = first_alpha(items [(scroll + i) * 2 + 1], "YyNnMmHh");
+                                       if (key == tolower(items[(scroll + i) * 2 + 1][j]))
+                                               break;
+                               }
+               }
+
+               if (i < max_choice ||
+                   key == KEY_UP || key == KEY_DOWN ||
+                   key == '-' || key == '+' ||
+                   key == KEY_PPAGE || key == KEY_NPAGE) {
+                       /* Remove highligt of current item */
+                       print_item(scroll + choice, choice, FALSE);
+
+                       if (key == KEY_UP || key == '-') {
+                               if (choice < 2 && scroll) {
+                                       /* Scroll menu down */
+                                       do_scroll(menu, &scroll, -1);
+
+                                       print_item(scroll, 0, FALSE);
+                               } else
+                                       choice = MAX(choice - 1, 0);
+
+                       } else if (key == KEY_DOWN || key == '+') {
+                               print_item(scroll+choice, choice, FALSE);
+
+                               if ((choice > max_choice - 3) &&
+                                   (scroll + max_choice < item_no)) {
+                                       /* Scroll menu up */
+                                       do_scroll(menu, &scroll, 1);
+
+                                       print_item(scroll+max_choice - 1,
+                                                  max_choice - 1, FALSE);
+                               } else
+                                       choice = MIN(choice + 1, max_choice - 1);
+
+                       } else if (key == KEY_PPAGE) {
+                               scrollok(menu, TRUE);
+                               for (i = 0; (i < max_choice); i++) {
+                                       if (scroll > 0) {
+                                               do_scroll(menu, &scroll, -1);
+                                               print_item(scroll, 0, FALSE);
+                                       } else {
+                                               if (choice > 0)
+                                                       choice--;
+                                       }
+                               }
+
+                       } else if (key == KEY_NPAGE) {
+                               for (i = 0; (i < max_choice); i++) {
+                                       if (scroll + max_choice < item_no) {
+                                               do_scroll(menu, &scroll, 1);
+                                               print_item(scroll+max_choice-1,
+                                                          max_choice - 1, FALSE);
+                                       } else {
+                                               if (choice + 1 < max_choice)
+                                                       choice++;
+                                       }
+                               }
+                       } else
+                               choice = i;
+
+                       print_item(scroll + choice, choice, TRUE);
+
+                       print_arrows(dialog, item_no, scroll,
+                                    box_y, box_x + item_x + 1, menu_height);
+
+                       wnoutrefresh(dialog);
+                       wrefresh(menu);
+
+                       continue;       /* wait for another key press */
+               }
+
+               switch (key) {
+               case KEY_LEFT:
+               case TAB:
+               case KEY_RIGHT:
+                       button = ((key == KEY_LEFT ? --button : ++button) < 0)
+                           ? 2 : (button > 2 ? 0 : button);
+
+                       print_buttons(dialog, height, width, button);
+                       wrefresh(menu);
+                       break;
+               case ' ':
+               case 's':
+               case 'y':
+               case 'n':
+               case 'm':
+               case '/':
+                       /* save scroll info */
+                       if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) {
+                               fprintf(f, "%d\n", scroll);
+                               fclose(f);
+                       }
+                       delwin(dialog);
+                       fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
+                       switch (key) {
+                       case 's':
+                               return 3;
+                       case 'y':
+                               return 3;
+                       case 'n':
+                               return 4;
+                       case 'm':
+                               return 5;
+                       case ' ':
+                               return 6;
+                       case '/':
+                               return 7;
+                       }
+                       return 0;
+               case 'h':
+               case '?':
+                       button = 2;
+               case '\n':
+                       delwin(dialog);
+                       if (button == 2)
+                               fprintf(stderr, "%s \"%s\"\n",
+                                       items[(scroll + choice) * 2],
+                                       items[(scroll + choice) * 2 + 1] +
+                                       first_alpha(items [(scroll + choice) * 2 + 1], ""));
+                       else
+                               fprintf(stderr, "%s\n",
+                                       items[(scroll + choice) * 2]);
+
+                       remove("lxdialog.scrltmp");
+                       return button;
+               case 'e':
+               case 'x':
+                       key = ESC;
+               case ESC:
+                       break;
+               }
+       }
+
+       delwin(dialog);
+       remove("lxdialog.scrltmp");
+       return -1;              /* ESC pressed */
+}
diff --git a/kitten/scripts/kconfig/lxdialog/msgbox.c b/kitten/scripts/kconfig/lxdialog/msgbox.c
new file mode 100644 (file)
index 0000000..7323f54
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  msgbox.c -- implements the message box and info box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display a message box. Program will pause and display an "OK" button
+ * if the parameter 'pause' is non-zero.
+ */
+int dialog_msgbox(const char *title, const char *prompt, int height, int width,
+                  int pause)
+{
+       int i, x, y, key = 0;
+       WINDOW *dialog;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dialog_attr);
+       print_autowrap(dialog, prompt, width - 2, 1, 2);
+
+       if (pause) {
+               wattrset(dialog, border_attr);
+               mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+               for (i = 0; i < width - 2; i++)
+                       waddch(dialog, ACS_HLINE);
+               wattrset(dialog, dialog_attr);
+               waddch(dialog, ACS_RTEE);
+
+               print_button(dialog, "  Ok  ", height - 2, width / 2 - 4, TRUE);
+
+               wrefresh(dialog);
+               while (key != ESC && key != '\n' && key != ' ' &&
+                      key != 'O' && key != 'o' && key != 'X' && key != 'x')
+                       key = wgetch(dialog);
+       } else {
+               key = '\n';
+               wrefresh(dialog);
+       }
+
+       delwin(dialog);
+       return key == ESC ? -1 : 0;
+}
diff --git a/kitten/scripts/kconfig/lxdialog/textbox.c b/kitten/scripts/kconfig/lxdialog/textbox.c
new file mode 100644 (file)
index 0000000..77848bb
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win, int height, int width);
+
+static int hscroll, fd, file_size, bytes_read;
+static int begin_reached = 1, end_reached, page_length;
+static char *buf, *page;
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *file, int height, int width)
+{
+       int i, x, y, cur_x, cur_y, fpos, key = 0;
+       int passed_end;
+       char search_term[MAX_LEN + 1];
+       WINDOW *dialog, *text;
+
+       search_term[0] = '\0';  /* no search term entered yet */
+
+       /* Open input file for reading */
+       if ((fd = open(file, O_RDONLY)) == -1) {
+               endwin();
+               fprintf(stderr, "\nCan't open input file in dialog_textbox().\n");
+               exit(-1);
+       }
+       /* Get file size. Actually, 'file_size' is the real file size - 1,
+          since it's only the last byte offset from the beginning */
+       if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
+               endwin();
+               fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
+               exit(-1);
+       }
+       /* Restore file pointer to beginning of file after getting file size */
+       if (lseek(fd, 0, SEEK_SET) == -1) {
+               endwin();
+               fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+               exit(-1);
+       }
+       /* Allocate space for read buffer */
+       if ((buf = malloc(BUF_SIZE + 1)) == NULL) {
+               endwin();
+               fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
+               exit(-1);
+       }
+       if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+               endwin();
+               fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+               exit(-1);
+       }
+       buf[bytes_read] = '\0'; /* mark end of valid data */
+       page = buf;             /* page is pointer to start of page to be displayed */
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       /* Create window for text region, used for scrolling text */
+       text = subwin(dialog, height - 4, width - 2, y + 1, x + 1);
+       wattrset(text, dialog_attr);
+       wbkgdset(text, dialog_attr & A_COLOR);
+
+       keypad(text, TRUE);
+
+       /* register the new window, along with its borders */
+       draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+       wattrset(dialog, border_attr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dialog_attr);
+       wbkgdset(dialog, dialog_attr & A_COLOR);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
+       wnoutrefresh(dialog);
+       getyx(dialog, cur_y, cur_x);    /* Save cursor position */
+
+       /* Print first page of text */
+       attr_clear(text, height - 4, width - 2, dialog_attr);
+       print_page(text, height - 4, width - 2);
+       print_position(dialog, height, width);
+       wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+       wrefresh(dialog);
+
+       while ((key != ESC) && (key != '\n')) {
+               key = wgetch(dialog);
+               switch (key) {
+               case 'E':       /* Exit */
+               case 'e':
+               case 'X':
+               case 'x':
+                       delwin(dialog);
+                       free(buf);
+                       close(fd);
+                       return 0;
+               case 'g':       /* First page */
+               case KEY_HOME:
+                       if (!begin_reached) {
+                               begin_reached = 1;
+                               /* First page not in buffer? */
+                               if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+                                       endwin();
+                                       fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+                                       exit(-1);
+                               }
+                               if (fpos > bytes_read) {        /* Yes, we have to read it in */
+                                       if (lseek(fd, 0, SEEK_SET) == -1) {
+                                               endwin();
+                                               fprintf(stderr, "\nError moving file pointer in "
+                                                               "dialog_textbox().\n");
+                                               exit(-1);
+                                       }
+                                       if ((bytes_read =
+                                            read(fd, buf, BUF_SIZE)) == -1) {
+                                               endwin();
+                                               fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+                                               exit(-1);
+                                       }
+                                       buf[bytes_read] = '\0';
+                               }
+                               page = buf;
+                               print_page(text, height - 4, width - 2);
+                               print_position(dialog, height, width);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case 'G':       /* Last page */
+               case KEY_END:
+
+                       end_reached = 1;
+                       /* Last page not in buffer? */
+                       if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+                               endwin();
+                               fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+                               exit(-1);
+                       }
+                       if (fpos < file_size) { /* Yes, we have to read it in */
+                               if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
+                                       endwin();
+                                       fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+                                       exit(-1);
+                               }
+                               if ((bytes_read =
+                                    read(fd, buf, BUF_SIZE)) == -1) {
+                                       endwin();
+                                       fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+                                       exit(-1);
+                               }
+                               buf[bytes_read] = '\0';
+                       }
+                       page = buf + bytes_read;
+                       back_lines(height - 4);
+                       print_page(text, height - 4, width - 2);
+                       print_position(dialog, height, width);
+                       wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                       wrefresh(dialog);
+                       break;
+               case 'K':       /* Previous line */
+               case 'k':
+               case KEY_UP:
+                       if (!begin_reached) {
+                               back_lines(page_length + 1);
+
+                               /* We don't call print_page() here but use scrolling to ensure
+                                  faster screen update. However, 'end_reached' and
+                                  'page_length' should still be updated, and 'page' should
+                                  point to start of next page. This is done by calling
+                                  get_line() in the following 'for' loop. */
+                               scrollok(text, TRUE);
+                               wscrl(text, -1);        /* Scroll text region down one line */
+                               scrollok(text, FALSE);
+                               page_length = 0;
+                               passed_end = 0;
+                               for (i = 0; i < height - 4; i++) {
+                                       if (!i) {
+                                               /* print first line of page */
+                                               print_line(text, 0, width - 2);
+                                               wnoutrefresh(text);
+                                       } else
+                                               /* Called to update 'end_reached' and 'page' */
+                                               get_line();
+                                       if (!passed_end)
+                                               page_length++;
+                                       if (end_reached && !passed_end)
+                                               passed_end = 1;
+                               }
+
+                               print_position(dialog, height, width);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case 'B':       /* Previous page */
+               case 'b':
+               case KEY_PPAGE:
+                       if (begin_reached)
+                               break;
+                       back_lines(page_length + height - 4);
+                       print_page(text, height - 4, width - 2);
+                       print_position(dialog, height, width);
+                       wmove(dialog, cur_y, cur_x);
+                       wrefresh(dialog);
+                       break;
+               case 'J':       /* Next line */
+               case 'j':
+               case KEY_DOWN:
+                       if (!end_reached) {
+                               begin_reached = 0;
+                               scrollok(text, TRUE);
+                               scroll(text);   /* Scroll text region up one line */
+                               scrollok(text, FALSE);
+                               print_line(text, height - 5, width - 2);
+                               wnoutrefresh(text);
+                               print_position(dialog, height, width);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case KEY_NPAGE: /* Next page */
+               case ' ':
+                       if (end_reached)
+                               break;
+
+                       begin_reached = 0;
+                       print_page(text, height - 4, width - 2);
+                       print_position(dialog, height, width);
+                       wmove(dialog, cur_y, cur_x);
+                       wrefresh(dialog);
+                       break;
+               case '0':       /* Beginning of line */
+               case 'H':       /* Scroll left */
+               case 'h':
+               case KEY_LEFT:
+                       if (hscroll <= 0)
+                               break;
+
+                       if (key == '0')
+                               hscroll = 0;
+                       else
+                               hscroll--;
+                       /* Reprint current page to scroll horizontally */
+                       back_lines(page_length);
+                       print_page(text, height - 4, width - 2);
+                       wmove(dialog, cur_y, cur_x);
+                       wrefresh(dialog);
+                       break;
+               case 'L':       /* Scroll right */
+               case 'l':
+               case KEY_RIGHT:
+                       if (hscroll >= MAX_LEN)
+                               break;
+                       hscroll++;
+                       /* Reprint current page to scroll horizontally */
+                       back_lines(page_length);
+                       print_page(text, height - 4, width - 2);
+                       wmove(dialog, cur_y, cur_x);
+                       wrefresh(dialog);
+                       break;
+               case ESC:
+                       break;
+               }
+       }
+
+       delwin(dialog);
+       free(buf);
+       close(fd);
+       return -1;              /* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text file. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+       int i, fpos;
+
+       begin_reached = 0;
+       /* We have to distinguish between end_reached and !end_reached
+          since at end of file, the line is not ended by a '\n'.
+          The code inside 'if' basically does a '--page' to move one
+          character backward so as to skip '\n' of the previous line */
+       if (!end_reached) {
+               /* Either beginning of buffer or beginning of file reached? */
+               if (page == buf) {
+                       if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+                               endwin();
+                               fprintf(stderr, "\nError moving file pointer in "
+                                               "back_lines().\n");
+                               exit(-1);
+                       }
+                       if (fpos > bytes_read) {        /* Not beginning of file yet */
+                               /* We've reached beginning of buffer, but not beginning of
+                                  file yet, so read previous part of file into buffer.
+                                  Note that we only move backward for BUF_SIZE/2 bytes,
+                                  but not BUF_SIZE bytes to avoid re-reading again in
+                                  print_page() later */
+                               /* Really possible to move backward BUF_SIZE/2 bytes? */
+                               if (fpos < BUF_SIZE / 2 + bytes_read) {
+                                       /* No, move less then */
+                                       if (lseek(fd, 0, SEEK_SET) == -1) {
+                                               endwin();
+                                               fprintf(stderr, "\nError moving file pointer in "
+                                                               "back_lines().\n");
+                                               exit(-1);
+                                       }
+                                       page = buf + fpos - bytes_read;
+                               } else {        /* Move backward BUF_SIZE/2 bytes */
+                                       if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
+                                               endwin();
+                                               fprintf(stderr, "\nError moving file pointer "
+                                                               "in back_lines().\n");
+                                               exit(-1);
+                                       }
+                                       page = buf + BUF_SIZE / 2;
+                               }
+                               if ((bytes_read =
+                                    read(fd, buf, BUF_SIZE)) == -1) {
+                                       endwin();
+                                       fprintf(stderr, "\nError reading file in back_lines().\n");
+                                       exit(-1);
+                               }
+                               buf[bytes_read] = '\0';
+                       } else {        /* Beginning of file reached */
+                               begin_reached = 1;
+                               return;
+                       }
+               }
+               if (*(--page) != '\n') {        /* '--page' here */
+                       /* Something's wrong... */
+                       endwin();
+                       fprintf(stderr, "\nInternal error in back_lines().\n");
+                       exit(-1);
+               }
+       }
+       /* Go back 'n' lines */
+       for (i = 0; i < n; i++)
+               do {
+                       if (page == buf) {
+                               if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+                                       endwin();
+                                       fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+                                       exit(-1);
+                               }
+                               if (fpos > bytes_read) {
+                                       /* Really possible to move backward BUF_SIZE/2 bytes? */
+                                       if (fpos < BUF_SIZE / 2 + bytes_read) {
+                                               /* No, move less then */
+                                               if (lseek(fd, 0, SEEK_SET) == -1) {
+                                                       endwin();
+                                                       fprintf(stderr, "\nError moving file pointer "
+                                                                       "in back_lines().\n");
+                                                       exit(-1);
+                                               }
+                                               page = buf + fpos - bytes_read;
+                                       } else {        /* Move backward BUF_SIZE/2 bytes */
+                                               if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
+                                                       endwin();
+                                                       fprintf(stderr, "\nError moving file pointer"
+                                                                       " in back_lines().\n");
+                                                       exit(-1);
+                                               }
+                                               page = buf + BUF_SIZE / 2;
+                                       }
+                                       if ((bytes_read =
+                                            read(fd, buf, BUF_SIZE)) == -1) {
+                                               endwin();
+                                               fprintf(stderr, "\nError reading file in "
+                                                               "back_lines().\n");
+                                               exit(-1);
+                                       }
+                                       buf[bytes_read] = '\0';
+                               } else {        /* Beginning of file reached */
+                                       begin_reached = 1;
+                                       return;
+                               }
+                       }
+               } while (*(--page) != '\n');
+       page++;
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+       int i, passed_end = 0;
+
+       page_length = 0;
+       for (i = 0; i < height; i++) {
+               print_line(win, i, width);
+               if (!passed_end)
+                       page_length++;
+               if (end_reached && !passed_end)
+                       passed_end = 1;
+       }
+       wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+       int y, x;
+       char *line;
+
+       line = get_line();
+       line += MIN(strlen(line), hscroll);     /* Scroll horizontally */
+       wmove(win, row, 0);     /* move cursor to correct line */
+       waddch(win, ' ');
+       waddnstr(win, line, MIN(strlen(line), width - 2));
+
+       getyx(win, y, x);
+       /* Clear 'residue' of previous line */
+#if OLD_NCURSES
+       {
+               int i;
+               for (i = 0; i < width - x; i++)
+                       waddch(win, ' ');
+       }
+#else
+       wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+       int i = 0, fpos;
+       static char line[MAX_LEN + 1];
+
+       end_reached = 0;
+       while (*page != '\n') {
+               if (*page == '\0') {
+                       /* Either end of file or end of buffer reached */
+                       if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+                               endwin();
+                               fprintf(stderr, "\nError moving file pointer in "
+                                               "get_line().\n");
+                               exit(-1);
+                       }
+                       if (fpos < file_size) { /* Not end of file yet */
+                               /* We've reached end of buffer, but not end of file yet,
+                                  so read next part of file into buffer */
+                               if ((bytes_read =
+                                    read(fd, buf, BUF_SIZE)) == -1) {
+                                       endwin();
+                                       fprintf(stderr, "\nError reading file in get_line().\n");
+                                       exit(-1);
+                               }
+                               buf[bytes_read] = '\0';
+                               page = buf;
+                       } else {
+                               if (!end_reached)
+                                       end_reached = 1;
+                               break;
+                       }
+               } else if (i < MAX_LEN)
+                       line[i++] = *(page++);
+               else {
+                       /* Truncate lines longer than MAX_LEN characters */
+                       if (i == MAX_LEN)
+                               line[i++] = '\0';
+                       page++;
+               }
+       }
+       if (i <= MAX_LEN)
+               line[i] = '\0';
+       if (!end_reached)
+               page++;         /* move pass '\n' */
+
+       return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win, int height, int width)
+{
+       int fpos, percent;
+
+       if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+               endwin();
+               fprintf(stderr, "\nError moving file pointer in print_position().\n");
+               exit(-1);
+       }
+       wattrset(win, position_indicator_attr);
+       wbkgdset(win, position_indicator_attr & A_COLOR);
+       percent = !file_size ?
+           100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
+       wmove(win, height - 3, width - 9);
+       wprintw(win, "(%3d%%)", percent);
+}
diff --git a/kitten/scripts/kconfig/lxdialog/util.c b/kitten/scripts/kconfig/lxdialog/util.c
new file mode 100644 (file)
index 0000000..f82cebb
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/* use colors by default? */
+bool use_colors = 1;
+
+const char *backtitle = NULL;
+
+/*
+ * Attribute values, default is for mono display
+ */
+chtype attributes[] = {
+       A_NORMAL,               /* screen_attr */
+       A_NORMAL,               /* shadow_attr */
+       A_NORMAL,               /* dialog_attr */
+       A_BOLD,                 /* title_attr */
+       A_NORMAL,               /* border_attr */
+       A_REVERSE,              /* button_active_attr */
+       A_DIM,                  /* button_inactive_attr */
+       A_REVERSE,              /* button_key_active_attr */
+       A_BOLD,                 /* button_key_inactive_attr */
+       A_REVERSE,              /* button_label_active_attr */
+       A_NORMAL,               /* button_label_inactive_attr */
+       A_NORMAL,               /* inputbox_attr */
+       A_NORMAL,               /* inputbox_border_attr */
+       A_NORMAL,               /* searchbox_attr */
+       A_BOLD,                 /* searchbox_title_attr */
+       A_NORMAL,               /* searchbox_border_attr */
+       A_BOLD,                 /* position_indicator_attr */
+       A_NORMAL,               /* menubox_attr */
+       A_NORMAL,               /* menubox_border_attr */
+       A_NORMAL,               /* item_attr */
+       A_REVERSE,              /* item_selected_attr */
+       A_BOLD,                 /* tag_attr */
+       A_REVERSE,              /* tag_selected_attr */
+       A_BOLD,                 /* tag_key_attr */
+       A_REVERSE,              /* tag_key_selected_attr */
+       A_BOLD,                 /* check_attr */
+       A_REVERSE,              /* check_selected_attr */
+       A_BOLD,                 /* uarrow_attr */
+       A_BOLD                  /* darrow_attr */
+};
+
+#include "colors.h"
+
+/*
+ * Table of color values
+ */
+int color_table[][3] = {
+       {SCREEN_FG, SCREEN_BG, SCREEN_HL},
+       {SHADOW_FG, SHADOW_BG, SHADOW_HL},
+       {DIALOG_FG, DIALOG_BG, DIALOG_HL},
+       {TITLE_FG, TITLE_BG, TITLE_HL},
+       {BORDER_FG, BORDER_BG, BORDER_HL},
+       {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
+       {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
+       {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
+       {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG,
+        BUTTON_KEY_INACTIVE_HL},
+       {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG,
+        BUTTON_LABEL_ACTIVE_HL},
+       {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
+        BUTTON_LABEL_INACTIVE_HL},
+       {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
+       {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
+       {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
+       {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
+       {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
+       {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
+       {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
+       {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
+       {ITEM_FG, ITEM_BG, ITEM_HL},
+       {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
+       {TAG_FG, TAG_BG, TAG_HL},
+       {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
+       {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
+       {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
+       {CHECK_FG, CHECK_BG, CHECK_HL},
+       {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
+       {UARROW_FG, UARROW_BG, UARROW_HL},
+       {DARROW_FG, DARROW_BG, DARROW_HL},
+};                             /* color_table */
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+       int i, j;
+
+       wattrset(win, attr);
+       for (i = 0; i < height; i++) {
+               wmove(win, i, 0);
+               for (j = 0; j < width; j++)
+                       waddch(win, ' ');
+       }
+       touchwin(win);
+}
+
+void dialog_clear(void)
+{
+       attr_clear(stdscr, LINES, COLS, screen_attr);
+       /* Display background title if it exists ... - SLH */
+       if (backtitle != NULL) {
+               int i;
+
+               wattrset(stdscr, screen_attr);
+               mvwaddstr(stdscr, 0, 1, (char *)backtitle);
+               wmove(stdscr, 1, 1);
+               for (i = 1; i < COLS - 1; i++)
+                       waddch(stdscr, ACS_HLINE);
+       }
+       wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+void init_dialog(void)
+{
+       initscr();              /* Init curses */
+       keypad(stdscr, TRUE);
+       cbreak();
+       noecho();
+
+       if (use_colors)         /* Set up colors */
+               color_setup();
+
+       dialog_clear();
+}
+
+/*
+ * Setup for color display
+ */
+void color_setup(void)
+{
+       int i;
+
+       if (has_colors()) {     /* Terminal supports color? */
+               start_color();
+
+               /* Initialize color pairs */
+               for (i = 0; i < ATTRIBUTE_COUNT; i++)
+                       init_pair(i + 1, color_table[i][0], color_table[i][1]);
+
+               /* Setup color attributes */
+               for (i = 0; i < ATTRIBUTE_COUNT; i++)
+                       attributes[i] = C_ATTR(color_table[i][2], i + 1);
+       }
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(void)
+{
+       endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+       if (title) {
+               int tlen = MIN(width - 2, strlen(title));
+               wattrset(dialog, title_attr);
+               mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+               mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+               waddch(dialog, ' ');
+       }
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+       int newl, cur_x, cur_y;
+       int i, prompt_len, room, wlen;
+       char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+       strcpy(tempstr, prompt);
+
+       prompt_len = strlen(tempstr);
+
+       /*
+        * Remove newlines
+        */
+       for (i = 0; i < prompt_len; i++) {
+               if (tempstr[i] == '\n')
+                       tempstr[i] = ' ';
+       }
+
+       if (prompt_len <= width - x * 2) {      /* If prompt is short */
+               wmove(win, y, (width - prompt_len) / 2);
+               waddstr(win, tempstr);
+       } else {
+               cur_x = x;
+               cur_y = y;
+               newl = 1;
+               word = tempstr;
+               while (word && *word) {
+                       sp = index(word, ' ');
+                       if (sp)
+                               *sp++ = 0;
+
+                       /* Wrap to next line if either the word does not fit,
+                          or it is the first word of a new sentence, and it is
+                          short, and the next word does not fit. */
+                       room = width - cur_x;
+                       wlen = strlen(word);
+                       if (wlen > room ||
+                           (newl && wlen < 4 && sp
+                            && wlen + 1 + strlen(sp) > room
+                            && (!(sp2 = index(sp, ' '))
+                                || wlen + 1 + (sp2 - sp) > room))) {
+                               cur_y++;
+                               cur_x = x;
+                       }
+                       wmove(win, cur_y, cur_x);
+                       waddstr(win, word);
+                       getyx(win, cur_y, cur_x);
+                       cur_x++;
+                       if (sp && *sp == ' ') {
+                               cur_x++;        /* double space */
+                               while (*++sp == ' ') ;
+                               newl = 1;
+                       } else
+                               newl = 0;
+                       word = sp;
+               }
+       }
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+       int i, temp;
+
+       wmove(win, y, x);
+       wattrset(win, selected ? button_active_attr : button_inactive_attr);
+       waddstr(win, "<");
+       temp = strspn(label, " ");
+       label += temp;
+       wattrset(win, selected ? button_label_active_attr
+                : button_label_inactive_attr);
+       for (i = 0; i < temp; i++)
+               waddch(win, ' ');
+       wattrset(win, selected ? button_key_active_attr
+                : button_key_inactive_attr);
+       waddch(win, label[0]);
+       wattrset(win, selected ? button_label_active_attr
+                : button_label_inactive_attr);
+       waddstr(win, (char *)label + 1);
+       wattrset(win, selected ? button_active_attr : button_inactive_attr);
+       waddstr(win, ">");
+       wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+        chtype box, chtype border)
+{
+       int i, j;
+
+       wattrset(win, 0);
+       for (i = 0; i < height; i++) {
+               wmove(win, y + i, x);
+               for (j = 0; j < width; j++)
+                       if (!i && !j)
+                               waddch(win, border | ACS_ULCORNER);
+                       else if (i == height - 1 && !j)
+                               waddch(win, border | ACS_LLCORNER);
+                       else if (!i && j == width - 1)
+                               waddch(win, box | ACS_URCORNER);
+                       else if (i == height - 1 && j == width - 1)
+                               waddch(win, box | ACS_LRCORNER);
+                       else if (!i)
+                               waddch(win, border | ACS_HLINE);
+                       else if (i == height - 1)
+                               waddch(win, box | ACS_HLINE);
+                       else if (!j)
+                               waddch(win, border | ACS_VLINE);
+                       else if (j == width - 1)
+                               waddch(win, box | ACS_VLINE);
+                       else
+                               waddch(win, box | ' ');
+       }
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+       int i;
+
+       if (has_colors()) {     /* Whether terminal supports color? */
+               wattrset(win, shadow_attr);
+               wmove(win, y + height, x + 2);
+               for (i = 0; i < width; i++)
+                       waddch(win, winch(win) & A_CHARTEXT);
+               for (i = y + 1; i < y + height + 1; i++) {
+                       wmove(win, i, x + width);
+                       waddch(win, winch(win) & A_CHARTEXT);
+                       waddch(win, winch(win) & A_CHARTEXT);
+               }
+               wnoutrefresh(win);
+       }
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+       int i, in_paren = 0, c;
+
+       for (i = 0; i < strlen(string); i++) {
+               c = tolower(string[i]);
+
+               if (strchr("<[(", c))
+                       ++in_paren;
+               if (strchr(">])", c) && in_paren > 0)
+                       --in_paren;
+
+               if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+                       return i;
+       }
+
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/lxdialog/yesno.c b/kitten/scripts/kconfig/lxdialog/yesno.c
new file mode 100644 (file)
index 0000000..cb2568a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+       int x = width / 2 - 10;
+       int y = height - 2;
+
+       print_button(dialog, " Yes ", y, x, selected == 0);
+       print_button(dialog, "  No  ", y, x + 13, selected == 1);
+
+       wmove(dialog, y, x + 1 + 13 * selected);
+       wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+       int i, x, y, key = 0, button = 0;
+       WINDOW *dialog;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - height) / 2;
+
+       draw_shadow(stdscr, y, x, height, width);
+
+       dialog = newwin(height, width, y, x);
+       keypad(dialog, TRUE);
+
+       draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+       wattrset(dialog, border_attr);
+       mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+       for (i = 0; i < width - 2; i++)
+               waddch(dialog, ACS_HLINE);
+       wattrset(dialog, dialog_attr);
+       waddch(dialog, ACS_RTEE);
+
+       print_title(dialog, title, width);
+
+       wattrset(dialog, dialog_attr);
+       print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+       print_buttons(dialog, height, width, 0);
+
+       while (key != ESC) {
+               key = wgetch(dialog);
+               switch (key) {
+               case 'Y':
+               case 'y':
+                       delwin(dialog);
+                       return 0;
+               case 'N':
+               case 'n':
+                       delwin(dialog);
+                       return 1;
+
+               case TAB:
+               case KEY_LEFT:
+               case KEY_RIGHT:
+                       button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+                       print_buttons(dialog, height, width, button);
+                       wrefresh(dialog);
+                       break;
+               case ' ':
+               case '\n':
+                       delwin(dialog);
+                       return button;
+               case ESC:
+                       break;
+               }
+       }
+
+       delwin(dialog);
+       return -1;              /* ESC pressed */
+}
diff --git a/kitten/scripts/kconfig/mconf.c b/kitten/scripts/kconfig/mconf.c
new file mode 100644 (file)
index 0000000..d7d4962
--- /dev/null
@@ -0,0 +1,1098 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char menu_backtitle[128];
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"Some kernel features may be built directly into the kernel.\n"
+"Some may be made into loadable runtime modules.  Some features\n"
+"may be completely removed altogether.  There are also certain\n"
+"kernel parameters which are not really features, but must be\n"
+"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"\n"
+"Menu items beginning with [*], <M> or [ ] represent features\n"
+"configured to be built in, modularized or removed respectively.\n"
+"Pointed brackets <> represent module capable features.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+"   you wish to change or submenu wish to select and press <Enter>.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Shortcut: Press the option's highlighted letter (hotkey).\n"
+"             Pressing a hotkey more than once will sequence\n"
+"             through all visible items which use that hotkey.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+"             using those letters.  You may press a single <ESC>, but\n"
+"             there is a delayed response which you may find annoying.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+"   <Exit> and <Help>\n"
+"\n"
+"o  To get help with an item, use the cursor keys to highlight <Help>\n"
+"   and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, use the cursor keys to highlight\n"
+"   <Help> and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+"   <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
+"   and press <ENTER>.  You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different kernel configurations.\n"
+"\n"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the kernel options listed in a single\n"
+"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
+"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"),
+menu_instructions[] = N_(
+       "Arrow keys navigate the menu.  "
+       "<Enter> selects submenus --->.  "
+       "Highlighted letters are hotkeys.  "
+       "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
+       "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+       "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
+       "Use the arrow keys to navigate this window or "
+       "press the hotkey of the item you wish to select "
+       "followed by the <SPACE BAR>. "
+       "Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+       "Please enter a decimal value. "
+       "Fractions will not be accepted.  "
+       "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+       "Please enter a hexadecimal value. "
+       "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+       "Please enter a string value. "
+       "Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+       "This feature depends on another which has been configured as a module.\n"
+       "As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+       "There is no help available for this kernel option.\n"),
+load_config_text[] = N_(
+       "Enter the name of the configuration file you wish to load.  "
+       "Accept the name shown to restore the configuration you "
+       "last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+       "\n"
+       "For various reasons, one may wish to keep several different kernel\n"
+       "configurations available on a single machine.\n"
+       "\n"
+       "If you have saved a previous configuration in a file other than the\n"
+       "kernel's default, entering the name of the file here will allow you\n"
+       "to modify that configuration.\n"
+       "\n"
+       "If you are uncertain, then you have probably never used alternate\n"
+       "configuration files.  You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+       "Enter a filename to which this configuration should be saved "
+       "as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+       "\n"
+       "For various reasons, one may wish to keep different kernel\n"
+       "configurations available on a single machine.\n"
+       "\n"
+       "Entering a file name here will allow you to later retrieve, modify\n"
+       "and use the current configuration as an alternate to whatever\n"
+       "configuration options you have selected at that time.\n"
+       "\n"
+       "If you are uncertain what all this means then you should probably\n"
+       "leave this blank.\n"),
+search_help[] = N_(
+       "\n"
+       "Search for CONFIG_ symbols and display their relations.\n"
+       "Regular expressions are allowed.\n"
+       "Example: search for \"^FOO\"\n"
+       "Result:\n"
+       "-----------------------------------------------------------------\n"
+       "Symbol: FOO [=m]\n"
+       "Prompt: Foo bus is used to drive the bar HW\n"
+       "Defined at drivers/pci/Kconfig:47\n"
+       "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+       "Location:\n"
+       "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+       "    -> PCI support (PCI [=y])\n"
+       "      -> PCI access mode (<choice> [=y])\n"
+       "Selects: LIBCRC32\n"
+       "Selected by: BAR\n"
+       "-----------------------------------------------------------------\n"
+       "o The line 'Prompt:' shows the text used in the menu structure for\n"
+       "  this CONFIG_ symbol\n"
+       "o The 'Defined at' line tell at what file / line number the symbol\n"
+       "  is defined\n"
+       "o The 'Depends on:' line tell what symbols needs to be defined for\n"
+       "  this symbol to be visible in the menu (selectable)\n"
+       "o The 'Location:' lines tell where in the menu structure this symbol\n"
+       "  is located\n"
+       "    A location followed by a [=y] indicate that this is a selectable\n"
+       "    menu item - and current value is displayed inside brackets.\n"
+       "o The 'Selects:' line tell what symbol will be automatically\n"
+       "  selected if this symbol is selected (y or m)\n"
+       "o The 'Selected by' line tell what symbol has selected this symbol\n"
+       "\n"
+       "Only relevant lines are shown.\n"
+       "\n\n"
+       "Search examples:\n"
+       "Examples: USB  => find all CONFIG_ symbols containing USB\n"
+       "          ^USB => find all CONFIG_ symbols starting with USB\n"
+       "          USB$ => find all CONFIG_ symbols ending with USB\n"
+       "\n");
+
+static char buf[4096], *bufptr = buf;
+static char input_buf[4096];
+static char filename[PATH_MAX+1] = ".config";
+static char *args[1024], **argptr = args;
+static int indent;
+static struct termios ios_org;
+static int rows = 0, cols = 0;
+static struct menu *current_menu;
+static int child_count;
+static int do_resize;
+static int single_menu_mode;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+static void show_file(const char *filename, const char *title, int r, int c);
+
+static void cprint_init(void);
+static int cprint1(const char *fmt, ...);
+static void cprint_done(void);
+static int cprint(const char *fmt, ...);
+
+static void init_wsize(void)
+{
+       struct winsize ws;
+       char *env;
+
+       if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
+               rows = ws.ws_row;
+               cols = ws.ws_col;
+       }
+
+       if (!rows) {
+               env = getenv("LINES");
+               if (env)
+                       rows = atoi(env);
+               if (!rows)
+                       rows = 24;
+       }
+       if (!cols) {
+               env = getenv("COLUMNS");
+               if (env)
+                       cols = atoi(env);
+               if (!cols)
+                       cols = 80;
+       }
+
+       if (rows < 19 || cols < 80) {
+               fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+               fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+               exit(1);
+       }
+
+       rows -= 4;
+       cols -= 5;
+}
+
+static void cprint_init(void)
+{
+       bufptr = buf;
+       argptr = args;
+       memset(args, 0, sizeof(args));
+       indent = 0;
+       child_count = 0;
+       cprint("./scripts/kconfig/lxdialog/lxdialog");
+       cprint("--backtitle");
+       cprint(menu_backtitle);
+}
+
+static int cprint1(const char *fmt, ...)
+{
+       va_list ap;
+       int res;
+
+       if (!*argptr)
+               *argptr = bufptr;
+       va_start(ap, fmt);
+       res = vsprintf(bufptr, fmt, ap);
+       va_end(ap);
+       bufptr += res;
+
+       return res;
+}
+
+static void cprint_done(void)
+{
+       *bufptr++ = 0;
+       argptr++;
+}
+
+static int cprint(const char *fmt, ...)
+{
+       va_list ap;
+       int res;
+
+       *argptr++ = bufptr;
+       va_start(ap, fmt);
+       res = vsprintf(bufptr, fmt, ap);
+       va_end(ap);
+       bufptr += res;
+       *bufptr++ = 0;
+
+       return res;
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+       int i, j;
+       struct menu *submenu[8], *menu;
+
+       str_printf(r, "Prompt: %s\n", prop->text);
+       str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
+               prop->menu->lineno);
+       if (!expr_is_yes(prop->visible.expr)) {
+               str_append(r, "  Depends on: ");
+               expr_gstr_print(prop->visible.expr, r);
+               str_append(r, "\n");
+       }
+       menu = prop->menu->parent;
+       for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+               submenu[i++] = menu;
+       if (i > 0) {
+               str_printf(r, "  Location:\n");
+               for (j = 4; --i >= 0; j += 2) {
+                       menu = submenu[i];
+                       str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
+                       if (menu->sym) {
+                               str_printf(r, " (%s [=%s])", menu->sym->name ?
+                                       menu->sym->name : "<choice>",
+                                       sym_get_string_value(menu->sym));
+                       }
+                       str_append(r, "\n");
+               }
+       }
+}
+
+static void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+       bool hit;
+       struct property *prop;
+
+       str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+                                      sym_get_string_value(sym));
+       for_all_prompts(sym, prop)
+               get_prompt_str(r, prop);
+       hit = false;
+       for_all_properties(sym, prop, P_SELECT) {
+               if (!hit) {
+                       str_append(r, "  Selects: ");
+                       hit = true;
+               } else
+                       str_printf(r, " && ");
+               expr_gstr_print(prop->expr, r);
+       }
+       if (hit)
+               str_append(r, "\n");
+       if (sym->rev_dep.expr) {
+               str_append(r, "  Selected by: ");
+               expr_gstr_print(sym->rev_dep.expr, r);
+               str_append(r, "\n");
+       }
+       str_append(r, "\n\n");
+}
+
+static struct gstr get_relations_str(struct symbol **sym_arr)
+{
+       struct symbol *sym;
+       struct gstr res = str_new();
+       int i;
+
+       for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+               get_symbol_str(&res, sym);
+       if (!i)
+               str_append(&res, "No matches found.\n");
+       return res;
+}
+
+pid_t pid;
+
+static void winch_handler(int sig)
+{
+       if (!do_resize) {
+               kill(pid, SIGINT);
+               do_resize = 1;
+       }
+}
+
+static int exec_conf(void)
+{
+       int pipefd[2], stat, size;
+       struct sigaction sa;
+       sigset_t sset, osset;
+
+       sigemptyset(&sset);
+       sigaddset(&sset, SIGINT);
+       sigprocmask(SIG_BLOCK, &sset, &osset);
+
+       signal(SIGINT, SIG_DFL);
+
+       sa.sa_handler = winch_handler;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGWINCH, &sa, NULL);
+
+       *argptr++ = NULL;
+
+       pipe(pipefd);
+       pid = fork();
+       if (pid == 0) {
+               sigprocmask(SIG_SETMASK, &osset, NULL);
+               dup2(pipefd[1], 2);
+               close(pipefd[0]);
+               close(pipefd[1]);
+               execv(args[0], args);
+               _exit(EXIT_FAILURE);
+       }
+
+       close(pipefd[1]);
+       bufptr = input_buf;
+       while (1) {
+               size = input_buf + sizeof(input_buf) - bufptr;
+               size = read(pipefd[0], bufptr, size);
+               if (size <= 0) {
+                       if (size < 0) {
+                               if (errno == EINTR || errno == EAGAIN)
+                                       continue;
+                               perror("read");
+                       }
+                       break;
+               }
+               bufptr += size;
+       }
+       *bufptr++ = 0;
+       close(pipefd[0]);
+       waitpid(pid, &stat, 0);
+
+       if (do_resize) {
+               init_wsize();
+               do_resize = 0;
+               sigprocmask(SIG_SETMASK, &osset, NULL);
+               return -1;
+       }
+       if (WIFSIGNALED(stat)) {
+               printf("\finterrupted(%d)\n", WTERMSIG(stat));
+               exit(1);
+       }
+#if 0
+       printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
+       sleep(1);
+#endif
+       sigpending(&sset);
+       if (sigismember(&sset, SIGINT)) {
+               printf("\finterrupted\n");
+               exit(1);
+       }
+       sigprocmask(SIG_SETMASK, &osset, NULL);
+
+       return WEXITSTATUS(stat);
+}
+
+static void search_conf(void)
+{
+       struct symbol **sym_arr;
+       int stat;
+       struct gstr res;
+
+again:
+       cprint_init();
+       cprint("--title");
+       cprint(_("Search Configuration Parameter"));
+       cprint("--inputbox");
+       cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
+       cprint("10");
+       cprint("75");
+       cprint("");
+       stat = exec_conf();
+       if (stat < 0)
+               goto again;
+       switch (stat) {
+       case 0:
+               break;
+       case 1:
+               show_helptext(_("Search Configuration"), search_help);
+               goto again;
+       default:
+               return;
+       }
+
+       sym_arr = sym_re_search(input_buf);
+       res = get_relations_str(sym_arr);
+       free(sym_arr);
+       show_textbox(_("Search Results"), str_get(&res), 0, 0);
+       str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+       int type, tmp, doint = 2;
+       tristate val;
+       char ch;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       if (!sym) {
+               if (prop && menu != current_menu) {
+                       const char *prompt = menu_get_prompt(menu);
+                       switch (prop->type) {
+                       case P_MENU:
+                               child_count++;
+                               cprint("m%p", menu);
+
+                               if (single_menu_mode) {
+                                       cprint1("%s%*c%s",
+                                               menu->data ? "-->" : "++>",
+                                               indent + 1, ' ', prompt);
+                               } else
+                                       cprint1("   %*c%s  --->", indent + 1, ' ', prompt);
+
+                               cprint_done();
+                               if (single_menu_mode && menu->data)
+                                       goto conf_childs;
+                               return;
+                       default:
+                               if (prompt) {
+                                       child_count++;
+                                       cprint(":%p", menu);
+                                       cprint("---%*c%s", indent + 1, ' ', prompt);
+                               }
+                       }
+               } else
+                       doint = 0;
+               goto conf_childs;
+       }
+
+       type = sym_get_type(sym);
+       if (sym_is_choice(sym)) {
+               struct symbol *def_sym = sym_get_choice_value(sym);
+               struct menu *def_menu = NULL;
+
+               child_count++;
+               for (child = menu->list; child; child = child->next) {
+                       if (menu_is_visible(child) && child->sym == def_sym)
+                               def_menu = child;
+               }
+
+               val = sym_get_tristate_value(sym);
+               if (sym_is_changable(sym)) {
+                       cprint("t%p", menu);
+                       switch (type) {
+                       case S_BOOLEAN:
+                               cprint1("[%c]", val == no ? ' ' : '*');
+                               break;
+                       case S_TRISTATE:
+                               switch (val) {
+                               case yes: ch = '*'; break;
+                               case mod: ch = 'M'; break;
+                               default:  ch = ' '; break;
+                               }
+                               cprint1("<%c>", ch);
+                               break;
+                       }
+               } else {
+                       cprint("%c%p", def_menu ? 't' : ':', menu);
+                       cprint1("   ");
+               }
+
+               cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+               if (val == yes) {
+                       if (def_menu) {
+                               cprint1(" (%s)", menu_get_prompt(def_menu));
+                               cprint1("  --->");
+                               cprint_done();
+                               if (def_menu->list) {
+                                       indent += 2;
+                                       build_conf(def_menu);
+                                       indent -= 2;
+                               }
+                       } else
+                               cprint_done();
+                       return;
+               }
+               cprint_done();
+       } else {
+               if (menu == current_menu) {
+                       cprint(":%p", menu);
+                       cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+                       goto conf_childs;
+               }
+               child_count++;
+               val = sym_get_tristate_value(sym);
+               if (sym_is_choice_value(sym) && val == yes) {
+                       cprint(":%p", menu);
+                       cprint1("   ");
+               } else {
+                       switch (type) {
+                       case S_BOOLEAN:
+                               cprint("t%p", menu);
+                               if (sym_is_changable(sym))
+                                       cprint1("[%c]", val == no ? ' ' : '*');
+                               else
+                                       cprint1("---");
+                               break;
+                       case S_TRISTATE:
+                               cprint("t%p", menu);
+                               switch (val) {
+                               case yes: ch = '*'; break;
+                               case mod: ch = 'M'; break;
+                               default:  ch = ' '; break;
+                               }
+                               if (sym_is_changable(sym))
+                                       cprint1("<%c>", ch);
+                               else
+                                       cprint1("---");
+                               break;
+                       default:
+                               cprint("s%p", menu);
+                               tmp = cprint1("(%s)", sym_get_string_value(sym));
+                               tmp = indent - tmp + 4;
+                               if (tmp < 0)
+                                       tmp = 0;
+                               cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+                                       (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                                       "" : " (NEW)");
+                               cprint_done();
+                               goto conf_childs;
+                       }
+               }
+               cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+                       (sym_has_value(sym) || !sym_is_changable(sym)) ?
+                       "" : " (NEW)");
+               if (menu->prompt->type == P_MENU) {
+                       cprint1("  --->");
+                       cprint_done();
+                       return;
+               }
+               cprint_done();
+       }
+
+conf_childs:
+       indent += doint;
+       for (child = menu->list; child; child = child->next)
+               build_conf(child);
+       indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+       struct menu *submenu;
+       const char *prompt = menu_get_prompt(menu);
+       struct symbol *sym;
+       char active_entry[40];
+       int stat, type, i;
+
+       unlink("lxdialog.scrltmp");
+       active_entry[0] = 0;
+       while (1) {
+               cprint_init();
+               cprint("--title");
+               cprint("%s", prompt ? prompt : _("Main Menu"));
+               cprint("--menu");
+               cprint(_(menu_instructions));
+               cprint("%d", rows);
+               cprint("%d", cols);
+               cprint("%d", rows - 10);
+               cprint("%s", active_entry);
+               current_menu = menu;
+               build_conf(menu);
+               if (!child_count)
+                       break;
+               if (menu == &rootmenu) {
+                       cprint(":");
+                       cprint("--- ");
+                       cprint("L");
+                       cprint(_("    Load an Alternate Configuration File"));
+                       cprint("S");
+                       cprint(_("    Save Configuration to an Alternate File"));
+               }
+               stat = exec_conf();
+               if (stat < 0)
+                       continue;
+
+               if (stat == 1 || stat == 255)
+                       break;
+
+               type = input_buf[0];
+               if (!type)
+                       continue;
+
+               for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
+                       ;
+               if (i >= sizeof(active_entry))
+                       i = sizeof(active_entry) - 1;
+               input_buf[i] = 0;
+               strcpy(active_entry, input_buf);
+
+               sym = NULL;
+               submenu = NULL;
+               if (sscanf(input_buf + 1, "%p", &submenu) == 1)
+                       sym = submenu->sym;
+
+               switch (stat) {
+               case 0:
+                       switch (type) {
+                       case 'm':
+                               if (single_menu_mode)
+                                       submenu->data = (void *) (long) !submenu->data;
+                               else
+                                       conf(submenu);
+                               break;
+                       case 't':
+                               if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+                                       conf_choice(submenu);
+                               else if (submenu->prompt->type == P_MENU)
+                                       conf(submenu);
+                               break;
+                       case 's':
+                               conf_string(submenu);
+                               break;
+                       case 'L':
+                               conf_load();
+                               break;
+                       case 'S':
+                               conf_save();
+                               break;
+                       }
+                       break;
+               case 2:
+                       if (sym)
+                               show_help(submenu);
+                       else
+                               show_helptext("README", _(mconf_readme));
+                       break;
+               case 3:
+                       if (type == 't') {
+                               if (sym_set_tristate_value(sym, yes))
+                                       break;
+                               if (sym_set_tristate_value(sym, mod))
+                                       show_textbox(NULL, setmod_text, 6, 74);
+                       }
+                       break;
+               case 4:
+                       if (type == 't')
+                               sym_set_tristate_value(sym, no);
+                       break;
+               case 5:
+                       if (type == 't')
+                               sym_set_tristate_value(sym, mod);
+                       break;
+               case 6:
+                       if (type == 't')
+                               sym_toggle_tristate_value(sym);
+                       else if (type == 'm')
+                               conf(submenu);
+                       break;
+               case 7:
+                       search_conf();
+                       break;
+               }
+       }
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+       int fd;
+
+       fd = creat(".help.tmp", 0777);
+       write(fd, text, strlen(text));
+       close(fd);
+       show_file(".help.tmp", title, r, c);
+       unlink(".help.tmp");
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+       show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+       struct gstr help = str_new();
+       struct symbol *sym = menu->sym;
+
+       if (sym->help)
+       {
+               if (sym->name) {
+                       str_printf(&help, "CONFIG_%s:\n\n", sym->name);
+                       str_append(&help, _(sym->help));
+                       str_append(&help, "\n");
+               }
+       } else {
+               str_append(&help, nohelp_text);
+       }
+       get_symbol_str(&help, sym);
+       show_helptext(menu_get_prompt(menu), str_get(&help));
+       str_free(&help);
+}
+
+static void show_file(const char *filename, const char *title, int r, int c)
+{
+       do {
+               cprint_init();
+               if (title) {
+                       cprint("--title");
+                       cprint("%s", title);
+               }
+               cprint("--textbox");
+               cprint("%s", filename);
+               cprint("%d", r ? r : rows);
+               cprint("%d", c ? c : cols);
+       } while (exec_conf() < 0);
+}
+
+static void conf_choice(struct menu *menu)
+{
+       const char *prompt = menu_get_prompt(menu);
+       struct menu *child;
+       struct symbol *active;
+       int stat;
+
+       active = sym_get_choice_value(menu->sym);
+       while (1) {
+               cprint_init();
+               cprint("--title");
+               cprint("%s", prompt ? prompt : _("Main Menu"));
+               cprint("--radiolist");
+               cprint(_(radiolist_instructions));
+               cprint("15");
+               cprint("70");
+               cprint("6");
+
+               current_menu = menu;
+               for (child = menu->list; child; child = child->next) {
+                       if (!menu_is_visible(child))
+                               continue;
+                       cprint("%p", child);
+                       cprint("%s", menu_get_prompt(child));
+                       if (child->sym == sym_get_choice_value(menu->sym))
+                               cprint("ON");
+                       else if (child->sym == active)
+                               cprint("SELECTED");
+                       else
+                               cprint("OFF");
+               }
+
+               stat = exec_conf();
+               switch (stat) {
+               case 0:
+                       if (sscanf(input_buf, "%p", &child) != 1)
+                               break;
+                       sym_set_tristate_value(child->sym, yes);
+                       return;
+               case 1:
+                       if (sscanf(input_buf, "%p", &child) == 1) {
+                               show_help(child);
+                               active = child->sym;
+                       } else
+                               show_help(menu);
+                       break;
+               case 255:
+                       return;
+               }
+       }
+}
+
+static void conf_string(struct menu *menu)
+{
+       const char *prompt = menu_get_prompt(menu);
+       int stat;
+
+       while (1) {
+               cprint_init();
+               cprint("--title");
+               cprint("%s", prompt ? prompt : _("Main Menu"));
+               cprint("--inputbox");
+               switch (sym_get_type(menu->sym)) {
+               case S_INT:
+                       cprint(_(inputbox_instructions_int));
+                       break;
+               case S_HEX:
+                       cprint(_(inputbox_instructions_hex));
+                       break;
+               case S_STRING:
+                       cprint(_(inputbox_instructions_string));
+                       break;
+               default:
+                       /* panic? */;
+               }
+               cprint("10");
+               cprint("75");
+               cprint("%s", sym_get_string_value(menu->sym));
+               stat = exec_conf();
+               switch (stat) {
+               case 0:
+                       if (sym_set_string_value(menu->sym, input_buf))
+                               return;
+                       show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+                       break;
+               case 1:
+                       show_help(menu);
+                       break;
+               case 255:
+                       return;
+               }
+       }
+}
+
+static void conf_load(void)
+{
+       int stat;
+
+       while (1) {
+               cprint_init();
+               cprint("--inputbox");
+               cprint(load_config_text);
+               cprint("11");
+               cprint("55");
+               cprint("%s", filename);
+               stat = exec_conf();
+               switch(stat) {
+               case 0:
+                       if (!input_buf[0])
+                               return;
+                       if (!conf_read(input_buf))
+                               return;
+                       show_textbox(NULL, _("File does not exist!"), 5, 38);
+                       break;
+               case 1:
+                       show_helptext(_("Load Alternate Configuration"), load_config_help);
+                       break;
+               case 255:
+                       return;
+               }
+       }
+}
+
+static void conf_save(void)
+{
+       int stat;
+
+       while (1) {
+               cprint_init();
+               cprint("--inputbox");
+               cprint(save_config_text);
+               cprint("11");
+               cprint("55");
+               cprint("%s", filename);
+               stat = exec_conf();
+               switch(stat) {
+               case 0:
+                       if (!input_buf[0])
+                               return;
+                       if (!conf_write(input_buf))
+                               return;
+                       show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
+                       break;
+               case 1:
+                       show_helptext(_("Save Alternate Configuration"), save_config_help);
+                       break;
+               case 255:
+                       return;
+               }
+       }
+}
+
+static void conf_cleanup(void)
+{
+       tcsetattr(1, TCSAFLUSH, &ios_org);
+       unlink(".help.tmp");
+       unlink("lxdialog.scrltmp");
+}
+
+int main(int ac, char **av)
+{
+       struct symbol *sym;
+       char *mode;
+       int stat;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       conf_parse(av[1]);
+       conf_read(NULL);
+
+       sym = sym_lookup("KERNELVERSION", 0);
+       sym_calc_value(sym);
+       sprintf(menu_backtitle, _("LWK Kernel v%s Configuration"),
+               sym_get_string_value(sym));
+
+       mode = getenv("MENUCONFIG_MODE");
+       if (mode) {
+               if (!strcasecmp(mode, "single_menu"))
+                       single_menu_mode = 1;
+       }
+
+       tcgetattr(1, &ios_org);
+       atexit(conf_cleanup);
+       init_wsize();
+       conf(&rootmenu);
+
+       do {
+               cprint_init();
+               cprint("--yesno");
+               cprint(_("Do you wish to save your new kernel configuration?"));
+               cprint("5");
+               cprint("60");
+               stat = exec_conf();
+       } while (stat < 0);
+
+       if (stat == 0) {
+               if (conf_write(NULL)) {
+                       fprintf(stderr, _("\n\n"
+                               "Error during writing of the kernel configuration.\n"
+                               "Your kernel configuration changes were NOT saved."
+                               "\n\n"));
+                       return 1;
+               }
+               printf(_("\n\n"
+                       "*** End of LWK kernel configuration.\n"
+                       "*** Execute 'make' to build the kernel or try 'make help'."
+                       "\n\n"));
+       } else {
+               fprintf(stderr, _("\n\n"
+                       "Your kernel configuration changes were NOT saved."
+                       "\n\n"));
+       }
+
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/menu.c b/kitten/scripts/kconfig/menu.c
new file mode 100644 (file)
index 0000000..0fce20c
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+static void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+void menu_init(void)
+{
+       current_entry = current_menu = &rootmenu;
+       last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+       struct menu *menu;
+
+       menu = malloc(sizeof(*menu));
+       memset(menu, 0, sizeof(*menu));
+       menu->sym = sym;
+       menu->parent = current_menu;
+       menu->file = current_file;
+       menu->lineno = zconf_lineno();
+
+       *last_entry_ptr = menu;
+       last_entry_ptr = &menu->next;
+       current_entry = menu;
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+       menu_end_entry();
+       last_entry_ptr = &current_entry->list;
+       return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+       last_entry_ptr = &current_menu->next;
+       current_menu = current_menu->parent;
+}
+
+struct expr *menu_check_dep(struct expr *e)
+{
+       if (!e)
+               return e;
+
+       switch (e->type) {
+       case E_NOT:
+               e->left.expr = menu_check_dep(e->left.expr);
+               break;
+       case E_OR:
+       case E_AND:
+               e->left.expr = menu_check_dep(e->left.expr);
+               e->right.expr = menu_check_dep(e->right.expr);
+               break;
+       case E_SYMBOL:
+               /* change 'm' into 'm' && MODULES */
+               if (e->left.sym == &symbol_mod)
+                       return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+               break;
+       default:
+               break;
+       }
+       return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+       current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+       struct symbol *sym = current_entry->sym;
+
+       if (sym->type == type)
+               return;
+       if (sym->type == S_UNKNOWN) {
+               sym->type = type;
+               return;
+       }
+       menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
+           sym->name ? sym->name : "<choice>",
+           sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+       struct property *prop = prop_alloc(type, current_entry->sym);
+
+       prop->menu = current_entry;
+       prop->text = prompt;
+       prop->expr = expr;
+       prop->visible.expr = menu_check_dep(dep);
+
+       if (prompt) {
+               if (current_entry->prompt)
+                       menu_warn(current_entry, "prompt redefined\n");
+               current_entry->prompt = prop;
+       }
+
+       return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+       return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+       menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+       menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+{
+       return sym2->type == S_INT || sym2->type == S_HEX ||
+              (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+void sym_check_prop(struct symbol *sym)
+{
+       struct property *prop;
+       struct symbol *sym2;
+       for (prop = sym->prop; prop; prop = prop->next) {
+               switch (prop->type) {
+               case P_DEFAULT:
+                       if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+                           prop->expr->type != E_SYMBOL)
+                               prop_warn(prop,
+                                   "default for config symbol '%'"
+                                   " must be a single symbol", sym->name);
+                       break;
+               case P_SELECT:
+                       sym2 = prop_get_symbol(prop);
+                       if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+                               prop_warn(prop,
+                                   "config symbol '%s' uses select, but is "
+                                   "not boolean or tristate", sym->name);
+                       else if (sym2->type == S_UNKNOWN)
+                               prop_warn(prop,
+                                   "'select' used by config symbol '%s' "
+                                   "refer to undefined symbol '%s'",
+                                   sym->name, sym2->name);
+                       else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
+                               prop_warn(prop,
+                                   "'%s' has wrong type. 'select' only "
+                                   "accept arguments of boolean and "
+                                   "tristate type", sym2->name);
+                       break;
+               case P_RANGE:
+                       if (sym->type != S_INT && sym->type != S_HEX)
+                               prop_warn(prop, "range is only allowed "
+                                               "for int or hex symbols");
+                       if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
+                           !menu_range_valid_sym(sym, prop->expr->right.sym))
+                               prop_warn(prop, "range is invalid");
+                       break;
+               default:
+                       ;
+               }
+       }
+}
+
+void menu_finalize(struct menu *parent)
+{
+       struct menu *menu, *last_menu;
+       struct symbol *sym;
+       struct property *prop;
+       struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+       sym = parent->sym;
+       if (parent->list) {
+               if (sym && sym_is_choice(sym)) {
+                       /* find the first choice value and find out choice type */
+                       for (menu = parent->list; menu; menu = menu->next) {
+                               if (menu->sym) {
+                                       current_entry = parent;
+                                       menu_set_type(menu->sym->type);
+                                       current_entry = menu;
+                                       menu_set_type(sym->type);
+                                       break;
+                               }
+                       }
+                       parentdep = expr_alloc_symbol(sym);
+               } else if (parent->prompt)
+                       parentdep = parent->prompt->visible.expr;
+               else
+                       parentdep = parent->dep;
+
+               for (menu = parent->list; menu; menu = menu->next) {
+                       basedep = expr_transform(menu->dep);
+                       basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+                       basedep = expr_eliminate_dups(basedep);
+                       menu->dep = basedep;
+                       if (menu->sym)
+                               prop = menu->sym->prop;
+                       else
+                               prop = menu->prompt;
+                       for (; prop; prop = prop->next) {
+                               if (prop->menu != menu)
+                                       continue;
+                               dep = expr_transform(prop->visible.expr);
+                               dep = expr_alloc_and(expr_copy(basedep), dep);
+                               dep = expr_eliminate_dups(dep);
+                               if (menu->sym && menu->sym->type != S_TRISTATE)
+                                       dep = expr_trans_bool(dep);
+                               prop->visible.expr = dep;
+                               if (prop->type == P_SELECT) {
+                                       struct symbol *es = prop_get_symbol(prop);
+                                       es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+                                                       expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+                               }
+                       }
+               }
+               for (menu = parent->list; menu; menu = menu->next)
+                       menu_finalize(menu);
+       } else if (sym) {
+               basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+               basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+               basedep = expr_eliminate_dups(expr_transform(basedep));
+               last_menu = NULL;
+               for (menu = parent->next; menu; menu = menu->next) {
+                       dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+                       if (!expr_contains_symbol(dep, sym))
+                               break;
+                       if (expr_depends_symbol(dep, sym))
+                               goto next;
+                       dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+                       dep = expr_eliminate_dups(expr_transform(dep));
+                       dep2 = expr_copy(basedep);
+                       expr_eliminate_eq(&dep, &dep2);
+                       expr_free(dep);
+                       if (!expr_is_yes(dep2)) {
+                               expr_free(dep2);
+                               break;
+                       }
+                       expr_free(dep2);
+               next:
+                       menu_finalize(menu);
+                       menu->parent = parent;
+                       last_menu = menu;
+               }
+               if (last_menu) {
+                       parent->list = parent->next;
+                       parent->next = last_menu->next;
+                       last_menu->next = NULL;
+               }
+       }
+       for (menu = parent->list; menu; menu = menu->next) {
+               if (sym && sym_is_choice(sym) && menu->sym) {
+                       menu->sym->flags |= SYMBOL_CHOICEVAL;
+                       if (!menu->prompt)
+                               menu_warn(menu, "choice value must have a prompt");
+                       for (prop = menu->sym->prop; prop; prop = prop->next) {
+                               if (prop->type == P_PROMPT && prop->menu != menu) {
+                                       prop_warn(prop, "choice values "
+                                           "currently only support a "
+                                           "single prompt");
+                               }
+                               if (prop->type == P_DEFAULT)
+                                       prop_warn(prop, "defaults for choice "
+                                           "values not supported");
+                       }
+                       current_entry = menu;
+                       menu_set_type(sym->type);
+                       menu_add_symbol(P_CHOICE, sym, NULL);
+                       prop = sym_get_choice_prop(sym);
+                       for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+                               ;
+                       *ep = expr_alloc_one(E_CHOICE, NULL);
+                       (*ep)->right.sym = menu->sym;
+               }
+               if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+                       for (last_menu = menu->list; ; last_menu = last_menu->next) {
+                               last_menu->parent = parent;
+                               if (!last_menu->next)
+                                       break;
+                       }
+                       last_menu->next = menu->next;
+                       menu->next = menu->list;
+                       menu->list = NULL;
+               }
+       }
+
+       if (sym && !(sym->flags & SYMBOL_WARNED)) {
+               if (sym->type == S_UNKNOWN)
+                       menu_warn(parent, "config symbol defined "
+                           "without type\n");
+
+               if (sym_is_choice(sym) && !parent->prompt)
+                       menu_warn(parent, "choice must have a prompt\n");
+
+               /* Check properties connected to this symbol */
+               sym_check_prop(sym);
+               sym->flags |= SYMBOL_WARNED;
+       }
+
+       if (sym && !sym_is_optional(sym) && parent->prompt) {
+               sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+                               expr_alloc_and(parent->prompt->visible.expr,
+                                       expr_alloc_symbol(&symbol_mod)));
+       }
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+       struct menu *child;
+       struct symbol *sym;
+       tristate visible;
+
+       if (!menu->prompt)
+               return false;
+       sym = menu->sym;
+       if (sym) {
+               sym_calc_value(sym);
+               visible = menu->prompt->visible.tri;
+       } else
+               visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+       if (visible != no)
+               return true;
+       if (!sym || sym_get_tristate_value(menu->sym) == no)
+               return false;
+
+       for (child = menu->list; child; child = child->next)
+               if (menu_is_visible(child))
+                       return true;
+       return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+       if (menu->prompt)
+               return _(menu->prompt->text);
+       else if (menu->sym)
+               return _(menu->sym->name);
+       return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+       return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+       enum prop_type type;
+
+       for (; menu != &rootmenu; menu = menu->parent) {
+               type = menu->prompt ? menu->prompt->type : 0;
+               if (type == P_MENU)
+                       break;
+       }
+       return menu;
+}
+
diff --git a/kitten/scripts/kconfig/qconf.cc b/kitten/scripts/kconfig/qconf.cc
new file mode 100644 (file)
index 0000000..4590cd3
--- /dev/null
@@ -0,0 +1,1426 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qapplication.h>
+#include <qmainwindow.h>
+#include <qtoolbar.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qlistview.h>
+#include <qtextview.h>
+#include <qlineedit.h>
+#include <qmenubar.h>
+#include <qmessagebox.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qregexp.h>
+
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "qconf.h"
+
+#include "qconf.moc"
+#include "images.c"
+
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
+static QApplication *configApp;
+
+static inline QString qgettext(const char* str)
+{
+  return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+  return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
+ConfigSettings::ConfigSettings()
+       : showAll(false), showName(false), showRange(false), showData(false)
+{
+}
+
+#if QT_VERSION >= 300
+/**
+ * Reads the list column settings from the application settings.
+ */
+void ConfigSettings::readListSettings()
+{
+       showAll = readBoolEntry("/kconfig/qconf/showAll", false);
+       showName = readBoolEntry("/kconfig/qconf/showName", false);
+       showRange = readBoolEntry("/kconfig/qconf/showRange", false);
+       showData = readBoolEntry("/kconfig/qconf/showData", false);
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+       QValueList<int> result;
+       QStringList entryList = readListEntry(key, ok);
+       if (ok) {
+               QStringList::Iterator it;
+               for (it = entryList.begin(); it != entryList.end(); ++it)
+                       result.push_back((*it).toInt());
+       }
+
+       return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
+{
+       QStringList stringList;
+       QValueList<int>::ConstIterator it;
+
+       for (it = value.begin(); it != value.end(); ++it)
+               stringList.push_back(QString::number(*it));
+       return writeEntry(key, stringList);
+}
+#endif
+
+
+/*
+ * update all the children of a menu entry
+ *   removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+       struct menu* child;
+       ConfigItem* item;
+       ConfigItem* last;
+       bool visible;
+       enum prop_type type;
+
+       if (!menu) {
+               while ((item = parent->firstChild()))
+                       delete item;
+               return;
+       }
+
+       last = parent->firstChild();
+       if (last && !last->goParent)
+               last = 0;
+       for (child = menu->list; child; child = child->next) {
+               item = last ? last->nextSibling() : parent->firstChild();
+               type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+               switch (mode) {
+               case menuMode:
+                       if (!(child->flags & MENU_ROOT))
+                               goto hide;
+                       break;
+               case symbolMode:
+                       if (child->flags & MENU_ROOT)
+                               goto hide;
+                       break;
+               default:
+                       break;
+               }
+
+               visible = menu_is_visible(child);
+               if (showAll || visible) {
+                       if (!item || item->menu != child)
+                               item = new ConfigItem(parent, last, child, visible);
+                       else
+                               item->testUpdateMenu(visible);
+
+                       if (mode == fullMode || mode == menuMode || type != P_MENU)
+                               updateMenuList(item, child);
+                       else
+                               updateMenuList(item, 0);
+                       last = item;
+                       continue;
+               }
+       hide:
+               if (item && item->menu == child) {
+                       last = parent->firstChild();
+                       if (last == item)
+                               last = 0;
+                       else while (last->nextSibling() != item)
+                               last = last->nextSibling();
+                       delete item;
+               }
+       }
+}
+
+#if QT_VERSION >= 300
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+       Parent::okRename(col);
+       sym_set_string_value(menu->sym, text(dataColIdx).latin1());
+}
+#endif
+
+/*
+ * update the displayed of a menu entry
+ */
+void ConfigItem::updateMenu(void)
+{
+       ConfigList* list;
+       struct symbol* sym;
+       struct property *prop;
+       QString prompt;
+       int type;
+       tristate expr;
+
+       list = listView();
+       if (goParent) {
+               setPixmap(promptColIdx, list->menuBackPix);
+               prompt = "..";
+               goto set_prompt;
+       }
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       prompt = QString::fromLocal8Bit(menu_get_prompt(menu));
+
+       if (prop) switch (prop->type) {
+       case P_MENU:
+               if (list->mode == singleMode || list->mode == symbolMode) {
+                       /* a menuconfig entry is displayed differently
+                        * depending whether it's at the view root or a child.
+                        */
+                       if (sym && list->rootEntry == menu)
+                               break;
+                       setPixmap(promptColIdx, list->menuPix);
+               } else {
+                       if (sym)
+                               break;
+                       setPixmap(promptColIdx, 0);
+               }
+               goto set_prompt;
+       case P_COMMENT:
+               setPixmap(promptColIdx, 0);
+               goto set_prompt;
+       default:
+               ;
+       }
+       if (!sym)
+               goto set_prompt;
+
+       setText(nameColIdx, QString::fromLocal8Bit(sym->name));
+
+       type = sym_get_type(sym);
+       switch (type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               char ch;
+
+               if (!sym_is_changable(sym) && !list->showAll) {
+                       setPixmap(promptColIdx, 0);
+                       setText(noColIdx, QString::null);
+                       setText(modColIdx, QString::null);
+                       setText(yesColIdx, QString::null);
+                       break;
+               }
+               expr = sym_get_tristate_value(sym);
+               switch (expr) {
+               case yes:
+                       if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+                               setPixmap(promptColIdx, list->choiceYesPix);
+                       else
+                               setPixmap(promptColIdx, list->symbolYesPix);
+                       setText(yesColIdx, "Y");
+                       ch = 'Y';
+                       break;
+               case mod:
+                       setPixmap(promptColIdx, list->symbolModPix);
+                       setText(modColIdx, "M");
+                       ch = 'M';
+                       break;
+               default:
+                       if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+                               setPixmap(promptColIdx, list->choiceNoPix);
+                       else
+                               setPixmap(promptColIdx, list->symbolNoPix);
+                       setText(noColIdx, "N");
+                       ch = 'N';
+                       break;
+               }
+               if (expr != no)
+                       setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+               if (expr != mod)
+                       setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+               if (expr != yes)
+                       setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
+
+               setText(dataColIdx, QChar(ch));
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               const char* data;
+
+               data = sym_get_string_value(sym);
+
+#if QT_VERSION >= 300
+               int i = list->mapIdx(dataColIdx);
+               if (i >= 0)
+                       setRenameEnabled(i, TRUE);
+#endif
+               setText(dataColIdx, data);
+               if (type == S_STRING)
+                       prompt = QString("%1: %2").arg(prompt).arg(data);
+               else
+                       prompt = QString("(%2) %1").arg(prompt).arg(data);
+               break;
+       }
+       if (!sym_has_value(sym) && visible)
+               prompt += " (NEW)";
+set_prompt:
+       setText(promptColIdx, prompt);
+}
+
+void ConfigItem::testUpdateMenu(bool v)
+{
+       ConfigItem* i;
+
+       visible = v;
+       if (!menu)
+               return;
+
+       sym_calc_value(menu->sym);
+       if (menu->flags & MENU_CHANGED) {
+               /* the menu entry changed, so update all list items */
+               menu->flags &= ~MENU_CHANGED;
+               for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
+                       i->updateMenu();
+       } else if (listView()->updateAll)
+               updateMenu();
+}
+
+void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+       ConfigList* list = listView();
+
+       if (visible) {
+               if (isSelected() && !list->hasFocus() && list->mode == menuMode)
+                       Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
+               else
+                       Parent::paintCell(p, cg, column, width, align);
+       } else
+               Parent::paintCell(p, list->disabledColorGroup, column, width, align);
+}
+
+/*
+ * construct a menu entry
+ */
+void ConfigItem::init(void)
+{
+       if (menu) {
+               ConfigList* list = listView();
+               nextItem = (ConfigItem*)menu->data;
+               menu->data = this;
+
+               if (list->mode != fullMode)
+                       setOpen(TRUE);
+               sym_calc_value(menu->sym);
+       }
+       updateMenu();
+}
+
+/*
+ * destruct a menu entry
+ */
+ConfigItem::~ConfigItem(void)
+{
+       if (menu) {
+               ConfigItem** ip = (ConfigItem**)&menu->data;
+               for (; *ip; ip = &(*ip)->nextItem) {
+                       if (*ip == this) {
+                               *ip = nextItem;
+                               break;
+                       }
+               }
+       }
+}
+
+void ConfigLineEdit::show(ConfigItem* i)
+{
+       item = i;
+       if (sym_get_string_value(item->menu->sym))
+               setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
+       else
+               setText(QString::null);
+       Parent::show();
+       setFocus();
+}
+
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+       switch (e->key()) {
+       case Key_Escape:
+               break;
+       case Key_Return:
+       case Key_Enter:
+               sym_set_string_value(item->menu->sym, text().latin1());
+               parent()->updateList(item);
+               break;
+       default:
+               Parent::keyPressEvent(e);
+               return;
+       }
+       e->accept();
+       parent()->list->setFocus();
+       hide();
+}
+
+ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv, ConfigSettings* configSettings)
+       : Parent(p), cview(cv),
+         updateAll(false),
+         symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
+         choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
+         menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
+         showAll(false), showName(false), showRange(false), showData(false),
+         rootEntry(0)
+{
+       int i;
+
+       setSorting(-1);
+       setRootIsDecorated(TRUE);
+       disabledColorGroup = palette().active();
+       disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
+       inactivedColorGroup = palette().active();
+       inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+
+       connect(this, SIGNAL(selectionChanged(void)),
+               SLOT(updateSelection(void)));
+
+       if (configSettings) {
+               showAll = configSettings->showAll;
+               showName = configSettings->showName;
+               showRange = configSettings->showRange;
+               showData = configSettings->showData;
+       }
+
+       for (i = 0; i < colNr; i++)
+               colMap[i] = colRevMap[i] = -1;
+       addColumn(promptColIdx, "Option");
+
+       reinit();
+}
+
+void ConfigList::reinit(void)
+{
+       removeColumn(dataColIdx);
+       removeColumn(yesColIdx);
+       removeColumn(modColIdx);
+       removeColumn(noColIdx);
+       removeColumn(nameColIdx);
+
+       if (showName)
+               addColumn(nameColIdx, "Name");
+       if (showRange) {
+               addColumn(noColIdx, "N");
+               addColumn(modColIdx, "M");
+               addColumn(yesColIdx, "Y");
+       }
+       if (showData)
+               addColumn(dataColIdx, "Value");
+
+       updateListAll();
+}
+
+void ConfigList::updateSelection(void)
+{
+       struct menu *menu;
+       enum prop_type type;
+
+       ConfigItem* item = (ConfigItem*)selectedItem();
+       if (!item)
+               return;
+
+       cview->setHelp(item);
+
+       menu = item->menu;
+       if (!menu)
+               return;
+       type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       if (mode == menuMode && type == P_MENU)
+               emit menuSelected(menu);
+}
+
+void ConfigList::updateList(ConfigItem* item)
+{
+       ConfigItem* last = 0;
+
+       if (!rootEntry)
+               goto update;
+
+       if (rootEntry != &rootmenu && (mode == singleMode ||
+           (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+               item = firstChild();
+               if (!item)
+                       item = new ConfigItem(this, 0, true);
+               last = item;
+       }
+       if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
+           rootEntry->sym && rootEntry->prompt) {
+               item = last ? last->nextSibling() : firstChild();
+               if (!item)
+                       item = new ConfigItem(this, last, rootEntry, true);
+               else
+                       item->testUpdateMenu(true);
+
+               updateMenuList(item, rootEntry);
+               triggerUpdate();
+               return;
+       }
+update:
+       updateMenuList(this, rootEntry);
+       triggerUpdate();
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+       QListViewItemIterator it(this);
+
+       for (; it.current(); it++)
+               it.current()->setOpen(open);
+}
+
+void ConfigList::setValue(ConfigItem* item, tristate val)
+{
+       struct symbol* sym;
+       int type;
+       tristate oldval;
+
+       sym = item->menu ? item->menu->sym : 0;
+       if (!sym)
+               return;
+
+       type = sym_get_type(sym);
+       switch (type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldval = sym_get_tristate_value(sym);
+
+               if (!sym_set_tristate_value(sym, val))
+                       return;
+               if (oldval == no && item->menu->list)
+                       item->setOpen(TRUE);
+               parent()->updateList(item);
+               break;
+       }
+}
+
+void ConfigList::changeValue(ConfigItem* item)
+{
+       struct symbol* sym;
+       struct menu* menu;
+       int type, oldexpr, newexpr;
+
+       menu = item->menu;
+       if (!menu)
+               return;
+       sym = menu->sym;
+       if (!sym) {
+               if (item->menu->list)
+                       item->setOpen(!item->isOpen());
+               return;
+       }
+
+       type = sym_get_type(sym);
+       switch (type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldexpr = sym_get_tristate_value(sym);
+               newexpr = sym_toggle_tristate_value(sym);
+               if (item->menu->list) {
+                       if (oldexpr == newexpr)
+                               item->setOpen(!item->isOpen());
+                       else if (oldexpr == no)
+                               item->setOpen(TRUE);
+               }
+               if (oldexpr != newexpr)
+                       parent()->updateList(item);
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+#if QT_VERSION >= 300
+               if (colMap[dataColIdx] >= 0)
+                       item->startRename(colMap[dataColIdx]);
+               else
+#endif
+                       parent()->lineEdit->show(item);
+               break;
+       }
+}
+
+void ConfigList::setRootMenu(struct menu *menu)
+{
+       enum prop_type type;
+
+       if (rootEntry == menu)
+               return;
+       type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       if (type != P_MENU)
+               return;
+       updateMenuList(this, 0);
+       rootEntry = menu;
+       updateListAll();
+       setSelected(currentItem(), hasFocus());
+}
+
+void ConfigList::setParentMenu(void)
+{
+       ConfigItem* item;
+       struct menu *oldroot;
+
+       oldroot = rootEntry;
+       if (rootEntry == &rootmenu)
+               return;
+       setRootMenu(menu_get_parent_menu(rootEntry->parent));
+
+       QListViewItemIterator it(this);
+       for (; (item = (ConfigItem*)it.current()); it++) {
+               if (item->menu == oldroot) {
+                       setCurrentItem(item);
+                       ensureItemVisible(item);
+                       break;
+               }
+       }
+}
+
+void ConfigList::keyPressEvent(QKeyEvent* ev)
+{
+       QListViewItem* i = currentItem();
+       ConfigItem* item;
+       struct menu *menu;
+       enum prop_type type;
+
+       if (ev->key() == Key_Escape && mode != fullMode) {
+               emit parentSelected();
+               ev->accept();
+               return;
+       }
+
+       if (!i) {
+               Parent::keyPressEvent(ev);
+               return;
+       }
+       item = (ConfigItem*)i;
+
+       switch (ev->key()) {
+       case Key_Return:
+       case Key_Enter:
+               if (item->goParent) {
+                       emit parentSelected();
+                       break;
+               }
+               menu = item->menu;
+               if (!menu)
+                       break;
+               type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+               if (type == P_MENU && rootEntry != menu &&
+                   mode != fullMode && mode != menuMode) {
+                       emit menuSelected(menu);
+                       break;
+               }
+       case Key_Space:
+               changeValue(item);
+               break;
+       case Key_N:
+               setValue(item, no);
+               break;
+       case Key_M:
+               setValue(item, mod);
+               break;
+       case Key_Y:
+               setValue(item, yes);
+               break;
+       default:
+               Parent::keyPressEvent(ev);
+               return;
+       }
+       ev->accept();
+}
+
+void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+{
+       //QPoint p(contentsToViewport(e->pos()));
+       //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMousePressEvent(e);
+}
+
+void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+       QPoint p(contentsToViewport(e->pos()));
+       ConfigItem* item = (ConfigItem*)itemAt(p);
+       struct menu *menu;
+       enum prop_type ptype;
+       const QPixmap* pm;
+       int idx, x;
+
+       if (!item)
+               goto skip;
+
+       menu = item->menu;
+       x = header()->offset() + p.x();
+       idx = colRevMap[header()->sectionAt(x)];
+       switch (idx) {
+       case promptColIdx:
+               pm = item->pixmap(promptColIdx);
+               if (pm) {
+                       int off = header()->sectionPos(0) + itemMargin() +
+                               treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
+                       if (x >= off && x < off + pm->width()) {
+                               if (item->goParent) {
+                                       emit parentSelected();
+                                       break;
+                               } else if (!menu)
+                                       break;
+                               ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+                               if (ptype == P_MENU && rootEntry != menu &&
+                                   mode != fullMode && mode != menuMode)
+                                       emit menuSelected(menu);
+                               else
+                                       changeValue(item);
+                       }
+               }
+               break;
+       case noColIdx:
+               setValue(item, no);
+               break;
+       case modColIdx:
+               setValue(item, mod);
+               break;
+       case yesColIdx:
+               setValue(item, yes);
+               break;
+       case dataColIdx:
+               changeValue(item);
+               break;
+       }
+
+skip:
+       //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMouseReleaseEvent(e);
+}
+
+void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+{
+       //QPoint p(contentsToViewport(e->pos()));
+       //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMouseMoveEvent(e);
+}
+
+void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+       QPoint p(contentsToViewport(e->pos()));
+       ConfigItem* item = (ConfigItem*)itemAt(p);
+       struct menu *menu;
+       enum prop_type ptype;
+
+       if (!item)
+               goto skip;
+       if (item->goParent) {
+               emit parentSelected();
+               goto skip;
+       }
+       menu = item->menu;
+       if (!menu)
+               goto skip;
+       ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
+               emit menuSelected(menu);
+       else if (menu->sym)
+               changeValue(item);
+
+skip:
+       //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
+       Parent::contentsMouseDoubleClickEvent(e);
+}
+
+void ConfigList::focusInEvent(QFocusEvent *e)
+{
+       Parent::focusInEvent(e);
+
+       QListViewItem* item = currentItem();
+       if (!item)
+               return;
+
+       setSelected(item, TRUE);
+       emit gotFocus();
+}
+
+ConfigView* ConfigView::viewList;
+
+ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview,
+                      ConfigSettings *configSettings)
+       : Parent(parent)
+{
+       list = new ConfigList(this, cview, configSettings);
+       lineEdit = new ConfigLineEdit(this);
+       lineEdit->hide();
+
+       this->nextView = viewList;
+       viewList = this;
+}
+
+ConfigView::~ConfigView(void)
+{
+       ConfigView** vp;
+
+       for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+               if (*vp == this) {
+                       *vp = nextView;
+                       break;
+               }
+       }
+}
+
+void ConfigView::updateList(ConfigItem* item)
+{
+       ConfigView* v;
+
+       for (v = viewList; v; v = v->nextView)
+               v->list->updateList(item);
+}
+
+void ConfigView::updateListAll(void)
+{
+       ConfigView* v;
+
+       for (v = viewList; v; v = v->nextView)
+               v->list->updateListAll();
+}
+
+/*
+ * Construct the complete config widget
+ */
+ConfigMainWindow::ConfigMainWindow(void)
+{
+       QMenuBar* menu;
+       bool ok;
+       int x, y, width, height;
+
+       QWidget *d = configApp->desktop();
+
+       ConfigSettings* configSettings = new ConfigSettings();
+#if QT_VERSION >= 300
+       width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64);
+       height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64);
+       resize(width, height);
+       x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok);
+       if (ok)
+               y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok);
+       if (ok)
+               move(x, y);
+       showDebug = configSettings->readBoolEntry("/kconfig/qconf/showDebug", false);
+
+       // read list settings into configSettings, will be used later for ConfigList setup
+       configSettings->readListSettings();
+#else
+       width = d->width() - 64;
+       height = d->height() - 64;
+       resize(width, height);
+       showDebug = false;
+#endif
+
+       split1 = new QSplitter(this);
+       split1->setOrientation(QSplitter::Horizontal);
+       setCentralWidget(split1);
+
+       menuView = new ConfigView(split1, this, configSettings);
+       menuList = menuView->list;
+
+       split2 = new QSplitter(split1);
+       split2->setOrientation(QSplitter::Vertical);
+
+       // create config tree
+       configView = new ConfigView(split2, this, configSettings);
+       configList = configView->list;
+
+       helpText = new QTextView(split2);
+       helpText->setTextFormat(Qt::RichText);
+
+       setTabOrder(configList, helpText);
+       configList->setFocus();
+
+       menu = menuBar();
+       toolBar = new QToolBar("Tools", this);
+
+       backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
+         connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+         backAction->setEnabled(FALSE);
+       QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
+         connect(quitAction, SIGNAL(activated()), SLOT(close()));
+       QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
+         connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+       QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
+         connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+       QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
+         connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+       QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
+         connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+       QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
+         connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+       QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
+         connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+       QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
+         showNameAction->setToggleAction(TRUE);
+         showNameAction->setOn(configList->showName);
+         connect(showNameAction, SIGNAL(toggled(bool)), SLOT(setShowName(bool)));
+       QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
+         showRangeAction->setToggleAction(TRUE);
+         showRangeAction->setOn(configList->showRange);
+         connect(showRangeAction, SIGNAL(toggled(bool)), SLOT(setShowRange(bool)));
+       QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
+         showDataAction->setToggleAction(TRUE);
+         showDataAction->setOn(configList->showData);
+         connect(showDataAction, SIGNAL(toggled(bool)), SLOT(setShowData(bool)));
+       QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
+         showAllAction->setToggleAction(TRUE);
+         showAllAction->setOn(configList->showAll);
+         connect(showAllAction, SIGNAL(toggled(bool)), SLOT(setShowAll(bool)));
+       QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
+         showDebugAction->setToggleAction(TRUE);
+         showDebugAction->setOn(showDebug);
+         connect(showDebugAction, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+
+       QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
+         connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+       QAction *showAboutAction = new QAction(NULL, "About", 0, this);
+         connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+       // init tool bar
+       backAction->addTo(toolBar);
+       toolBar->addSeparator();
+       loadAction->addTo(toolBar);
+       saveAction->addTo(toolBar);
+       toolBar->addSeparator();
+       singleViewAction->addTo(toolBar);
+       splitViewAction->addTo(toolBar);
+       fullViewAction->addTo(toolBar);
+
+       // create config menu
+       QPopupMenu* config = new QPopupMenu(this);
+       menu->insertItem("&File", config);
+       loadAction->addTo(config);
+       saveAction->addTo(config);
+       saveAsAction->addTo(config);
+       config->insertSeparator();
+       quitAction->addTo(config);
+
+       // create options menu
+       QPopupMenu* optionMenu = new QPopupMenu(this);
+       menu->insertItem("&Option", optionMenu);
+       showNameAction->addTo(optionMenu);
+       showRangeAction->addTo(optionMenu);
+       showDataAction->addTo(optionMenu);
+       optionMenu->insertSeparator();
+       showAllAction->addTo(optionMenu);
+       showDebugAction->addTo(optionMenu);
+
+       // create help menu
+       QPopupMenu* helpMenu = new QPopupMenu(this);
+       menu->insertSeparator();
+       menu->insertItem("&Help", helpMenu);
+       showIntroAction->addTo(helpMenu);
+       showAboutAction->addTo(helpMenu);
+
+       connect(configList, SIGNAL(menuSelected(struct menu *)),
+               SLOT(changeMenu(struct menu *)));
+       connect(configList, SIGNAL(parentSelected()),
+               SLOT(goBack()));
+       connect(menuList, SIGNAL(menuSelected(struct menu *)),
+               SLOT(changeMenu(struct menu *)));
+
+       connect(configList, SIGNAL(gotFocus(void)),
+               SLOT(listFocusChanged(void)));
+       connect(menuList, SIGNAL(gotFocus(void)),
+               SLOT(listFocusChanged(void)));
+
+#if QT_VERSION >= 300
+       QString listMode = configSettings->readEntry("/kconfig/qconf/listMode", "symbol");
+       if (listMode == "single")
+               showSingleView();
+       else if (listMode == "full")
+               showFullView();
+       else /*if (listMode == "split")*/
+               showSplitView();
+
+       // UI setup done, restore splitter positions
+       QValueList<int> sizes = configSettings->readSizes("/kconfig/qconf/split1", &ok);
+       if (ok)
+               split1->setSizes(sizes);
+
+       sizes = configSettings->readSizes("/kconfig/qconf/split2", &ok);
+       if (ok)
+               split2->setSizes(sizes);
+#else
+       showSplitView();
+#endif
+       delete configSettings;
+}
+
+static QString print_filter(const QString &str)
+{
+       QRegExp re("[<>&\"\\n]");
+       QString res = str;
+       for (int i = 0; (i = res.find(re, i)) >= 0;) {
+               switch (res[i].latin1()) {
+               case '<':
+                       res.replace(i, 1, "&lt;");
+                       i += 4;
+                       break;
+               case '>':
+                       res.replace(i, 1, "&gt;");
+                       i += 4;
+                       break;
+               case '&':
+                       res.replace(i, 1, "&amp;");
+                       i += 5;
+                       break;
+               case '"':
+                       res.replace(i, 1, "&quot;");
+                       i += 6;
+                       break;
+               case '\n':
+                       res.replace(i, 1, "<br>");
+                       i += 4;
+                       break;
+               }
+       }
+       return res;
+}
+
+static void expr_print_help(void *data, const char *str)
+{
+       reinterpret_cast<QString*>(data)->append(print_filter(str));
+}
+
+/*
+ * display a new help entry as soon as a new menu entry is selected
+ */
+void ConfigMainWindow::setHelp(QListViewItem* item)
+{
+       struct symbol* sym;
+       struct menu* menu = 0;
+
+       configList->parent()->lineEdit->hide();
+       if (item)
+               menu = ((ConfigItem*)item)->menu;
+       if (!menu) {
+               helpText->setText(QString::null);
+               return;
+       }
+
+       QString head, debug, help;
+       menu = ((ConfigItem*)item)->menu;
+       sym = menu->sym;
+       if (sym) {
+               if (menu->prompt) {
+                       head += "<big><b>";
+                       head += print_filter(_(menu->prompt->text));
+                       head += "</b></big>";
+                       if (sym->name) {
+                               head += " (";
+                               head += print_filter(_(sym->name));
+                               head += ")";
+                       }
+               } else if (sym->name) {
+                       head += "<big><b>";
+                       head += print_filter(_(sym->name));
+                       head += "</b></big>";
+               }
+               head += "<br><br>";
+
+               if (showDebug) {
+                       debug += "type: ";
+                       debug += print_filter(sym_type_name(sym->type));
+                       if (sym_is_choice(sym))
+                               debug += " (choice)";
+                       debug += "<br>";
+                       if (sym->rev_dep.expr) {
+                               debug += "reverse dep: ";
+                               expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+                               debug += "<br>";
+                       }
+                       for (struct property *prop = sym->prop; prop; prop = prop->next) {
+                               switch (prop->type) {
+                               case P_PROMPT:
+                               case P_MENU:
+                                       debug += "prompt: ";
+                                       debug += print_filter(_(prop->text));
+                                       debug += "<br>";
+                                       break;
+                               case P_DEFAULT:
+                                       debug += "default: ";
+                                       expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+                                       debug += "<br>";
+                                       break;
+                               case P_CHOICE:
+                                       if (sym_is_choice(sym)) {
+                                               debug += "choice: ";
+                                               expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+                                               debug += "<br>";
+                                       }
+                                       break;
+                               case P_SELECT:
+                                       debug += "select: ";
+                                       expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+                                       debug += "<br>";
+                                       break;
+                               case P_RANGE:
+                                       debug += "range: ";
+                                       expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+                                       debug += "<br>";
+                                       break;
+                               default:
+                                       debug += "unknown property: ";
+                                       debug += prop_get_type_name(prop->type);
+                                       debug += "<br>";
+                               }
+                               if (prop->visible.expr) {
+                                       debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
+                                       expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+                                       debug += "<br>";
+                               }
+                       }
+                       debug += "<br>";
+               }
+
+               help = print_filter(_(sym->help));
+       } else if (menu->prompt) {
+               head += "<big><b>";
+               head += print_filter(_(menu->prompt->text));
+               head += "</b></big><br><br>";
+               if (showDebug) {
+                       if (menu->prompt->visible.expr) {
+                               debug += "&nbsp;&nbsp;dep: ";
+                               expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+                               debug += "<br><br>";
+                       }
+               }
+       }
+       if (showDebug)
+               debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
+       helpText->setText(head + debug + help);
+}
+
+void ConfigMainWindow::loadConfig(void)
+{
+       QString s = QFileDialog::getOpenFileName(".config", NULL, this);
+       if (s.isNull())
+               return;
+       if (conf_read(QFile::encodeName(s)))
+               QMessageBox::information(this, "qconf", "Unable to load configuration!");
+       ConfigView::updateListAll();
+}
+
+void ConfigMainWindow::saveConfig(void)
+{
+       if (conf_write(NULL))
+               QMessageBox::information(this, "qconf", "Unable to save configuration!");
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+       QString s = QFileDialog::getSaveFileName(".config", NULL, this);
+       if (s.isNull())
+               return;
+       if (conf_write(QFile::encodeName(s)))
+               QMessageBox::information(this, "qconf", "Unable to save configuration!");
+}
+
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+       configList->setRootMenu(menu);
+       backAction->setEnabled(TRUE);
+}
+
+void ConfigMainWindow::listFocusChanged(void)
+{
+       if (menuList->hasFocus()) {
+               if (menuList->mode == menuMode)
+                       configList->clearSelection();
+               setHelp(menuList->selectedItem());
+       } else if (configList->hasFocus()) {
+               setHelp(configList->selectedItem());
+       }
+}
+
+void ConfigMainWindow::goBack(void)
+{
+       ConfigItem* item;
+
+       configList->setParentMenu();
+       if (configList->rootEntry == &rootmenu)
+               backAction->setEnabled(FALSE);
+       item = (ConfigItem*)menuList->selectedItem();
+       while (item) {
+               if (item->menu == configList->rootEntry) {
+                       menuList->setSelected(item, TRUE);
+                       break;
+               }
+               item = (ConfigItem*)item->parent();
+       }
+}
+
+void ConfigMainWindow::showSingleView(void)
+{
+       menuView->hide();
+       menuList->setRootMenu(0);
+       configList->mode = singleMode;
+       if (configList->rootEntry == &rootmenu)
+               configList->updateListAll();
+       else
+               configList->setRootMenu(&rootmenu);
+       configList->setAllOpen(TRUE);
+       configList->setFocus();
+}
+
+void ConfigMainWindow::showSplitView(void)
+{
+       configList->mode = symbolMode;
+       if (configList->rootEntry == &rootmenu)
+               configList->updateListAll();
+       else
+               configList->setRootMenu(&rootmenu);
+       configList->setAllOpen(TRUE);
+       configApp->processEvents();
+       menuList->mode = menuMode;
+       menuList->setRootMenu(&rootmenu);
+       menuList->setAllOpen(TRUE);
+       menuView->show();
+       menuList->setFocus();
+}
+
+void ConfigMainWindow::showFullView(void)
+{
+       menuView->hide();
+       menuList->setRootMenu(0);
+       configList->mode = fullMode;
+       if (configList->rootEntry == &rootmenu)
+               configList->updateListAll();
+       else
+               configList->setRootMenu(&rootmenu);
+       configList->setAllOpen(FALSE);
+       configList->setFocus();
+}
+
+void ConfigMainWindow::setShowAll(bool b)
+{
+       if (configList->showAll == b)
+               return;
+       configList->showAll = b;
+       configList->updateListAll();
+       menuList->showAll = b;
+       menuList->updateListAll();
+}
+
+void ConfigMainWindow::setShowDebug(bool b)
+{
+       if (showDebug == b)
+               return;
+       showDebug = b;
+}
+
+void ConfigMainWindow::setShowName(bool b)
+{
+       if (configList->showName == b)
+               return;
+       configList->showName = b;
+       configList->reinit();
+       menuList->showName = b;
+       menuList->reinit();
+}
+
+void ConfigMainWindow::setShowRange(bool b)
+{
+       if (configList->showRange == b)
+               return;
+       configList->showRange = b;
+       configList->reinit();
+       menuList->showRange = b;
+       menuList->reinit();
+}
+
+void ConfigMainWindow::setShowData(bool b)
+{
+       if (configList->showData == b)
+               return;
+       configList->showData = b;
+       configList->reinit();
+       menuList->showData = b;
+       menuList->reinit();
+}
+
+/*
+ * ask for saving configuration before quitting
+ * TODO ask only when something changed
+ */
+void ConfigMainWindow::closeEvent(QCloseEvent* e)
+{
+       if (!sym_change_count) {
+               e->accept();
+               return;
+       }
+       QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
+                       QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
+       mb.setButtonText(QMessageBox::Yes, "&Save Changes");
+       mb.setButtonText(QMessageBox::No, "&Discard Changes");
+       mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
+       switch (mb.exec()) {
+       case QMessageBox::Yes:
+               conf_write(NULL);
+       case QMessageBox::No:
+               e->accept();
+               break;
+       case QMessageBox::Cancel:
+               e->ignore();
+               break;
+       }
+}
+
+void ConfigMainWindow::showIntro(void)
+{
+       static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
+               "For each option, a blank box indicates the feature is disabled, a check\n"
+               "indicates it is enabled, and a dot indicates that it is to be compiled\n"
+               "as a module.  Clicking on the box will cycle through the three states.\n\n"
+               "If you do not see an option (e.g., a device driver) that you believe\n"
+               "should be present, try turning on Show All Options under the Options menu.\n"
+               "Although there is no cross reference yet to help you figure out what other\n"
+               "options must be enabled to support the option you are interested in, you can\n"
+               "still view the help of a grayed-out option.\n\n"
+               "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+               "which you can then match by examining other options.\n\n";
+
+       QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::showAbout(void)
+{
+       static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
+               "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
+
+       QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::saveSettings(void)
+{
+#if QT_VERSION >= 300
+       ConfigSettings *configSettings = new ConfigSettings;
+       configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
+       configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
+       configSettings->writeEntry("/kconfig/qconf/window width", size().width());
+       configSettings->writeEntry("/kconfig/qconf/window height", size().height());
+       configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
+       configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
+       configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
+       configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
+       configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
+
+       QString entry;
+       switch(configList->mode) {
+       case singleMode :
+               entry = "single";
+               break;
+
+       case symbolMode :
+               entry = "split";
+               break;
+
+       case fullMode :
+               entry = "full";
+               break;
+       }
+       configSettings->writeEntry("/kconfig/qconf/listMode", entry);
+
+       configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
+       configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
+
+       delete configSettings;
+#endif
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+       struct menu *child;
+       static int menu_cnt = 0;
+
+       menu->flags |= MENU_ROOT;
+       for (child = menu->list; child; child = child->next) {
+               if (child->prompt && child->prompt->type == P_MENU) {
+                       menu_cnt++;
+                       fixup_rootmenu(child);
+                       menu_cnt--;
+               } else if (!menu_cnt)
+                       fixup_rootmenu(child);
+       }
+}
+
+static const char *progname;
+
+static void usage(void)
+{
+       printf("%s <config>\n", progname);
+       exit(0);
+}
+
+int main(int ac, char** av)
+{
+       ConfigMainWindow* v;
+       const char *name;
+
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       progname = av[0];
+       configApp = new QApplication(ac, av);
+       if (ac > 1 && av[1][0] == '-') {
+               switch (av[1][1]) {
+               case 'h':
+               case '?':
+                       usage();
+               }
+               name = av[2];
+       } else
+               name = av[1];
+       if (!name)
+               usage();
+
+       conf_parse(name);
+       fixup_rootmenu(&rootmenu);
+       conf_read(NULL);
+       //zconfdump(stdout);
+
+       v = new ConfigMainWindow();
+
+       //zconfdump(stdout);
+       v->show();
+       configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+       configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+       configApp->exec();
+
+       return 0;
+}
diff --git a/kitten/scripts/kconfig/qconf.h b/kitten/scripts/kconfig/qconf.h
new file mode 100644 (file)
index 0000000..e52f3e9
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qlistview.h>
+#if QT_VERSION >= 300
+#include <qsettings.h>
+#else
+class QSettings { };
+#endif
+
+class ConfigList;
+class ConfigItem;
+class ConfigLineEdit;
+class ConfigMainWindow;
+
+
+class ConfigSettings : public QSettings {
+public:
+       ConfigSettings();
+
+#if QT_VERSION >= 300
+       void readListSettings();
+       QValueList<int> readSizes(const QString& key, bool *ok);
+       bool writeSizes(const QString& key, const QValueList<int>& value);
+#endif
+
+       bool showAll;
+       bool showName;
+       bool showRange;
+       bool showData;
+};
+
+class ConfigView : public QVBox {
+       Q_OBJECT
+       typedef class QVBox Parent;
+public:
+       ConfigView(QWidget* parent, ConfigMainWindow* cview, ConfigSettings* configSettings);
+       ~ConfigView(void);
+       static void updateList(ConfigItem* item);
+       static void updateListAll(void);
+
+public:
+       ConfigList* list;
+       ConfigLineEdit* lineEdit;
+
+       static ConfigView* viewList;
+       ConfigView* nextView;
+};
+
+enum colIdx {
+       promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+};
+enum listMode {
+       singleMode, menuMode, symbolMode, fullMode
+};
+
+class ConfigList : public QListView {
+       Q_OBJECT
+       typedef class QListView Parent;
+public:
+       ConfigList(ConfigView* p, ConfigMainWindow* cview, ConfigSettings *configSettings);
+       void reinit(void);
+       ConfigView* parent(void) const
+       {
+               return (ConfigView*)Parent::parent();
+       }
+
+protected:
+       ConfigMainWindow* cview;
+
+       void keyPressEvent(QKeyEvent *e);
+       void contentsMousePressEvent(QMouseEvent *e);
+       void contentsMouseReleaseEvent(QMouseEvent *e);
+       void contentsMouseMoveEvent(QMouseEvent *e);
+       void contentsMouseDoubleClickEvent(QMouseEvent *e);
+       void focusInEvent(QFocusEvent *e);
+public slots:
+       void setRootMenu(struct menu *menu);
+
+       void updateList(ConfigItem *item);
+       void setValue(ConfigItem* item, tristate val);
+       void changeValue(ConfigItem* item);
+       void updateSelection(void);
+signals:
+       void menuSelected(struct menu *menu);
+       void parentSelected(void);
+       void gotFocus(void);
+
+public:
+       void updateListAll(void)
+       {
+               updateAll = true;
+               updateList(NULL);
+               updateAll = false;
+       }
+       ConfigList* listView()
+       {
+               return this;
+       }
+       ConfigItem* firstChild() const
+       {
+               return (ConfigItem *)Parent::firstChild();
+       }
+       int mapIdx(colIdx idx)
+       {
+               return colMap[idx];
+       }
+       void addColumn(colIdx idx, const QString& label)
+       {
+               colMap[idx] = Parent::addColumn(label);
+               colRevMap[colMap[idx]] = idx;
+       }
+       void removeColumn(colIdx idx)
+       {
+               int col = colMap[idx];
+               if (col >= 0) {
+                       Parent::removeColumn(col);
+                       colRevMap[col] = colMap[idx] = -1;
+               }
+       }
+       void setAllOpen(bool open);
+       void setParentMenu(void);
+
+       template <class P>
+       void updateMenuList(P*, struct menu*);
+
+       bool updateAll;
+
+       QPixmap symbolYesPix, symbolModPix, symbolNoPix;
+       QPixmap choiceYesPix, choiceNoPix;
+       QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
+
+       bool showAll, showName, showRange, showData;
+       enum listMode mode;
+       struct menu *rootEntry;
+       QColorGroup disabledColorGroup;
+       QColorGroup inactivedColorGroup;
+
+private:
+       int colMap[colNr];
+       int colRevMap[colNr];
+};
+
+class ConfigItem : public QListViewItem {
+       typedef class QListViewItem Parent;
+public:
+       ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v)
+       : Parent(parent, after), menu(m), visible(v), goParent(false)
+       {
+               init();
+       }
+       ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
+       : Parent(parent, after), menu(m), visible(v), goParent(false)
+       {
+               init();
+       }
+       ConfigItem(QListView *parent, ConfigItem *after, bool v)
+       : Parent(parent, after), menu(0), visible(v), goParent(true)
+       {
+               init();
+       }
+       ~ConfigItem(void);
+       void init(void);
+#if QT_VERSION >= 300
+       void okRename(int col);
+#endif
+       void updateMenu(void);
+       void testUpdateMenu(bool v);
+       ConfigList* listView() const
+       {
+               return (ConfigList*)Parent::listView();
+       }
+       ConfigItem* firstChild() const
+       {
+               return (ConfigItem *)Parent::firstChild();
+       }
+       ConfigItem* nextSibling() const
+       {
+               return (ConfigItem *)Parent::nextSibling();
+       }
+       void setText(colIdx idx, const QString& text)
+       {
+               Parent::setText(listView()->mapIdx(idx), text);
+       }
+       QString text(colIdx idx) const
+       {
+               return Parent::text(listView()->mapIdx(idx));
+       }
+       void setPixmap(colIdx idx, const QPixmap& pm)
+       {
+               Parent::setPixmap(listView()->mapIdx(idx), pm);
+       }
+       const QPixmap* pixmap(colIdx idx) const
+       {
+               return Parent::pixmap(listView()->mapIdx(idx));
+       }
+       void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+       ConfigItem* nextItem;
+       struct menu *menu;
+       bool visible;
+       bool goParent;
+};
+
+class ConfigLineEdit : public QLineEdit {
+       Q_OBJECT
+       typedef class QLineEdit Parent;
+public:
+       ConfigLineEdit(ConfigView* parent)
+       : Parent(parent)
+       { }
+       ConfigView* parent(void) const
+       {
+               return (ConfigView*)Parent::parent();
+       }
+       void show(ConfigItem *i);
+       void keyPressEvent(QKeyEvent *e);
+
+public:
+       ConfigItem *item;
+};
+
+class ConfigMainWindow : public QMainWindow {
+       Q_OBJECT
+public:
+       ConfigMainWindow(void);
+public slots:
+       void setHelp(QListViewItem* item);
+       void changeMenu(struct menu *);
+       void listFocusChanged(void);
+       void goBack(void);
+       void loadConfig(void);
+       void saveConfig(void);
+       void saveConfigAs(void);
+       void showSingleView(void);
+       void showSplitView(void);
+       void showFullView(void);
+       void setShowAll(bool);
+       void setShowDebug(bool);
+       void setShowRange(bool);
+       void setShowName(bool);
+       void setShowData(bool);
+       void showIntro(void);
+       void showAbout(void);
+       void saveSettings(void);
+
+protected:
+       void closeEvent(QCloseEvent *e);
+
+       ConfigView *menuView;
+       ConfigList *menuList;
+       ConfigView *configView;
+       ConfigList *configList;
+       QTextView *helpText;
+       QToolBar *toolBar;
+       QAction *backAction;
+       QSplitter* split1;
+       QSplitter* split2;
+
+       bool showDebug;
+};
diff --git a/kitten/scripts/kconfig/symbol.c b/kitten/scripts/kconfig/symbol.c
new file mode 100644 (file)
index 0000000..3d7877a
--- /dev/null
@@ -0,0 +1,882 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+       .name = "y",
+       .curr = { "y", yes },
+       .flags = SYMBOL_YES|SYMBOL_VALID,
+}, symbol_mod = {
+       .name = "m",
+       .curr = { "m", mod },
+       .flags = SYMBOL_MOD|SYMBOL_VALID,
+}, symbol_no = {
+       .name = "n",
+       .curr = { "n", no },
+       .flags = SYMBOL_NO|SYMBOL_VALID,
+}, symbol_empty = {
+       .name = "",
+       .curr = { "", no },
+       .flags = SYMBOL_VALID,
+};
+
+int sym_change_count;
+struct symbol *modules_sym;
+tristate modules_val;
+
+void sym_add_default(struct symbol *sym, const char *def)
+{
+       struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+       prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+}
+
+void sym_init(void)
+{
+       struct symbol *sym;
+       struct utsname uts;
+       char *p;
+       static bool inited = false;
+
+       if (inited)
+               return;
+       inited = true;
+
+       uname(&uts);
+
+       sym = sym_lookup("ARCH", 0);
+       sym->type = S_STRING;
+       sym->flags |= SYMBOL_AUTO;
+       p = getenv("ARCH");
+       if (p)
+               sym_add_default(sym, p);
+
+       sym = sym_lookup("KERNELVERSION", 0);
+       sym->type = S_STRING;
+       sym->flags |= SYMBOL_AUTO;
+       p = getenv("KERNELVERSION");
+       if (p)
+               sym_add_default(sym, p);
+
+       sym = sym_lookup("UNAME_RELEASE", 0);
+       sym->type = S_STRING;
+       sym->flags |= SYMBOL_AUTO;
+       sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+       enum symbol_type type = sym->type;
+
+       if (type == S_TRISTATE) {
+               if (sym_is_choice_value(sym) && sym->visible == yes)
+                       type = S_BOOLEAN;
+               else if (modules_val == no)
+                       type = S_BOOLEAN;
+       }
+       return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+       switch (type) {
+       case S_BOOLEAN:
+               return "boolean";
+       case S_TRISTATE:
+               return "tristate";
+       case S_INT:
+               return "integer";
+       case S_HEX:
+               return "hex";
+       case S_STRING:
+               return "string";
+       case S_UNKNOWN:
+               return "unknown";
+       case S_OTHER:
+               break;
+       }
+       return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_choices(sym, prop)
+               return prop;
+       return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_defaults(sym, prop) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               if (prop->visible.tri != no)
+                       return prop;
+       }
+       return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+       struct property *prop;
+
+       for_all_properties(sym, prop, P_RANGE) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               if (prop->visible.tri != no)
+                       return prop;
+       }
+       return NULL;
+}
+
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+       sym_calc_value(sym);
+       switch (sym->type) {
+       case S_INT:
+               base = 10;
+               break;
+       case S_HEX:
+               base = 16;
+               break;
+       default:
+               break;
+       }
+       return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+       struct property *prop;
+       int base, val, val2;
+       char str[64];
+
+       switch (sym->type) {
+       case S_INT:
+               base = 10;
+               break;
+       case S_HEX:
+               base = 16;
+               break;
+       default:
+               return;
+       }
+       prop = sym_get_range_prop(sym);
+       if (!prop)
+               return;
+       val = strtol(sym->curr.val, NULL, base);
+       val2 = sym_get_range_val(prop->expr->left.sym, base);
+       if (val >= val2) {
+               val2 = sym_get_range_val(prop->expr->right.sym, base);
+               if (val <= val2)
+                       return;
+       }
+       if (sym->type == S_INT)
+               sprintf(str, "%d", val2);
+       else
+               sprintf(str, "0x%x", val2);
+       sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+       struct property *prop;
+       tristate tri;
+
+       /* any prompt visible? */
+       tri = no;
+       for_all_prompts(sym, prop) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               tri = E_OR(tri, prop->visible.tri);
+       }
+       if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+               tri = yes;
+       if (sym->visible != tri) {
+               sym->visible = tri;
+               sym_set_changed(sym);
+       }
+       if (sym_is_choice_value(sym))
+               return;
+       tri = no;
+       if (sym->rev_dep.expr)
+               tri = expr_calc_value(sym->rev_dep.expr);
+       if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+               tri = yes;
+       if (sym->rev_dep.tri != tri) {
+               sym->rev_dep.tri = tri;
+               sym_set_changed(sym);
+       }
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+       struct symbol *def_sym;
+       struct property *prop;
+       struct expr *e;
+
+       /* is the user choice visible? */
+       def_sym = sym->user.val;
+       if (def_sym) {
+               sym_calc_visibility(def_sym);
+               if (def_sym->visible != no)
+                       return def_sym;
+       }
+
+       /* any of the defaults visible? */
+       for_all_defaults(sym, prop) {
+               prop->visible.tri = expr_calc_value(prop->visible.expr);
+               if (prop->visible.tri == no)
+                       continue;
+               def_sym = prop_get_symbol(prop);
+               sym_calc_visibility(def_sym);
+               if (def_sym->visible != no)
+                       return def_sym;
+       }
+
+       /* just get the first visible value */
+       prop = sym_get_choice_prop(sym);
+       for (e = prop->expr; e; e = e->left.expr) {
+               def_sym = e->right.sym;
+               sym_calc_visibility(def_sym);
+               if (def_sym->visible != no)
+                       return def_sym;
+       }
+
+       /* no choice? reset tristate value */
+       sym->curr.tri = no;
+       return NULL;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+       struct symbol_value newval, oldval;
+       struct property *prop;
+       struct expr *e;
+
+       if (!sym)
+               return;
+
+       if (sym->flags & SYMBOL_VALID)
+               return;
+       sym->flags |= SYMBOL_VALID;
+
+       oldval = sym->curr;
+
+       switch (sym->type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               newval = symbol_empty.curr;
+               break;
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               newval = symbol_no.curr;
+               break;
+       default:
+               sym->curr.val = sym->name;
+               sym->curr.tri = no;
+               return;
+       }
+       if (!sym_is_choice_value(sym))
+               sym->flags &= ~SYMBOL_WRITE;
+
+       sym_calc_visibility(sym);
+
+       /* set default if recursively called */
+       sym->curr = newval;
+
+       switch (sym_get_type(sym)) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               if (sym_is_choice_value(sym) && sym->visible == yes) {
+                       prop = sym_get_choice_prop(sym);
+                       newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+               } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
+                       sym->flags |= SYMBOL_WRITE;
+                       if (sym_has_value(sym))
+                               newval.tri = sym->user.tri;
+                       else if (!sym_is_choice(sym)) {
+                               prop = sym_get_default_prop(sym);
+                               if (prop)
+                                       newval.tri = expr_calc_value(prop->expr);
+                       }
+                       newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
+               } else if (!sym_is_choice(sym)) {
+                       prop = sym_get_default_prop(sym);
+                       if (prop) {
+                               sym->flags |= SYMBOL_WRITE;
+                               newval.tri = expr_calc_value(prop->expr);
+                       }
+               }
+               if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+                       newval.tri = yes;
+               break;
+       case S_STRING:
+       case S_HEX:
+       case S_INT:
+               if (sym->visible != no) {
+                       sym->flags |= SYMBOL_WRITE;
+                       if (sym_has_value(sym)) {
+                               newval.val = sym->user.val;
+                               break;
+                       }
+               }
+               prop = sym_get_default_prop(sym);
+               if (prop) {
+                       struct symbol *ds = prop_get_symbol(prop);
+                       if (ds) {
+                               sym->flags |= SYMBOL_WRITE;
+                               sym_calc_value(ds);
+                               newval.val = ds->curr.val;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+
+       sym->curr = newval;
+       if (sym_is_choice(sym) && newval.tri == yes)
+               sym->curr.val = sym_calc_choice(sym);
+       sym_validate_range(sym);
+
+       if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
+               sym_set_changed(sym);
+       if (modules_sym == sym)
+               modules_val = modules_sym->curr.tri;
+
+       if (sym_is_choice(sym)) {
+               int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+               prop = sym_get_choice_prop(sym);
+               for (e = prop->expr; e; e = e->left.expr) {
+                       e->right.sym->flags |= flags;
+                       if (flags & SYMBOL_CHANGED)
+                               sym_set_changed(e->right.sym);
+               }
+       }
+}
+
+void sym_clear_all_valid(void)
+{
+       struct symbol *sym;
+       int i;
+
+       for_all_symbols(i, sym)
+               sym->flags &= ~SYMBOL_VALID;
+       sym_change_count++;
+       if (modules_sym)
+               sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+       struct property *prop;
+
+       sym->flags |= SYMBOL_CHANGED;
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu)
+                       prop->menu->flags |= MENU_CHANGED;
+       }
+}
+
+void sym_set_all_changed(void)
+{
+       struct symbol *sym;
+       int i;
+
+       for_all_symbols(i, sym)
+               sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+       int type = sym_get_type(sym);
+
+       if (sym->visible == no)
+               return false;
+
+       if (type != S_BOOLEAN && type != S_TRISTATE)
+               return false;
+
+       if (type == S_BOOLEAN && val == mod)
+               return false;
+       if (sym->visible <= sym->rev_dep.tri)
+               return false;
+       if (sym_is_choice_value(sym) && sym->visible == yes)
+               return val == yes;
+       return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+       tristate oldval = sym_get_tristate_value(sym);
+
+       if (oldval != val && !sym_tristate_within_range(sym, val))
+               return false;
+
+       if (sym->flags & SYMBOL_NEW) {
+               sym->flags &= ~SYMBOL_NEW;
+               sym_set_changed(sym);
+       }
+       /*
+        * setting a choice value also resets the new flag of the choice
+        * symbol and all other choice values.
+        */
+       if (sym_is_choice_value(sym) && val == yes) {
+               struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+               struct property *prop;
+               struct expr *e;
+
+               cs->user.val = sym;
+               cs->flags &= ~SYMBOL_NEW;
+               prop = sym_get_choice_prop(cs);
+               for (e = prop->expr; e; e = e->left.expr) {
+                       if (e->right.sym->visible != no)
+                               e->right.sym->flags &= ~SYMBOL_NEW;
+               }
+       }
+
+       sym->user.tri = val;
+       if (oldval != val) {
+               sym_clear_all_valid();
+               if (sym == modules_sym)
+                       sym_set_all_changed();
+       }
+
+       return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+       tristate oldval, newval;
+
+       oldval = newval = sym_get_tristate_value(sym);
+       do {
+               switch (newval) {
+               case no:
+                       newval = mod;
+                       break;
+               case mod:
+                       newval = yes;
+                       break;
+               case yes:
+                       newval = no;
+                       break;
+               }
+               if (sym_set_tristate_value(sym, newval))
+                       break;
+       } while (oldval != newval);
+       return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+       signed char ch;
+
+       switch (sym->type) {
+       case S_STRING:
+               return true;
+       case S_INT:
+               ch = *str++;
+               if (ch == '-')
+                       ch = *str++;
+               if (!isdigit(ch))
+                       return false;
+               if (ch == '0' && *str != 0)
+                       return false;
+               while ((ch = *str++)) {
+                       if (!isdigit(ch))
+                               return false;
+               }
+               return true;
+       case S_HEX:
+               if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+                       str += 2;
+               ch = *str++;
+               do {
+                       if (!isxdigit(ch))
+                               return false;
+               } while ((ch = *str++));
+               return true;
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (str[0]) {
+               case 'y': case 'Y':
+               case 'm': case 'M':
+               case 'n': case 'N':
+                       return true;
+               }
+               return false;
+       default:
+               return false;
+       }
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+       struct property *prop;
+       int val;
+
+       switch (sym->type) {
+       case S_STRING:
+               return sym_string_valid(sym, str);
+       case S_INT:
+               if (!sym_string_valid(sym, str))
+                       return false;
+               prop = sym_get_range_prop(sym);
+               if (!prop)
+                       return true;
+               val = strtol(str, NULL, 10);
+               return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+                      val <= sym_get_range_val(prop->expr->right.sym, 10);
+       case S_HEX:
+               if (!sym_string_valid(sym, str))
+                       return false;
+               prop = sym_get_range_prop(sym);
+               if (!prop)
+                       return true;
+               val = strtol(str, NULL, 16);
+               return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+                      val <= sym_get_range_val(prop->expr->right.sym, 16);
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (str[0]) {
+               case 'y': case 'Y':
+                       return sym_tristate_within_range(sym, yes);
+               case 'm': case 'M':
+                       return sym_tristate_within_range(sym, mod);
+               case 'n': case 'N':
+                       return sym_tristate_within_range(sym, no);
+               }
+               return false;
+       default:
+               return false;
+       }
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+       const char *oldval;
+       char *val;
+       int size;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (newval[0]) {
+               case 'y': case 'Y':
+                       return sym_set_tristate_value(sym, yes);
+               case 'm': case 'M':
+                       return sym_set_tristate_value(sym, mod);
+               case 'n': case 'N':
+                       return sym_set_tristate_value(sym, no);
+               }
+               return false;
+       default:
+               ;
+       }
+
+       if (!sym_string_within_range(sym, newval))
+               return false;
+
+       if (sym->flags & SYMBOL_NEW) {
+               sym->flags &= ~SYMBOL_NEW;
+               sym_set_changed(sym);
+       }
+
+       oldval = sym->user.val;
+       size = strlen(newval) + 1;
+       if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+               size += 2;
+               sym->user.val = val = malloc(size);
+               *val++ = '0';
+               *val++ = 'x';
+       } else if (!oldval || strcmp(oldval, newval))
+               sym->user.val = val = malloc(size);
+       else
+               return true;
+
+       strcpy(val, newval);
+       free((void *)oldval);
+       sym_clear_all_valid();
+
+       return true;
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+       tristate val;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               val = sym_get_tristate_value(sym);
+               switch (val) {
+               case no:
+                       return "n";
+               case mod:
+                       return "m";
+               case yes:
+                       return "y";
+               }
+               break;
+       default:
+               ;
+       }
+       return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+       return sym->visible > sym->rev_dep.tri;
+}
+
+struct symbol *sym_lookup(const char *name, int isconst)
+{
+       struct symbol *symbol;
+       const char *ptr;
+       char *new_name;
+       int hash = 0;
+
+       if (name) {
+               if (name[0] && !name[1]) {
+                       switch (name[0]) {
+                       case 'y': return &symbol_yes;
+                       case 'm': return &symbol_mod;
+                       case 'n': return &symbol_no;
+                       }
+               }
+               for (ptr = name; *ptr; ptr++)
+                       hash += *ptr;
+               hash &= 0xff;
+
+               for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+                       if (!strcmp(symbol->name, name)) {
+                               if ((isconst && symbol->flags & SYMBOL_CONST) ||
+                                   (!isconst && !(symbol->flags & SYMBOL_CONST)))
+                                       return symbol;
+                       }
+               }
+               new_name = strdup(name);
+       } else {
+               new_name = NULL;
+               hash = 256;
+       }
+
+       symbol = malloc(sizeof(*symbol));
+       memset(symbol, 0, sizeof(*symbol));
+       symbol->name = new_name;
+       symbol->type = S_UNKNOWN;
+       symbol->flags = SYMBOL_NEW;
+       if (isconst)
+               symbol->flags |= SYMBOL_CONST;
+
+       symbol->next = symbol_hash[hash];
+       symbol_hash[hash] = symbol;
+
+       return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+       struct symbol *symbol = NULL;
+       const char *ptr;
+       int hash = 0;
+
+       if (!name)
+               return NULL;
+
+       if (name[0] && !name[1]) {
+               switch (name[0]) {
+               case 'y': return &symbol_yes;
+               case 'm': return &symbol_mod;
+               case 'n': return &symbol_no;
+               }
+       }
+       for (ptr = name; *ptr; ptr++)
+               hash += *ptr;
+       hash &= 0xff;
+
+       for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+               if (!strcmp(symbol->name, name) &&
+                   !(symbol->flags & SYMBOL_CONST))
+                               break;
+       }
+
+       return symbol;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+       struct symbol *sym, **sym_arr = NULL;
+       int i, cnt, size;
+       regex_t re;
+
+       cnt = size = 0;
+       /* Skip if empty */
+       if (strlen(pattern) == 0)
+               return NULL;
+       if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+               return NULL;
+
+       for_all_symbols(i, sym) {
+               if (sym->flags & SYMBOL_CONST || !sym->name)
+                       continue;
+               if (regexec(&re, sym->name, 0, NULL, 0))
+                       continue;
+               if (cnt + 1 >= size) {
+                       void *tmp = sym_arr;
+                       size += 16;
+                       sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+                       if (!sym_arr) {
+                               free(tmp);
+                               return NULL;
+                       }
+               }
+               sym_arr[cnt++] = sym;
+       }
+       if (sym_arr)
+               sym_arr[cnt] = NULL;
+       regfree(&re);
+
+       return sym_arr;
+}
+
+
+struct symbol *sym_check_deps(struct symbol *sym);
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+       struct symbol *sym;
+
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_OR:
+       case E_AND:
+               sym = sym_check_expr_deps(e->left.expr);
+               if (sym)
+                       return sym;
+               return sym_check_expr_deps(e->right.expr);
+       case E_NOT:
+               return sym_check_expr_deps(e->left.expr);
+       case E_EQUAL:
+       case E_UNEQUAL:
+               sym = sym_check_deps(e->left.sym);
+               if (sym)
+                       return sym;
+               return sym_check_deps(e->right.sym);
+       case E_SYMBOL:
+               return sym_check_deps(e->left.sym);
+       default:
+               break;
+       }
+       printf("Oops! How to check %d?\n", e->type);
+       return NULL;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+       struct symbol *sym2;
+       struct property *prop;
+
+       if (sym->flags & SYMBOL_CHECK) {
+               printf("Warning! Found recursive dependency: %s", sym->name);
+               return sym;
+       }
+       if (sym->flags & SYMBOL_CHECKED)
+               return NULL;
+
+       sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+       sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+       if (sym2)
+               goto out;
+
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->type == P_CHOICE || prop->type == P_SELECT)
+                       continue;
+               sym2 = sym_check_expr_deps(prop->visible.expr);
+               if (sym2)
+                       goto out;
+               if (prop->type != P_DEFAULT || sym_is_choice(sym))
+                       continue;
+               sym2 = sym_check_expr_deps(prop->expr);
+               if (sym2)
+                       goto out;
+       }
+out:
+       if (sym2) {
+               printf(" %s", sym->name);
+               if (sym2 == sym) {
+                       printf("\n");
+                       sym2 = NULL;
+               }
+       }
+       sym->flags &= ~SYMBOL_CHECK;
+       return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+       struct property *prop;
+       struct property **propp;
+
+       prop = malloc(sizeof(*prop));
+       memset(prop, 0, sizeof(*prop));
+       prop->type = type;
+       prop->sym = sym;
+       prop->file = current_file;
+       prop->lineno = zconf_lineno();
+
+       /* append property to the prop list of symbol */
+       if (sym) {
+               for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+                       ;
+               *propp = prop;
+       }
+
+       return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+       if (prop->expr && (prop->expr->type == E_SYMBOL ||
+                          prop->expr->type == E_CHOICE))
+               return prop->expr->left.sym;
+       return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+       switch (type) {
+       case P_PROMPT:
+               return "prompt";
+       case P_COMMENT:
+               return "comment";
+       case P_MENU:
+               return "menu";
+       case P_DEFAULT:
+               return "default";
+       case P_CHOICE:
+               return "choice";
+       case P_SELECT:
+               return "select";
+       case P_RANGE:
+               return "range";
+       case P_UNKNOWN:
+               break;
+       }
+       return "unknown";
+}
diff --git a/kitten/scripts/kconfig/util.c b/kitten/scripts/kconfig/util.c
new file mode 100644 (file)
index 0000000..50439bc
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+       struct file *file;
+
+       for (file = file_list; file; file = file->next) {
+               if (!strcmp(name, file->name))
+                       return file;
+       }
+
+       file = malloc(sizeof(*file));
+       memset(file, 0, sizeof(*file));
+       file->name = strdup(name);
+       file->next = file_list;
+       file_list = file;
+       return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+       struct file *file;
+       FILE *out;
+
+       if (!name)
+               name = ".kconfig.d";
+       out = fopen("..config.tmp", "w");
+       if (!out)
+               return 1;
+       fprintf(out, "deps_config := \\\n");
+       for (file = file_list; file; file = file->next) {
+               if (file->next)
+                       fprintf(out, "\t%s \\\n", file->name);
+               else
+                       fprintf(out, "\t%s\n", file->name);
+       }
+       fprintf(out, "\n.config include/lwk/autoconf.h: $(deps_config)\n\n$(deps_config):\n");
+       fclose(out);
+       rename("..config.tmp", name);
+       return 0;
+}
+
+
+/* Allocate initial growable sting */
+struct gstr str_new(void)
+{
+       struct gstr gs;
+       gs.s = malloc(sizeof(char) * 64);
+       gs.len = 16;
+       strcpy(gs.s, "\0");
+       return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+       struct gstr gs;
+       gs.s = strdup(s);
+       gs.len = strlen(s) + 1;
+       return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+       if (gs->s)
+               free(gs->s);
+       gs->s = NULL;
+       gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+       size_t l = strlen(gs->s) + strlen(s) + 1;
+       if (l > gs->len) {
+               gs->s   = realloc(gs->s, l);
+               gs->len = l;
+       }
+       strcat(gs->s, s);
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+       va_list ap;
+       char s[10000]; /* big enough... */
+       va_start(ap, fmt);
+       vsnprintf(s, sizeof(s), fmt, ap);
+       str_append(gs, s);
+       va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+       return gs->s;
+}
+
diff --git a/kitten/scripts/kconfig/zconf.gperf b/kitten/scripts/kconfig/zconf.gperf
new file mode 100644 (file)
index 0000000..b032206
--- /dev/null
@@ -0,0 +1,43 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+%%
+mainmenu,      T_MAINMENU,     TF_COMMAND
+menu,          T_MENU,         TF_COMMAND
+endmenu,       T_ENDMENU,      TF_COMMAND
+source,                T_SOURCE,       TF_COMMAND
+choice,                T_CHOICE,       TF_COMMAND
+endchoice,     T_ENDCHOICE,    TF_COMMAND
+comment,       T_COMMENT,      TF_COMMAND
+config,                T_CONFIG,       TF_COMMAND
+menuconfig,    T_MENUCONFIG,   TF_COMMAND
+help,          T_HELP,         TF_COMMAND
+if,            T_IF,           TF_COMMAND|TF_PARAM
+endif,         T_ENDIF,        TF_COMMAND
+depends,       T_DEPENDS,      TF_COMMAND
+requires,      T_REQUIRES,     TF_COMMAND
+optional,      T_OPTIONAL,     TF_COMMAND
+default,       T_DEFAULT,      TF_COMMAND, S_UNKNOWN
+prompt,                T_PROMPT,       TF_COMMAND
+tristate,      T_TYPE,         TF_COMMAND, S_TRISTATE
+def_tristate,  T_DEFAULT,      TF_COMMAND, S_TRISTATE
+bool,          T_TYPE,         TF_COMMAND, S_BOOLEAN
+boolean,       T_TYPE,         TF_COMMAND, S_BOOLEAN
+def_bool,      T_DEFAULT,      TF_COMMAND, S_BOOLEAN
+def_boolean,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN
+int,           T_TYPE,         TF_COMMAND, S_INT
+hex,           T_TYPE,         TF_COMMAND, S_HEX
+string,                T_TYPE,         TF_COMMAND, S_STRING
+select,                T_SELECT,       TF_COMMAND
+enable,                T_SELECT,       TF_COMMAND
+range,         T_RANGE,        TF_COMMAND
+on,            T_ON,           TF_PARAM
+%%
diff --git a/kitten/scripts/kconfig/zconf.hash.c_shipped b/kitten/scripts/kconfig/zconf.hash.c_shipped
new file mode 100644 (file)
index 0000000..345f0fc
--- /dev/null
@@ -0,0 +1,231 @@
+/* ANSI-C code produced by gperf version 3.0.1 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 45, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 25, 10, 15,
+       0,  0,  5, 47,  0,  0, 47, 47,  0, 10,
+       0, 20, 20, 20,  5,  0,  0, 20, 47, 47,
+      20, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("if")];
+    char kconf_id_strings_str3[sizeof("int")];
+    char kconf_id_strings_str4[sizeof("help")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("select")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("tristate")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("string")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("menu")];
+    char kconf_id_strings_str16[sizeof("def_boolean")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("mainmenu")];
+    char kconf_id_strings_str20[sizeof("menuconfig")];
+    char kconf_id_strings_str21[sizeof("config")];
+    char kconf_id_strings_str22[sizeof("on")];
+    char kconf_id_strings_str23[sizeof("hex")];
+    char kconf_id_strings_str26[sizeof("source")];
+    char kconf_id_strings_str27[sizeof("depends")];
+    char kconf_id_strings_str28[sizeof("optional")];
+    char kconf_id_strings_str31[sizeof("enable")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("requires")];
+    char kconf_id_strings_str34[sizeof("bool")];
+    char kconf_id_strings_str37[sizeof("boolean")];
+    char kconf_id_strings_str41[sizeof("choice")];
+    char kconf_id_strings_str46[sizeof("prompt")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "if",
+    "int",
+    "help",
+    "endif",
+    "select",
+    "endmenu",
+    "tristate",
+    "endchoice",
+    "range",
+    "string",
+    "default",
+    "def_bool",
+    "menu",
+    "def_boolean",
+    "def_tristate",
+    "mainmenu",
+    "menuconfig",
+    "config",
+    "on",
+    "hex",
+    "source",
+    "depends",
+    "optional",
+    "enable",
+    "comment",
+    "requires",
+    "bool",
+    "boolean",
+    "choice",
+    "prompt"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 30,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 12,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 46
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,            T_IF,           TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,            T_TYPE,         TF_COMMAND, S_INT},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4,            T_HELP,         TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,            T_ENDIF,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,            T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,    T_ENDMENU,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,    T_TYPE,         TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,    T_ENDCHOICE,    TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,           T_RANGE,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,           T_TYPE,         TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,   T_DEFAULT,      TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,           T_MENU,         TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,   T_DEFAULT,      TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,   T_MAINMENU,     TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,   T_MENUCONFIG,   TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,           T_CONFIG,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,           T_ON,           TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,           T_TYPE,         TF_COMMAND, S_HEX},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,           T_SOURCE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,   T_DEPENDS,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,   T_OPTIONAL,     TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,           T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,   T_COMMENT,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,   T_REQUIRES,     TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34,           T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,   T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,           T_CHOICE,       TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,           T_PROMPT,       TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/kitten/scripts/kconfig/zconf.l b/kitten/scripts/kconfig/zconf.l
new file mode 100644 (file)
index 0000000..cfa4607
--- /dev/null
@@ -0,0 +1,350 @@
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup nodefault perf-report perf-report
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE  16
+
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+       text = malloc(START_STRSIZE);
+       text_asize = START_STRSIZE;
+       text_size = 0;
+       *text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+       int new_size = text_size + size + 1;
+       if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
+               text = realloc(text, new_size);
+               text_asize = new_size;
+       }
+       memcpy(text + text_size, str, size);
+       text_size += size;
+       text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+       text = malloc(size + 1);
+       memcpy(text, str, size);
+       text[size] = 0;
+}
+%}
+
+ws     [ \n\t]
+n      [A-Za-z0-9_]
+
+%%
+       int str = 0;
+       int ts, i;
+
+[ \t]*#.*\n    |
+[ \t]*\n       {
+       current_file->lineno++;
+       return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+ {
+       BEGIN(COMMAND);
+}
+
+.      {
+       unput(yytext[0]);
+       BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+       {n}+    {
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       .
+       \n      {
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
+}
+
+<PARAM>{
+       "&&"    return T_AND;
+       "||"    return T_OR;
+       "("     return T_OPEN_PAREN;
+       ")"     return T_CLOSE_PAREN;
+       "!"     return T_NOT;
+       "="     return T_EQUAL;
+       "!="    return T_UNEQUAL;
+       \"|\'   {
+               str = yytext[0];
+               new_string();
+               BEGIN(STRING);
+       }
+       \n      BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+       ---     /* ignore */
+       ({n}|[-/.])+    {
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
+               alloc_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD;
+       }
+       #.*     /* comment */
+       \\\n    current_file->lineno++;
+       .
+       <<EOF>> {
+               BEGIN(INITIAL);
+       }
+}
+
+<STRING>{
+       [^'"\\\n]+/\n   {
+               append_string(yytext, yyleng);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       [^'"\\\n]+      {
+               append_string(yytext, yyleng);
+       }
+       \\.?/\n {
+               append_string(yytext + 1, yyleng - 1);
+               zconflval.string = text;
+               return T_WORD_QUOTE;
+       }
+       \\.?    {
+               append_string(yytext + 1, yyleng - 1);
+       }
+       \'|\"   {
+               if (str == yytext[0]) {
+                       BEGIN(PARAM);
+                       zconflval.string = text;
+                       return T_WORD_QUOTE;
+               } else
+                       append_string(yytext, 1);
+       }
+       \n      {
+               printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+               current_file->lineno++;
+               BEGIN(INITIAL);
+               return T_EOL;
+       }
+       <<EOF>> {
+               BEGIN(INITIAL);
+       }
+}
+
+<HELP>{
+       [ \t]+  {
+               ts = 0;
+               for (i = 0; i < yyleng; i++) {
+                       if (yytext[i] == '\t')
+                               ts = (ts & ~7) + 8;
+                       else
+                               ts++;
+               }
+               last_ts = ts;
+               if (first_ts) {
+                       if (ts < first_ts) {
+                               zconf_endhelp();
+                               return T_HELPTEXT;
+                       }
+                       ts -= first_ts;
+                       while (ts > 8) {
+                               append_string("        ", 8);
+                               ts -= 8;
+                       }
+                       append_string("        ", ts);
+               }
+       }
+       [ \t]*\n/[^ \t\n] {
+               current_file->lineno++;
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+       [ \t]*\n        {
+               current_file->lineno++;
+               append_string("\n", 1);
+       }
+       [^ \t\n].* {
+               append_string(yytext, yyleng);
+               if (!first_ts)
+                       first_ts = last_ts;
+       }
+       <<EOF>> {
+               zconf_endhelp();
+               return T_HELPTEXT;
+       }
+}
+
+<<EOF>>        {
+       if (current_file) {
+               zconf_endfile();
+               return T_EOL;
+       }
+       fclose(yyin);
+       yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+       new_string();
+       last_ts = first_ts = 0;
+       BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+       zconflval.string = text;
+       BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+       char *env, fullname[PATH_MAX+1];
+       FILE *f;
+
+       f = fopen(name, "r");
+       if (!f && name[0] != '/') {
+               env = getenv(SRCTREE);
+               if (env) {
+                       sprintf(fullname, "%s/%s", env, name);
+                       f = fopen(fullname, "r");
+               }
+       }
+       return f;
+}
+
+void zconf_initscan(const char *name)
+{
+       yyin = zconf_fopen(name);
+       if (!yyin) {
+               printf("can't find file %s\n", name);
+               exit(1);
+       }
+
+       current_buf = malloc(sizeof(*current_buf));
+       memset(current_buf, 0, sizeof(*current_buf));
+
+       current_file = file_lookup(name);
+       current_file->lineno = 1;
+       current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+       struct file *file = file_lookup(name);
+       struct buffer *buf = malloc(sizeof(*buf));
+       memset(buf, 0, sizeof(*buf));
+
+       current_buf->state = YY_CURRENT_BUFFER;
+       yyin = zconf_fopen(name);
+       if (!yyin) {
+               printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+               exit(1);
+       }
+       yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+       buf->parent = current_buf;
+       current_buf = buf;
+
+       if (file->flags & FILE_BUSY) {
+               printf("recursive scan (%s)?\n", name);
+               exit(1);
+       }
+       if (file->flags & FILE_SCANNED) {
+               printf("file %s already scanned?\n", name);
+               exit(1);
+       }
+       file->flags |= FILE_BUSY;
+       file->lineno = 1;
+       file->parent = current_file;
+       current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+       struct buffer *parent;
+
+       current_file->flags |= FILE_SCANNED;
+       current_file->flags &= ~FILE_BUSY;
+       current_file = current_file->parent;
+
+       parent = current_buf->parent;
+       if (parent) {
+               fclose(yyin);
+               yy_delete_buffer(YY_CURRENT_BUFFER);
+               yy_switch_to_buffer(parent->state);
+       }
+       free(current_buf);
+       current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+       return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+       return current_pos.file ? current_pos.file->name : "<none>";
+}
diff --git a/kitten/scripts/kconfig/zconf.tab.c_shipped b/kitten/scripts/kconfig/zconf.tab.c_shipped
new file mode 100644 (file)
index 0000000..1160817
--- /dev/null
@@ -0,0 +1,2173 @@
+/* A Bison parser, made by GNU Bison 2.0.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, 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, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse zconfparse
+#define yylex   zconflex
+#define yyerror zconferror
+#define yylval  zconflval
+#define yychar  zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_MENUCONFIG = 266,
+     T_HELP = 267,
+     T_HELPTEXT = 268,
+     T_IF = 269,
+     T_ENDIF = 270,
+     T_DEPENDS = 271,
+     T_REQUIRES = 272,
+     T_OPTIONAL = 273,
+     T_PROMPT = 274,
+     T_TYPE = 275,
+     T_DEFAULT = 276,
+     T_SELECT = 277,
+     T_RANGE = 278,
+     T_ON = 279,
+     T_WORD = 280,
+     T_WORD_QUOTE = 281,
+     T_UNEQUAL = 282,
+     T_CLOSE_PAREN = 283,
+     T_OPEN_PAREN = 284,
+     T_EOL = 285,
+     T_OR = 286,
+     T_AND = 287,
+     T_EQUAL = 288,
+     T_NOT = 289
+   };
+#endif
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_MENUCONFIG 266
+#define T_HELP 267
+#define T_HELPTEXT 268
+#define T_IF 269
+#define T_ENDIF 270
+#define T_DEPENDS 271
+#define T_REQUIRES 272
+#define T_OPTIONAL 273
+#define T_PROMPT 274
+#define T_TYPE 275
+#define T_DEFAULT 276
+#define T_SELECT 277
+#define T_RANGE 278
+#define T_ON 279
+#define T_WORD 280
+#define T_WORD_QUOTE 281
+#define T_UNEQUAL 282
+#define T_CLOSE_PAREN 283
+#define T_OPEN_PAREN 284
+#define T_EOL 285
+#define T_OR 286
+#define T_AND 287
+#define T_EQUAL 288
+#define T_NOT 289
+
+
+
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD         0x0001
+#define DEBUG_PARSE    0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+
+typedef union YYSTYPE {
+       char *string;
+       struct file *file;
+       struct symbol *symbol;
+       struct expr *expr;
+       struct menu *menu;
+       struct kconf_id *id;
+} YYSTYPE;
+/* Line 190 of yacc.c.  */
+
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 213 of yacc.c.  */
+
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+#  define YYFREE free
+# endif
+# ifndef YYMALLOC
+#  define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+#  if defined (__STDC__) || defined (__cplusplus)
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   define YYSIZE_T size_t
+#  endif
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+        || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short int yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))                    \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined (__GNUC__) && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         register YYSIZE_T yyi;                \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   264
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  35
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  42
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  104
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  175
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   289
+
+#define YYTRANSLATE(YYX)                                               \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned short int yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   104,   109,
+     114,   119,   125,   128,   131,   133,   137,   138,   141,   144,
+     147,   150,   153,   158,   162,   165,   170,   171,   174,   178,
+     180,   184,   185,   188,   191,   194,   198,   201,   203,   207,
+     208,   211,   214,   217,   221,   225,   228,   231,   234,   235,
+     238,   241,   244,   249,   253,   257,   258,   261,   263,   265,
+     268,   271,   274,   276,   279,   280,   283,   285,   289,   293,
+     297,   300,   304,   308,   310
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      36,     0,    -1,    37,    -1,    -1,    37,    39,    -1,    37,
+      50,    -1,    37,    61,    -1,    37,     3,    71,    73,    -1,
+      37,    72,    -1,    37,    25,     1,    30,    -1,    37,    38,
+       1,    30,    -1,    37,     1,    30,    -1,    16,    -1,    19,
+      -1,    20,    -1,    22,    -1,    18,    -1,    23,    -1,    21,
+      -1,    30,    -1,    56,    -1,    65,    -1,    42,    -1,    44,
+      -1,    63,    -1,    25,     1,    30,    -1,     1,    30,    -1,
+      10,    25,    30,    -1,    41,    45,    -1,    11,    25,    30,
+      -1,    43,    45,    -1,    -1,    45,    46,    -1,    45,    69,
+      -1,    45,    67,    -1,    45,    40,    -1,    45,    30,    -1,
+      20,    70,    30,    -1,    19,    71,    74,    30,    -1,    21,
+      75,    74,    30,    -1,    22,    25,    74,    30,    -1,    23,
+      76,    76,    74,    30,    -1,     7,    30,    -1,    47,    51,
+      -1,    72,    -1,    48,    53,    49,    -1,    -1,    51,    52,
+      -1,    51,    69,    -1,    51,    67,    -1,    51,    30,    -1,
+      51,    40,    -1,    19,    71,    74,    30,    -1,    20,    70,
+      30,    -1,    18,    30,    -1,    21,    25,    74,    30,    -1,
+      -1,    53,    39,    -1,    14,    75,    73,    -1,    72,    -1,
+      54,    57,    55,    -1,    -1,    57,    39,    -1,    57,    61,
+      -1,    57,    50,    -1,     4,    71,    30,    -1,    58,    68,
+      -1,    72,    -1,    59,    62,    60,    -1,    -1,    62,    39,
+      -1,    62,    61,    -1,    62,    50,    -1,     6,    71,    30,
+      -1,     9,    71,    30,    -1,    64,    68,    -1,    12,    30,
+      -1,    66,    13,    -1,    -1,    68,    69,    -1,    68,    30,
+      -1,    68,    40,    -1,    16,    24,    75,    30,    -1,    16,
+      75,    30,    -1,    17,    75,    30,    -1,    -1,    71,    74,
+      -1,    25,    -1,    26,    -1,     5,    30,    -1,     8,    30,
+      -1,    15,    30,    -1,    30,    -1,    73,    30,    -1,    -1,
+      14,    75,    -1,    76,    -1,    76,    33,    76,    -1,    76,
+      27,    76,    -1,    29,    75,    28,    -1,    34,    75,    -1,
+      75,    31,    75,    -1,    75,    32,    75,    -1,    25,    -1,
+      26,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned short int yyrline[] =
+{
+       0,   103,   103,   105,   107,   108,   109,   110,   111,   112,
+     113,   117,   121,   121,   121,   121,   121,   121,   121,   125,
+     126,   127,   128,   129,   130,   134,   135,   141,   149,   155,
+     163,   173,   175,   176,   177,   178,   179,   182,   190,   196,
+     206,   212,   220,   229,   234,   242,   245,   247,   248,   249,
+     250,   251,   254,   260,   271,   277,   287,   289,   294,   302,
+     310,   313,   315,   316,   317,   322,   329,   334,   342,   345,
+     347,   348,   349,   352,   360,   367,   374,   380,   387,   389,
+     390,   391,   394,   399,   404,   412,   414,   419,   420,   423,
+     424,   425,   429,   430,   433,   434,   437,   438,   439,   440,
+     441,   442,   443,   446,   447
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT",
+  "T_SELECT", "T_RANGE", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt",
+  "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "choice", "choice_entry", "choice_end", "choice_stmt",
+  "choice_option_list", "choice_option", "choice_block", "if_entry",
+  "if_end", "if_stmt", "if_block", "menu", "menu_entry", "menu_end",
+  "menu_stmt", "menu_block", "source_stmt", "comment", "comment_stmt",
+  "help_start", "help", "depends_list", "depends", "prompt_stmt_opt",
+  "prompt", "end", "nl", "if_expr", "expr", "symbol", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short int yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    35,    36,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    38,    38,    38,    38,    38,    38,    38,    39,
+      39,    39,    39,    39,    39,    40,    40,    41,    42,    43,
+      44,    45,    45,    45,    45,    45,    45,    46,    46,    46,
+      46,    46,    47,    48,    49,    50,    51,    51,    51,    51,
+      51,    51,    52,    52,    52,    52,    53,    53,    54,    55,
+      56,    57,    57,    57,    57,    58,    59,    60,    61,    62,
+      62,    62,    62,    63,    64,    65,    66,    67,    68,    68,
+      68,    68,    69,    69,    69,    70,    70,    71,    71,    72,
+      72,    72,    73,    73,    74,    74,    75,    75,    75,    75,
+      75,    75,    75,    76,    76
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     3,     4,     4,
+       4,     5,     2,     2,     1,     3,     0,     2,     2,     2,
+       2,     2,     4,     3,     2,     4,     0,     2,     3,     1,
+       3,     0,     2,     2,     2,     3,     2,     1,     3,     0,
+       2,     2,     2,     3,     3,     2,     2,     2,     0,     2,
+       2,     2,     4,     3,     3,     0,     2,     1,     1,     2,
+       2,     2,     1,     2,     0,     2,     1,     3,     3,     3,
+       2,     3,     3,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       3,     0,     0,     1,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    46,    56,     5,    61,    20,    78,    69,     6,    24,
+      78,    21,     8,    11,    87,    88,     0,     0,    89,     0,
+      42,    90,     0,     0,     0,   103,   104,     0,     0,     0,
+      96,    91,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    92,     7,    65,    73,    74,    27,    29,     0,
+     100,     0,     0,    58,     0,     0,     9,    10,     0,     0,
+       0,     0,     0,    85,     0,     0,     0,     0,    36,    35,
+      32,     0,    34,    33,     0,     0,    85,     0,    50,    51,
+      47,    49,    48,    57,    45,    44,    62,    64,    60,    63,
+      59,    80,    81,    79,    70,    72,    68,    71,    67,    93,
+      99,   101,   102,    98,    97,    26,    76,     0,     0,     0,
+      94,     0,    94,    94,    94,     0,     0,    77,    54,    94,
+       0,    94,     0,    83,    84,     0,     0,    37,    86,     0,
+       0,    94,    25,     0,    53,     0,    82,    95,    38,    39,
+      40,     0,    52,    55,    41
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
+{
+      -1,     1,     2,    25,    26,    99,    27,    28,    29,    30,
+      64,   100,    31,    32,   114,    33,    66,   110,    67,    34,
+     118,    35,    68,    36,    37,   126,    38,    70,    39,    40,
+      41,   101,   102,    69,   103,   141,   142,    42,    73,   156,
+      59,    60
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -78
+static const short int yypact[] =
+{
+     -78,     2,   159,   -78,   -21,     0,     0,   -12,     0,     1,
+       4,     0,    27,    38,    60,    58,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   100,   -78,   104,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    86,   113,   -78,   114,
+     -78,   -78,   125,   127,   128,   -78,   -78,    60,    60,   210,
+      65,   -78,   141,   142,    39,   103,   182,   200,     6,    66,
+       6,   131,   -78,   146,   -78,   -78,   -78,   -78,   -78,   196,
+     -78,    60,    60,   146,    40,    40,   -78,   -78,   155,   156,
+      -2,    60,     0,     0,    60,   105,    40,   194,   -78,   -78,
+     -78,   206,   -78,   -78,   183,     0,     0,   195,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   197,   -78,   -78,   -78,   -78,   -78,    60,   213,   216,
+     212,   203,   212,   190,   212,    40,   208,   -78,   -78,   212,
+     222,   212,   219,   -78,   -78,    60,   223,   -78,   -78,   224,
+     225,   212,   -78,   226,   -78,   227,   -78,    47,   -78,   -78,
+     -78,   228,   -78,   -78,   -78
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const short int yypgoto[] =
+{
+     -78,   -78,   -78,   -78,   164,   -36,   -78,   -78,   -78,   -78,
+     230,   -78,   -78,   -78,   -78,    29,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    59,   -78,   -78,   -78,
+     -78,   -78,   198,   220,    24,   157,    -5,   169,   202,    74,
+     -53,   -77
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -76
+static const short int yytable[] =
+{
+      46,    47,     3,    49,    79,    80,    52,   133,   134,    43,
+       6,     7,     8,     9,    10,    11,    12,    13,    48,   145,
+      14,    15,   137,    55,    56,    44,    45,    57,   131,   132,
+     109,    50,    58,   122,    51,   122,    24,   138,   139,   -28,
+      88,   143,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
+     -28,    89,    53,   -28,   -28,    90,    91,   -28,    92,    93,
+      94,    95,    96,    54,    97,    55,    56,    88,   161,    98,
+     -66,   -66,   -66,   -66,   -66,   -66,   -66,   -66,    81,    82,
+     -66,   -66,    90,    91,   152,    55,    56,   140,    61,    57,
+     112,    97,    84,   123,    58,   123,   121,   117,    85,   125,
+     149,    62,   167,   -30,    88,    63,   -30,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,    89,    72,   -30,   -30,    90,
+      91,   -30,    92,    93,    94,    95,    96,   119,    97,   127,
+     144,   -75,    88,    98,   -75,   -75,   -75,   -75,   -75,   -75,
+     -75,   -75,   -75,    74,    75,   -75,   -75,    90,    91,   -75,
+     -75,   -75,   -75,   -75,   -75,    76,    97,    77,    78,    -2,
+       4,   121,     5,     6,     7,     8,     9,    10,    11,    12,
+      13,    86,    87,    14,    15,    16,   129,    17,    18,    19,
+      20,    21,    22,    88,    23,   135,   136,   -43,   -43,    24,
+     -43,   -43,   -43,   -43,    89,   146,   -43,   -43,    90,    91,
+     104,   105,   106,   107,   155,     7,     8,    97,    10,    11,
+      12,    13,   108,   148,    14,    15,   158,   159,   160,   147,
+     151,    81,    82,   163,   130,   165,   155,    81,    82,    82,
+      24,   113,   116,   157,   124,   171,   115,   120,   162,   128,
+      72,    81,    82,   153,    81,    82,   154,    81,    82,   166,
+      81,    82,   164,   168,   169,   170,   172,   173,   174,    65,
+      71,    83,     0,   150,   111
+};
+
+static const short int yycheck[] =
+{
+       5,     6,     0,     8,    57,    58,    11,    84,    85,    30,
+       4,     5,     6,     7,     8,     9,    10,    11,    30,    96,
+      14,    15,    24,    25,    26,    25,    26,    29,    81,    82,
+      66,    30,    34,    69,    30,    71,    30,    90,    91,     0,
+       1,    94,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    25,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    25,    25,    25,    26,     1,   145,    30,
+       4,     5,     6,     7,     8,     9,    10,    11,    31,    32,
+      14,    15,    16,    17,   137,    25,    26,    92,    30,    29,
+      66,    25,    27,    69,    34,    71,    30,    68,    33,    70,
+     105,     1,   155,     0,     1,     1,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    30,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    68,    25,    70,
+      25,     0,     1,    30,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,    30,    30,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    30,    25,    30,    30,     0,
+       1,    30,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    30,    30,    14,    15,    16,    30,    18,    19,    20,
+      21,    22,    23,     1,    25,    30,    30,     5,     6,    30,
+       8,     9,    10,    11,    12,     1,    14,    15,    16,    17,
+      18,    19,    20,    21,    14,     5,     6,    25,     8,     9,
+      10,    11,    30,    30,    14,    15,   142,   143,   144,    13,
+      25,    31,    32,   149,    28,   151,    14,    31,    32,    32,
+      30,    67,    68,    30,    70,   161,    67,    68,    30,    70,
+      30,    31,    32,    30,    31,    32,    30,    31,    32,    30,
+      31,    32,    30,    30,    30,    30,    30,    30,    30,    29,
+      40,    59,    -1,   106,    66
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    18,    19,    20,
+      21,    22,    23,    25,    30,    38,    39,    41,    42,    43,
+      44,    47,    48,    50,    54,    56,    58,    59,    61,    63,
+      64,    65,    72,    30,    25,    26,    71,    71,    30,    71,
+      30,    30,    71,    25,    25,    25,    26,    29,    34,    75,
+      76,    30,     1,     1,    45,    45,    51,    53,    57,    68,
+      62,    68,    30,    73,    30,    30,    30,    30,    30,    75,
+      75,    31,    32,    73,    27,    33,    30,    30,     1,    12,
+      16,    17,    19,    20,    21,    22,    23,    25,    30,    40,
+      46,    66,    67,    69,    18,    19,    20,    21,    30,    40,
+      52,    67,    69,    39,    49,    72,    39,    50,    55,    61,
+      72,    30,    40,    69,    39,    50,    60,    61,    72,    30,
+      28,    75,    75,    76,    76,    30,    30,    24,    75,    75,
+      71,    70,    71,    75,    25,    76,     1,    13,    30,    71,
+      70,    25,    75,    30,    30,    14,    74,    30,    74,    74,
+      74,    76,    30,    74,    30,    74,    30,    75,    30,    30,
+      30,    74,    30,    30,    30
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok                (yyerrstatus = 0)
+#define yyclearin      (yychar = YYEMPTY)
+#define YYEMPTY                (-2)
+#define YYEOF          0
+
+#define YYACCEPT       goto yyacceptlab
+#define YYABORT                goto yyabortlab
+#define YYERROR                goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL         goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                 \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    {                                                          \
+      yychar = (Token);                                                \
+      yylval = (Value);                                                \
+      yytoken = YYTRANSLATE (yychar);                          \
+      YYPOPSTACK;                                              \
+      goto yybackup;                                           \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      yyerror ("syntax error: cannot back up");\
+      YYERROR;                                                 \
+    }                                                          \
+while (0)
+
+
+#define YYTERROR       1
+#define YYERRCODE      256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
+    do                                                                 \
+      if (N)                                                           \
+       {                                                               \
+         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+       }                                                               \
+      else                                                             \
+       {                                                               \
+         (Current).first_line   = (Current).last_line   =              \
+           YYRHSLOC (Rhs, 0).last_line;                                \
+         (Current).first_column = (Current).last_column =              \
+           YYRHSLOC (Rhs, 0).last_column;                              \
+       }                                                               \
+    while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)                 \
+     fprintf (File, "%d.%d-%d.%d",                     \
+              (Loc).first_line, (Loc).first_column,    \
+              (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                       \
+do {                                           \
+  if (yydebug)                                 \
+    YYFPRINTF Args;                            \
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)         \
+do {                                                           \
+  if (yydebug)                                                 \
+    {                                                          \
+      YYFPRINTF (stderr, "%s ", Title);                                \
+      yysymprint (stderr,                                      \
+                  Type, Value);        \
+      YYFPRINTF (stderr, "\n");                                        \
+    }                                                          \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short int *bottom;
+    short int *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                           \
+do {                                                           \
+  if (yydebug)                                                 \
+    yy_stack_print ((Bottom), (Top));                          \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+             yyrule - 1, yylno);
+  /* Print the symbols being reduced, and their result.  */
+  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+    YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)         \
+do {                                   \
+  if (yydebug)                         \
+    yy_reduce_print (Rule);            \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef        YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+\f
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 48: /* choice_entry */
+
+        {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+        break;
+      case 54: /* if_entry */
+
+        {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+        break;
+      case 59: /* menu_entry */
+
+        {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+        break;
+
+      default:
+        break;
+    }
+}
+\f
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+  void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  register short int *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;            /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+
+  yyvsp[0] = yylval;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+       /* Give user a chance to reallocate the stack. Use copies of
+          these so that the &'s don't force the real ones into
+          memory.  */
+       YYSTYPE *yyvs1 = yyvs;
+       short int *yyss1 = yyss;
+
+
+       /* Each stack pointer address is followed by the size of the
+          data in use in that stack, in bytes.  This used to be a
+          conditional around just the two extra args, but that might
+          be undefined if yyoverflow is a macro.  */
+       yyoverflow ("parser stack overflow",
+                   &yyss1, yysize * sizeof (*yyssp),
+                   &yyvs1, yysize * sizeof (*yyvsp),
+
+                   &yystacksize);
+
+       yyss = yyss1;
+       yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+       goto yyoverflowlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+       yystacksize = YYMAXDEPTH;
+
+      {
+       short int *yyss1 = yyss;
+       union yyalloc *yyptr =
+         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+       if (! yyptr)
+         goto yyoverflowlab;
+       YYSTACK_RELOCATE (yyss);
+       YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+       if (yyss1 != yyssa)
+         YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                 (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+       YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a look-ahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+       goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 8:
+
+    { zconf_error("unexpected end statement"); ;}
+    break;
+
+  case 9:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); ;}
+    break;
+
+  case 10:
+
+    {
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name);
+;}
+    break;
+
+  case 11:
+
+    { zconf_error("invalid statement"); ;}
+    break;
+
+  case 25:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); ;}
+    break;
+
+  case 26:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 27:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+;}
+    break;
+
+  case 28:
+
+    {
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 29:
+
+    {
+       struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+;}
+    break;
+
+  case 30:
+
+    {
+       if (current_entry->prompt)
+               current_entry->prompt->type = P_MENU;
+       else
+               zconfprint("warning: menuconfig statement without prompt");
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 37:
+
+    {
+       menu_set_type((yyvsp[-2].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[-2].id)->stype);
+;}
+    break;
+
+  case 38:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 39:
+
+    {
+       menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
+       if ((yyvsp[-3].id)->stype != S_UNKNOWN)
+               menu_set_type((yyvsp[-3].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[-3].id)->stype);
+;}
+    break;
+
+  case 40:
+
+    {
+       menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 41:
+
+    {
+       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 42:
+
+    {
+       struct symbol *sym = sym_lookup(NULL, 0);
+       sym->flags |= SYMBOL_CHOICE;
+       menu_add_entry(sym);
+       menu_add_expr(P_CHOICE, NULL, NULL);
+       printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 43:
+
+    {
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 44:
+
+    {
+       if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 52:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 53:
+
+    {
+       if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
+               menu_set_type((yyvsp[-2].id)->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       (yyvsp[-2].id)->stype);
+       } else
+               YYERROR;
+;}
+    break;
+
+  case 54:
+
+    {
+       current_entry->sym->flags |= SYMBOL_OPTIONAL;
+       printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 55:
+
+    {
+       if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
+;}
+    break;
+
+  case 58:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+       menu_add_entry(NULL);
+       menu_add_dep((yyvsp[-1].expr));
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 59:
+
+    {
+       if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 65:
+
+    {
+       menu_add_entry(NULL);
+       menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
+       printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 66:
+
+    {
+       (yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 67:
+
+    {
+       if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+       }
+;}
+    break;
+
+  case 73:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+       zconf_nextfile((yyvsp[-1].string));
+;}
+    break;
+
+  case 74:
+
+    {
+       menu_add_entry(NULL);
+       menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
+       printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 75:
+
+    {
+       menu_end_entry();
+;}
+    break;
+
+  case 76:
+
+    {
+       printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+       zconf_starthelp();
+;}
+    break;
+
+  case 77:
+
+    {
+       current_entry->sym->help = (yyvsp[0].string);
+;}
+    break;
+
+  case 82:
+
+    {
+       menu_add_dep((yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 83:
+
+    {
+       menu_add_dep((yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 84:
+
+    {
+       menu_add_dep((yyvsp[-1].expr));
+       printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 86:
+
+    {
+       menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
+;}
+    break;
+
+  case 89:
+
+    { (yyval.id) = (yyvsp[-1].id); ;}
+    break;
+
+  case 90:
+
+    { (yyval.id) = (yyvsp[-1].id); ;}
+    break;
+
+  case 91:
+
+    { (yyval.id) = (yyvsp[-1].id); ;}
+    break;
+
+  case 94:
+
+    { (yyval.expr) = NULL; ;}
+    break;
+
+  case 95:
+
+    { (yyval.expr) = (yyvsp[0].expr); ;}
+    break;
+
+  case 96:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;}
+    break;
+
+  case 97:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
+    break;
+
+  case 98:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
+    break;
+
+  case 99:
+
+    { (yyval.expr) = (yyvsp[-1].expr); ;}
+    break;
+
+  case 100:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;}
+    break;
+
+  case 101:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    break;
+
+  case 102:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    break;
+
+  case 103:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;}
+    break;
+
+  case 104:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 1); free((yyvsp[0].string)); ;}
+    break;
+
+
+    }
+
+/* Line 1037 of yacc.c.  */
+
+\f
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+       {
+         YYSIZE_T yysize = 0;
+         int yytype = YYTRANSLATE (yychar);
+         const char* yyprefix;
+         char *yymsg;
+         int yyx;
+
+         /* Start YYX at -YYN if negative to avoid negative indexes in
+            YYCHECK.  */
+         int yyxbegin = yyn < 0 ? -yyn : 0;
+
+         /* Stay within bounds of both yycheck and yytname.  */
+         int yychecklim = YYLAST - yyn;
+         int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+         int yycount = 0;
+
+         yyprefix = ", expecting ";
+         for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+           if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+             {
+               yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+               yycount += 1;
+               if (yycount == 5)
+                 {
+                   yysize = 0;
+                   break;
+                 }
+             }
+         yysize += (sizeof ("syntax error, unexpected ")
+                    + yystrlen (yytname[yytype]));
+         yymsg = (char *) YYSTACK_ALLOC (yysize);
+         if (yymsg != 0)
+           {
+             char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+             yyp = yystpcpy (yyp, yytname[yytype]);
+
+             if (yycount < 5)
+               {
+                 yyprefix = ", expecting ";
+                 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+                   if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+                     {
+                       yyp = yystpcpy (yyp, yyprefix);
+                       yyp = yystpcpy (yyp, yytname[yyx]);
+                       yyprefix = " or ";
+                     }
+               }
+             yyerror (yymsg);
+             YYSTACK_FREE (yymsg);
+           }
+         else
+           yyerror ("syntax error; also virtual memory exhausted");
+       }
+      else
+#endif /* YYERROR_VERBOSE */
+       yyerror ("syntax error");
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+        error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* If at end of input, pop the error token,
+            then the rest of the stack, then return failure.  */
+         if (yychar == YYEOF)
+            for (;;)
+              {
+
+                YYPOPSTACK;
+                if (yyssp == yyss)
+                  YYABORT;
+                yydestruct ("Error: popping",
+                             yystos[*yyssp], yyvsp);
+              }
+        }
+      else
+       {
+         yydestruct ("Error: discarding", yytoken, &yylval);
+         yychar = YYEMPTY;
+       }
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+  /* Pacify GCC when the user code never invokes YYERROR and the label
+     yyerrorlab therefore never appears in user code.  */
+  if (0)
+     goto yyerrorlab;
+#endif
+
+yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+       {
+         yyn += YYTERROR;
+         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+           {
+             yyn = yytable[yyn];
+             if (0 < yyn)
+               break;
+           }
+       }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+       YYABORT;
+
+
+      yydestruct ("Error: popping", yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token. */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yydestruct ("Error: discarding lookahead",
+              yytoken, &yylval);
+  yychar = YYEMPTY;
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here.  |
+`----------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+       struct symbol *sym;
+       int i;
+
+       zconf_initscan(name);
+
+       sym_init();
+       menu_init();
+       modules_sym = sym_lookup("MODULES", 0);
+       rootmenu.prompt = menu_add_prompt(P_MENU, "LWK Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       menu_finalize(&rootmenu);
+       for_all_symbols(i, sym) {
+               sym_check_deps(sym);
+        }
+
+       sym_change_count = 1;
+}
+
+const char *zconf_tokenname(int token)
+{
+       switch (token) {
+       case T_MENU:            return "menu";
+       case T_ENDMENU:         return "endmenu";
+       case T_CHOICE:          return "choice";
+       case T_ENDCHOICE:       return "endchoice";
+       case T_IF:              return "if";
+       case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
+       }
+       return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       if (current_menu->file != current_file) {
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+       const char *p;
+       int len;
+
+       putc('"', out);
+       while ((p = strchr(str, '"'))) {
+               len = p - str;
+               if (len)
+                       fprintf(out, "%.*s", len, str);
+               fputs("\\\"", out);
+               str = p + 1;
+       }
+       fputs(str, out);
+       putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       struct property *prop;
+
+       if (sym_is_choice(sym))
+               fprintf(out, "choice\n");
+       else
+               fprintf(out, "config %s\n", sym->name);
+       switch (sym->type) {
+       case S_BOOLEAN:
+               fputs("  boolean\n", out);
+               break;
+       case S_TRISTATE:
+               fputs("  tristate\n", out);
+               break;
+       case S_STRING:
+               fputs("  string\n", out);
+               break;
+       case S_INT:
+               fputs("  integer\n", out);
+               break;
+       case S_HEX:
+               fputs("  hex\n", out);
+               break;
+       default:
+               fputs("  ???\n", out);
+               break;
+       }
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu != menu)
+                       continue;
+               switch (prop->type) {
+               case P_PROMPT:
+                       fputs("  prompt ", out);
+                       print_quoted_string(out, prop->text);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_DEFAULT:
+                       fputs( "  default ", out);
+                       expr_fprint(prop->expr, out);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_CHOICE:
+                       fputs("  #choice value\n", out);
+                       break;
+               default:
+                       fprintf(out, "  unknown prop %d!\n", prop->type);
+                       break;
+               }
+       }
+       if (sym->help) {
+               int len = strlen(sym->help);
+               while (sym->help[--len] == '\n')
+                       sym->help[len] = 0;
+               fprintf(out, "  help\n%s\n", sym->help);
+       }
+       fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct menu *menu;
+
+       menu = rootmenu.list;
+       while (menu) {
+               if ((sym = menu->sym))
+                       print_symbol(out, menu);
+               else if ((prop = menu->prompt)) {
+                       switch (prop->type) {
+                       case P_COMMENT:
+                               fputs("\ncomment ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       case P_MENU:
+                               fputs("\nmenu ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       default:
+                               ;
+                       }
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs("  depends ", out);
+                               expr_fprint(prop->visible.expr, out);
+                               fputc('\n', out);
+                       }
+                       fputs("\n", out);
+               }
+
+               if (menu->list)
+                       menu = menu->list;
+               else if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->prompt && menu->prompt->type == P_MENU)
+                               fputs("\nendmenu\n", out);
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
+
diff --git a/kitten/scripts/kconfig/zconf.y b/kitten/scripts/kconfig/zconf.y
new file mode 100644 (file)
index 0000000..d8c4e5a
--- /dev/null
@@ -0,0 +1,681 @@
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD         0x0001
+#define DEBUG_PARSE    0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+%}
+%expect 26
+
+%union
+{
+       char *string;
+       struct file *file;
+       struct symbol *symbol;
+       struct expr *expr;
+       struct menu *menu;
+       struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_REQUIRES
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+
+%destructor {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               $$->file->name, $$->lineno);
+       if (current_menu == $$)
+               menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%%
+input: stmt_list;
+
+stmt_list:
+         /* empty */
+       | stmt_list common_stmt
+       | stmt_list choice_stmt
+       | stmt_list menu_stmt
+       | stmt_list T_MAINMENU prompt nl
+       | stmt_list end                 { zconf_error("unexpected end statement"); }
+       | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement \"%s\"", $2); }
+       | stmt_list option_name error T_EOL
+{
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+       | stmt_list error T_EOL         { zconf_error("invalid statement"); }
+;
+
+option_name:
+       T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
+;
+
+common_stmt:
+         T_EOL
+       | if_stmt
+       | comment_stmt
+       | config_stmt
+       | menuconfig_stmt
+       | source_stmt
+;
+
+option_error:
+         T_WORD error T_EOL            { zconf_error("unknown option \"%s\"", $1); }
+       | error T_EOL                   { zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+       struct symbol *sym = sym_lookup($2, 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+       struct symbol *sym = sym_lookup($2, 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+       if (current_entry->prompt)
+               current_entry->prompt->type = P_MENU;
+       else
+               zconfprint("warning: menuconfig statement without prompt");
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+         /* empty */
+       | config_option_list config_option
+       | config_option_list depends
+       | config_option_list help
+       | config_option_list option_error
+       | config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+       menu_set_type($1->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               $1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+       menu_add_prompt(P_PROMPT, $2, $3);
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+       menu_add_expr(P_DEFAULT, $2, $3);
+       if ($1->stype != S_UNKNOWN)
+               menu_set_type($1->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               $1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+       menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+       printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+       printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+/* choice entry */
+
+choice: T_CHOICE T_EOL
+{
+       struct symbol *sym = sym_lookup(NULL, 0);
+       sym->flags |= SYMBOL_CHOICE;
+       menu_add_entry(sym);
+       menu_add_expr(P_CHOICE, NULL, NULL);
+       printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+       $$ = menu_add_menu();
+};
+
+choice_end: end
+{
+       if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+       }
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+         /* empty */
+       | choice_option_list choice_option
+       | choice_option_list depends
+       | choice_option_list help
+       | choice_option_list T_EOL
+       | choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+       menu_add_prompt(P_PROMPT, $2, $3);
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+       if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+               menu_set_type($1->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       $1->stype);
+       } else
+               YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+       current_entry->sym->flags |= SYMBOL_OPTIONAL;
+       printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+       if ($1->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
+};
+
+choice_block:
+         /* empty */
+       | choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+       printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+       menu_add_entry(NULL);
+       menu_add_dep($2);
+       $$ = menu_add_menu();
+};
+
+if_end: end
+{
+       if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+       }
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+         /* empty */
+       | if_block common_stmt
+       | if_block menu_stmt
+       | if_block choice_stmt
+;
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+       menu_add_entry(NULL);
+       menu_add_prompt(P_MENU, $2, NULL);
+       printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu depends_list
+{
+       $$ = menu_add_menu();
+};
+
+menu_end: end
+{
+       if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+               menu_end_menu();
+               printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+       }
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+         /* empty */
+       | menu_block common_stmt
+       | menu_block menu_stmt
+       | menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+       zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+       menu_add_entry(NULL);
+       menu_add_prompt(P_COMMENT, $2, NULL);
+       printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+       menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+       printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+       zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+       current_entry->sym->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+         /* empty */
+       | depends_list depends
+       | depends_list T_EOL
+       | depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+       menu_add_dep($3);
+       printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+}
+       | T_DEPENDS expr T_EOL
+{
+       menu_add_dep($2);
+       printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
+}
+       | T_REQUIRES expr T_EOL
+{
+       menu_add_dep($2);
+       printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+         /* empty */
+       | prompt if_expr
+{
+       menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt:          T_WORD
+       | T_WORD_QUOTE
+;
+
+end:     T_ENDMENU T_EOL       { $$ = $1; }
+       | T_ENDCHOICE T_EOL     { $$ = $1; }
+       | T_ENDIF T_EOL         { $$ = $1; }
+;
+
+nl:
+         T_EOL
+       | nl T_EOL
+;
+
+if_expr:  /* empty */                  { $$ = NULL; }
+       | T_IF expr                     { $$ = $2; }
+;
+
+expr:    symbol                                { $$ = expr_alloc_symbol($1); }
+       | symbol T_EQUAL symbol                 { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+       | symbol T_UNEQUAL symbol               { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+       | T_OPEN_PAREN expr T_CLOSE_PAREN       { $$ = $2; }
+       | T_NOT expr                            { $$ = expr_alloc_one(E_NOT, $2); }
+       | expr T_OR expr                        { $$ = expr_alloc_two(E_OR, $1, $3); }
+       | expr T_AND expr                       { $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol:          T_WORD        { $$ = sym_lookup($1, 0); free($1); }
+       | T_WORD_QUOTE  { $$ = sym_lookup($1, 1); free($1); }
+;
+
+%%
+
+void conf_parse(const char *name)
+{
+       struct symbol *sym;
+       int i;
+
+       zconf_initscan(name);
+
+       sym_init();
+       menu_init();
+       modules_sym = sym_lookup("MODULES", 0);
+       rootmenu.prompt = menu_add_prompt(P_MENU, "LWK Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       menu_finalize(&rootmenu);
+       for_all_symbols(i, sym) {
+               sym_check_deps(sym);
+        }
+
+       sym_change_count = 1;
+}
+
+const char *zconf_tokenname(int token)
+{
+       switch (token) {
+       case T_MENU:            return "menu";
+       case T_ENDMENU:         return "endmenu";
+       case T_CHOICE:          return "choice";
+       case T_ENDCHOICE:       return "endchoice";
+       case T_IF:              return "if";
+       case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
+       }
+       return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       if (current_menu->file != current_file) {
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
+               zconfnerrs++;
+               return false;
+       }
+       return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+       const char *p;
+       int len;
+
+       putc('"', out);
+       while ((p = strchr(str, '"'))) {
+               len = p - str;
+               if (len)
+                       fprintf(out, "%.*s", len, str);
+               fputs("\\\"", out);
+               str = p + 1;
+       }
+       fputs(str, out);
+       putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       struct property *prop;
+
+       if (sym_is_choice(sym))
+               fprintf(out, "choice\n");
+       else
+               fprintf(out, "config %s\n", sym->name);
+       switch (sym->type) {
+       case S_BOOLEAN:
+               fputs("  boolean\n", out);
+               break;
+       case S_TRISTATE:
+               fputs("  tristate\n", out);
+               break;
+       case S_STRING:
+               fputs("  string\n", out);
+               break;
+       case S_INT:
+               fputs("  integer\n", out);
+               break;
+       case S_HEX:
+               fputs("  hex\n", out);
+               break;
+       default:
+               fputs("  ???\n", out);
+               break;
+       }
+       for (prop = sym->prop; prop; prop = prop->next) {
+               if (prop->menu != menu)
+                       continue;
+               switch (prop->type) {
+               case P_PROMPT:
+                       fputs("  prompt ", out);
+                       print_quoted_string(out, prop->text);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_DEFAULT:
+                       fputs( "  default ", out);
+                       expr_fprint(prop->expr, out);
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs(" if ", out);
+                               expr_fprint(prop->visible.expr, out);
+                       }
+                       fputc('\n', out);
+                       break;
+               case P_CHOICE:
+                       fputs("  #choice value\n", out);
+                       break;
+               default:
+                       fprintf(out, "  unknown prop %d!\n", prop->type);
+                       break;
+               }
+       }
+       if (sym->help) {
+               int len = strlen(sym->help);
+               while (sym->help[--len] == '\n')
+                       sym->help[len] = 0;
+               fprintf(out, "  help\n%s\n", sym->help);
+       }
+       fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct menu *menu;
+
+       menu = rootmenu.list;
+       while (menu) {
+               if ((sym = menu->sym))
+                       print_symbol(out, menu);
+               else if ((prop = menu->prompt)) {
+                       switch (prop->type) {
+                       case P_COMMENT:
+                               fputs("\ncomment ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       case P_MENU:
+                               fputs("\nmenu ", out);
+                               print_quoted_string(out, prop->text);
+                               fputs("\n", out);
+                               break;
+                       default:
+                               ;
+                       }
+                       if (!expr_is_yes(prop->visible.expr)) {
+                               fputs("  depends ", out);
+                               expr_fprint(prop->visible.expr, out);
+                               fputc('\n', out);
+                       }
+                       fputs("\n", out);
+               }
+
+               if (menu->list)
+                       menu = menu->list;
+               else if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->prompt && menu->prompt->type == P_MENU)
+                               fputs("\nendmenu\n", out);
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/kitten/scripts/mkcompile_h b/kitten/scripts/mkcompile_h
new file mode 100755 (executable)
index 0000000..8130012
--- /dev/null
@@ -0,0 +1,80 @@
+TARGET=$1
+ARCH=$2
+CC=$3
+
+# If compile.h exists already and we don't own autoconf.h
+# (i.e. we're not the same user who did make *config), don't
+# modify compile.h
+# So "sudo make install" won't change the "compiled by <user>"
+# do "compiled by root"
+
+if [ -r $TARGET -a ! -O include/linux/autoconf.h ]; then
+  echo "  SKIPPED $TARGET"
+  exit 0
+fi
+
+# Do not expand names
+set -f
+
+if [ -r .version ]; then
+  VERSION=`cat .version`
+else
+  VERSION=0
+  echo 0 > .version
+fi
+
+
+UTS_VERSION="#$VERSION"
+CONFIG_FLAGS=""
+#if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
+#if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
+UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS `LC_ALL=C LANG=C date`"
+
+# Truncate to maximum length
+
+UTS_LEN=64
+UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
+
+# Generate a temporary compile.h
+
+( echo /\* This file is auto generated, version $VERSION \*/
+  if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
+  
+  echo \#define UTS_MACHINE \"$ARCH\"
+
+  echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
+
+  echo \#define LWK_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\"
+  echo \#define LWK_COMPILE_BY \"`whoami`\"
+  echo \#define LWK_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
+
+  if [ -x /bin/dnsdomainname ]; then
+    echo \#define LWK_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
+  elif [ -x /bin/domainname ]; then
+    echo \#define LWK_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
+  else
+    echo \#define LWK_COMPILE_DOMAIN
+  fi
+
+  echo \#define LWK_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
+) > .tmpcompile
+
+# Only replace the real compile.h if the new one is different,
+# in order to preserve the timestamp and avoid unnecessary
+# recompilations.
+# We don't consider the file changed if only the date/time changed.
+# A kernel config change will increase the generation number, thus
+# causing compile.h to be updated (including date/time) due to the 
+# changed comment in the
+# first line.
+
+if [ -r $TARGET ] && \
+      grep -v 'UTS_VERSION\|LWK_COMPILE_TIME' $TARGET > .tmpver.1 && \
+      grep -v 'UTS_VERSION\|LWK_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
+      cmp -s .tmpver.1 .tmpver.2; then
+   rm -f .tmpcompile
+else
+   echo "  UPD     $TARGET"
+   mv -f .tmpcompile $TARGET
+fi
+rm -f .tmpver.1 .tmpver.2
diff --git a/kitten/scripts/mksysmap b/kitten/scripts/mksysmap
new file mode 100644 (file)
index 0000000..4390fab
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh -x
+# Based on the vmlinux file create the System.map file
+# System.map is used by module-init tools and some debugging
+# tools to retrieve the actual addresses of symbols in the kernel.
+#
+# Usage
+# mksysmap vmlinux System.map
+
+
+#####
+# Generate System.map (actual filename passed as second argument)
+
+# $NM produces the following output:
+# f0081e80 T alloc_vfsmnt
+
+#   The second row specify the type of the symbol:
+#   A = Absolute
+#   B = Uninitialised data (.bss)
+#   C = Comon symbol
+#   D = Initialised data
+#   G = Initialised data for small objects
+#   I = Indirect reference to another symbol
+#   N = Debugging symbol
+#   R = Read only
+#   S = Uninitialised data for small objects
+#   T = Text code symbol
+#   U = Undefined symbol
+#   V = Weak symbol
+#   W = Weak symbol
+#   Corresponding small letters are local symbols
+
+# For System.map filter away:
+#   a - local absolute symbols
+#   U - undefined global symbols
+#   w - local weak symbols
+
+# readprofile starts reading symbols when _stext is found, and
+# continue until it finds a symbol which is not either of 'T', 't',
+# 'W' or 'w'. __crc_ are 'A' and placed in the middle
+# so we just ignore them to let readprofile continue to work.
+# (At least sparc64 has __crc_ in the middle).
+
+$NM -n $1 | grep -v '\( [aUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2
+
diff --git a/kitten/scripts/toolchain/build-x86_64.sh b/kitten/scripts/toolchain/build-x86_64.sh
new file mode 100755 (executable)
index 0000000..3806194
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+# Cross-Compiler Toolchain for ${PLATFORM}
+#  by Martin Decky <martin@decky.cz>
+#
+#  GPL'ed, copyleft
+#
+
+
+check_error() {
+    if [ "$1" -ne "0" ]; then
+       echo
+       echo "Script failed: $2"
+       exit
+    fi
+}
+
+BINUTILS_VERSION="2.17"
+GCC_VERSION="4.1.1"
+
+BINUTILS="binutils-${BINUTILS_VERSION}.tar.gz"
+GCC_CORE="gcc-core-${GCC_VERSION}.tar.bz2"
+GCC_CPP="gcc-g++-${GCC_VERSION}.tar.bz2"
+
+BINUTILS_SOURCE="ftp://ftp.gnu.org/gnu/binutils/"
+GCC_SOURCE="ftp://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/"
+
+PLATFORM="x86_64"
+WORKDIR=`pwd`
+TARGET="${PLATFORM}-linux-gnu"
+PREFIX="/opt/toolchain/${PLATFORM}"
+BINUTILSDIR="${WORKDIR}/binutils-${BINUTILS_VERSION}"
+GCCDIR="${WORKDIR}/gcc-${GCC_VERSION}"
+OBJDIR="${WORKDIR}/gcc-obj"
+
+echo ">>> Downloading tarballs"
+
+if [ ! -f "${BINUTILS}" ]; then
+    wget -c "${BINUTILS_SOURCE}${BINUTILS}"
+    check_error $? "Error downloading binutils."
+fi
+if [ ! -f "${GCC_CORE}" ]; then
+    wget -c "${GCC_SOURCE}${GCC_CORE}"
+    check_error $? "Error downloading GCC Core."
+fi
+if [ ! -f "${GCC_CPP}" ]; then
+    wget -c "${GCC_SOURCE}${GCC_CPP}"
+    check_error $? "Error downloading GCC C++."
+fi
+
+echo ">>> Creating destionation directory"
+if [ ! -d "${PREFIX}" ]; then
+    mkdir -p "${PREFIX}" 
+    test -d "${PREFIX}"
+    check_error $? "Unable to create ${PREFIX}."
+fi
+
+echo ">>> Creating GCC work directory"
+if [ ! -d "${OBJDIR}" ]; then
+    mkdir -p "${OBJDIR}"
+    test -d "${OBJDIR}"
+    check_error $? "Unable to create ${OBJDIR}."
+fi
+
+echo ">>> Unpacking tarballs"
+tar -xvzf "${BINUTILS}"
+check_error $? "Error unpacking binutils."
+tar -xvjf "${GCC_CORE}"
+check_error $? "Error unpacking GCC Core."
+tar -xvjf "${GCC_CPP}"
+check_error $? "Error unpacking GCC C++."
+
+echo ">>> Compiling and installing binutils"
+cd "${BINUTILSDIR}"
+check_error $? "Change directory failed."
+./configure "--target=${TARGET}" "--prefix=${PREFIX}" "--program-prefix=${TARGET}-" "--disable-nls"
+check_error $? "Error configuring binutils."
+make all install
+check_error $? "Error compiling/installing binutils."
+
+echo ">>> Compiling and installing GCC"
+cd "${OBJDIR}"
+check_error $? "Change directory failed."
+"${GCCDIR}/configure" "--target=${TARGET}" "--prefix=${PREFIX}" "--program-prefix=${TARGET}-" --with-gnu-as --with-gnu-ld --disable-nls --disable-threads --enable-languages=c,c++ --disable-multilib --disable-libgcj --without-headers --disable-shared
+check_error $? "Error configuring GCC."
+PATH="${PATH}:${PREFIX}/bin" make all-gcc install-gcc
+check_error $? "Error compiling/installing GCC."
+
+echo
+echo ">>> Cross-compiler for ${TARGET} installed."
diff --git a/kitten/user/Make.rules b/kitten/user/Make.rules
new file mode 100644 (file)
index 0000000..3f31036
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (c) 2008, Sandia National Laboratories
+
+#
+# The build rules are modelled on the Linux style less-verbose
+# build by default, but with full details if V=1 flag is
+# set in the environment or on the build line.
+#
+# Typical usage:
+#      $(call build,FOO,$filename,\
+#              foo -flags $filename \
+#      )
+#
+build = \
+       @if [ "$(V)" != 1 ]; then \
+               echo '  $1'; \
+       else \
+               echo "$2"; \
+       fi; \
+       $2
+
+#
+# Generate a library .a file from a list of object files.
+# For consistency of symbol ordering, we do not use ar to do any
+# updates of the library, but instead remove the old one and
+# re-generate it from all of its input object files.
+#
+# Typical usage:
+#      $(call buildlib,libfoo.a,$(FILES))
+#
+buildlib = \
+       $(call build,AR      $1,\
+               $(RM) $1; \
+               $(AR) crs $1 $2; \
+       )
+
+buildprog = \
+       $(call build,LD      $1,\
+               $(RM) $1; \
+               $(CC) -static -o $1 $2; \
+       )
+
+#
+# Build the .o files from the sources.
+#
+%.o: %.c
+       $(call build,CC      $@,$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<)
+
+all: $(PROGS-y) $(LIBS-y)
+
+clean: FORCE
+       $(call build,CLEAN      $(PROGS-y) $(LIBS-y) $(OBJS-y), \
+               $(RM) $(PROGS-y) $(LIBS-y) $(OBJS-y); \
+       )
+
+FORCE:
diff --git a/kitten/user/Makefile b/kitten/user/Makefile
new file mode 100644 (file)
index 0000000..5426c24
--- /dev/null
@@ -0,0 +1,9 @@
+CFLAGS=-O2
+
+all:
+       make -C liblwk
+       make -C hello_world
+
+clean:
+       make -C liblwk clean
+       make -C hello_world clean
diff --git a/kitten/user/hello_world/COPYING b/kitten/user/hello_world/COPYING
new file mode 100644 (file)
index 0000000..b6bd517
--- /dev/null
@@ -0,0 +1,481 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/kitten/user/hello_world/Makefile b/kitten/user/hello_world/Makefile
new file mode 100644 (file)
index 0000000..4c8b9e6
--- /dev/null
@@ -0,0 +1,11 @@
+TARGET = hello_world
+
+PROGS-y += $(TARGET)
+OBJS-y += hello_world.o
+
+INCLUDES += -I../liblwk/include -I../../include
+
+$(TARGET): $(OBJS-y) ../liblwk/liblwk.a
+       $(call buildprog,$@,$(OBJS-y) ../liblwk/liblwk.a)
+
+include ../Make.rules
diff --git a/kitten/user/hello_world/hello_world.c b/kitten/user/hello_world/hello_world.c
new file mode 100644 (file)
index 0000000..7831b50
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <lwk/liblwk.h>
+
+static void pmem_api_test(void);
+static void aspace_api_test(void);
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+       int i;
+       id_t aspace_id;
+
+       printf("Hello, world!\n");
+
+       printf("Arguments:\n");
+       for (i = 0; i < argc; i++)
+               printf("  argv[%d] = %s\n", i, argv[i]);
+
+       printf("Environment Variables:\n");
+       for (i = 0; envp[i] != NULL; i++)
+               printf("  envp[%d] = %s\n", i, envp[i]);
+
+       pmem_api_test();
+       aspace_api_test();
+
+       printf("Spinning forever...\n");
+       while (1) {}
+}
+
+static void
+pmem_api_test(void)
+{
+       struct pmem_region query, result;
+       unsigned long bytes_umem = 0;
+       int status;
+
+       printf("TEST BEGIN: Physical Memory Management\n");
+
+       query.start = 0;
+       query.end = ULONG_MAX;
+       pmem_region_unset_all(&query);
+
+       printf("  Physical Memory Map:\n");
+       while ((status = pmem_query(&query, &result)) == 0) {
+               printf("    [%#016lx, %#016lx) %-11s\n",
+                       result.start,
+                       result.end,
+                       (result.type_is_set)
+                               ? pmem_type_to_string(result.type)
+                               : "UNSET"
+               );
+
+               if (result.type == PMEM_TYPE_UMEM)
+                       bytes_umem += (result.end - result.start);
+
+               query.start = result.end;
+       }
+
+       if (status != -ENOENT) {
+               printf("ERROR: pmem_query() status=%d\n", status);
+       }
+
+       printf("  Total User-Level Managed Memory: %lu bytes\n", bytes_umem);
+
+       printf("TEST END: Physical Memory Management\n");
+}
+
+static void
+aspace_api_test(void)
+{
+       int status;
+       id_t my_id, new_id;
+
+       printf("TEST BEGIN: Address Space Management\n");
+
+       if ((status = aspace_get_myid(&my_id)) != 0)
+               printf("ERROR: aspace_get_myid() status=%d\n", status);
+       else
+               printf("  My address space ID is %u\n", my_id);
+
+       printf("  Creating a new aspace: ");
+
+       status = aspace_create(ANY_ID, "TEST-ASPACE", &new_id);
+       if (status)
+               printf("\nERROR: aspace_create() status=%d\n", status);
+       else
+               printf("id=%u\n", new_id);
+
+       printf("  Using SMARTMAP to map myself into aspace %u\n", new_id);
+       status = aspace_smartmap(my_id, new_id, SMARTMAP_ALIGN, SMARTMAP_ALIGN);
+       if (status) printf("ERROR: aspace_smartmap() status=%d\n", status);
+
+       aspace_dump2console(new_id);
+
+       status = aspace_unsmartmap(my_id, new_id);
+       if (status) printf("ERROR: aspace_unsmartmap() status=%d\n", status);
+
+       printf("  Destroying a aspace %u: ", new_id);
+       status = aspace_destroy(new_id);
+       if (status)
+               printf("ERROR: aspace_destroy() status=%d\n", status);
+       else
+               printf("OK\n");
+
+       printf("TEST END: Address Space Management\n");
+}
diff --git a/kitten/user/liblwk/COPYING b/kitten/user/liblwk/COPYING
new file mode 100644 (file)
index 0000000..b6bd517
--- /dev/null
@@ -0,0 +1,481 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/kitten/user/liblwk/Makefile b/kitten/user/liblwk/Makefile
new file mode 100644 (file)
index 0000000..400d923
--- /dev/null
@@ -0,0 +1,11 @@
+TARGET = liblwk.a
+
+LIBS-y += $(TARGET)
+OBJS-y += syscalls.o pmem.o elf.o aspace.o
+
+INCLUDES += -I./include -I../../include
+
+$(TARGET): $(OBJS-y)
+       $(call buildlib,$@,$(OBJS-y))
+
+include ../Make.rules
diff --git a/kitten/user/liblwk/aspace.c b/kitten/user/liblwk/aspace.c
new file mode 100644 (file)
index 0000000..176dd75
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/liblwk.h>
+
+int
+aspace_map_region(
+       id_t         id,
+       vaddr_t      start,
+       size_t       extent,
+       vmflags_t    flags,
+       vmpagesize_t pagesz,
+       const char * name,
+       paddr_t      pmem
+)
+{
+       int status;
+
+       if ((status = aspace_add_region(id, start, extent, flags, pagesz, name)))
+               return status;
+
+       if ((status = aspace_map_pmem(id, pmem, start, extent))) {
+               aspace_del_region(id, start, extent);
+               return status;
+       }
+
+       return 0;
+}
+
+int
+aspace_map_region_anywhere(
+       id_t         id,
+       vaddr_t *    start,
+       size_t       extent,
+       vmflags_t    flags,
+       vmpagesize_t pagesz,
+       const char * name,
+       paddr_t      pmem
+)
+{
+       int status;
+
+retry:
+       if ((status = aspace_find_hole(id, 0, extent, pagesz, start)))
+               return status;
+
+       if ((status = aspace_add_region(id, *start, extent, flags, pagesz, name))) {
+               if (status == -ENOTUNIQ)
+                       goto retry; /* we lost a race with someone */
+               return status;
+       }
+
+       if ((status = aspace_map_pmem(id, pmem, *start, extent))) {
+               aspace_del_region(id, *start, extent);
+               return status;
+       }
+
+       return 0;
+}
diff --git a/kitten/user/liblwk/elf.c b/kitten/user/liblwk/elf.c
new file mode 100644 (file)
index 0000000..279685d
--- /dev/null
@@ -0,0 +1,842 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/liblwk.h>
+#include <lwk/ctype.h>
+
+/**
+ * Verifies that an ELF header is sane.
+ * Returns 0 if header is sane and random non-zero values if header is insane.
+ */
+int
+elf_check_hdr(const struct elfhdr *hdr)
+{
+       if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) {
+               print(TYPE_ERR "bad e_ident %#x\n",
+                              *((unsigned int *)hdr->e_ident));
+               return -1;
+       }
+       if (hdr->e_ident[EI_CLASS] != ELF_CLASS) {
+               print(TYPE_ERR "bad e_ident[EI_CLASS] %#x\n",
+                              (unsigned int)hdr->e_ident[EI_CLASS]);
+               return -1;
+       }
+       if (hdr->e_ident[EI_DATA] != ELF_DATA) {
+               print(TYPE_ERR "bad e_ident[EI_DATA] %#x\n",
+                              (unsigned int)hdr->e_ident[EI_DATA]);
+               return -1;
+       }
+       if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
+               print(TYPE_ERR "bad e_ident[EI_VERSION] %#x\n",
+                              (unsigned int)hdr->e_ident[EI_VERSION]);
+               return -1;
+       }
+       if (hdr->e_ident[EI_OSABI] != ELF_OSABI) {
+               print(TYPE_ERR "bad e_dent[EI_OSABI] %#x\n",
+                              (unsigned int)hdr->e_ident[EI_OSABI]);
+               return -1;
+       }
+       if (hdr->e_type != ET_EXEC) {
+               print(TYPE_ERR "bad e_type %#x\n",
+                              (unsigned int)hdr->e_type);
+               return -1;
+       }
+       if (hdr->e_machine != ELF_ARCH) {
+               print(TYPE_ERR "bad e_machine %#x\n",
+                              (unsigned int)hdr->e_machine);
+               return -1;
+       }
+       if (hdr->e_version != EV_CURRENT) {
+               print(TYPE_ERR "bad e_version %#x\n",
+                              (unsigned int)hdr->e_version);
+               return -1;
+       }
+       if (hdr->e_flags != 0) {
+               print(TYPE_ERR "bad e_flags %#x\n",
+                              (unsigned int)hdr->e_flags);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Prints the contents of an ELF file header to the console.
+ */
+void
+elf_print_elfhdr(const struct elfhdr *hdr)
+{
+       print(TYPE_NORM "ELF File Header:\n");
+       print(TYPE_NORM "  type      %0#10x\n",  (unsigned int)  hdr->e_type      );
+       print(TYPE_NORM "  machine   %0#10x\n",  (unsigned int)  hdr->e_machine   );
+       print(TYPE_NORM "  version   %0#10x\n",  (unsigned int)  hdr->e_version   );
+       print(TYPE_NORM "  entry     %0#18lx\n", (unsigned long) hdr->e_entry     );
+       print(TYPE_NORM "  phoff     %0#18lx\n", (unsigned long) hdr->e_phoff     );
+       print(TYPE_NORM "  shoff     %0#18lx\n", (unsigned long) hdr->e_shoff     );
+       print(TYPE_NORM "  flags     %0#10x\n",  (unsigned int)  hdr->e_flags     );
+       print(TYPE_NORM "  ehsize    %0#10x\n",  (unsigned int)  hdr->e_ehsize    );
+       print(TYPE_NORM "  phentsize %0#10x\n",  (unsigned int)  hdr->e_phentsize );
+       print(TYPE_NORM "  phnum     %0#10x\n",  (unsigned int)  hdr->e_phnum     );
+       print(TYPE_NORM "  shentsize %0#10x\n",  (unsigned int)  hdr->e_shentsize );
+       print(TYPE_NORM "  shnum     %0#10x\n",  (unsigned int)  hdr->e_shnum     );
+       print(TYPE_NORM "  shstrndx  %0#10x\n",  (unsigned int)  hdr->e_shstrndx  );
+}
+
+/**
+ * Prints the contents of an ELF program header to the console.
+ */
+void
+elf_print_phdr(const struct elf_phdr *hdr)
+{
+       char *name;
+
+       switch (hdr->p_type) {
+               case PT_NULL:    name = "NULL";    break;
+               case PT_LOAD:    name = "LOAD";    break;
+               case PT_DYNAMIC: name = "DYNAMIC"; break;
+               case PT_INTERP:  name = "INTERP";  break;
+               case PT_NOTE:    name = "NOTE";    break;
+               case PT_SHLIB:   name = "SHLIB";   break;
+               case PT_PHDR:    name = "PHDR";    break;
+               case PT_LOPROC:  name = "LOPROC";  break;
+               case PT_HIPROC:  name = "HIPROC";  break;
+               default:         name = "UNDEFINED TYPE";
+       }
+
+       print(TYPE_NORM "ELF Program Segment Header:\n");
+       print(TYPE_NORM "  type   %s\n", name);
+       print(TYPE_NORM "  flags  %0#10x\n",  (unsigned int)  hdr->p_flags  );
+       print(TYPE_NORM "  offset %0#18lx\n", (unsigned long) hdr->p_offset );
+       print(TYPE_NORM "  vaddr  %0#18lx\n", (unsigned long) hdr->p_vaddr  );
+       print(TYPE_NORM "  paddr  %0#18lx\n", (unsigned long) hdr->p_paddr  );
+       print(TYPE_NORM "  filesz %0#18lx\n", (unsigned long) hdr->p_filesz );
+       print(TYPE_NORM "  memsz  %0#18lx\n", (unsigned long) hdr->p_memsz  );
+       print(TYPE_NORM "  align  %0#18lx\n", (unsigned long) hdr->p_align  );
+}
+
+/**
+ * Converts ELF flags to the corresponding kernel memory subsystem flags.
+ */
+vmflags_t
+elf_pflags_to_vmflags(unsigned int elf_pflags)
+{
+       vmflags_t vmflags = VM_USER;
+       if ( elf_pflags & PF_R ) vmflags |= VM_READ;
+       if ( elf_pflags & PF_W ) vmflags |= VM_WRITE;
+       if ( elf_pflags & PF_X ) vmflags |= VM_EXEC;
+       return vmflags;
+}
+
+/**
+ * Determines an ELF executable's entry point... where to start executing.
+ * Note: The address returned is in the context of the executing ELF
+ *       image, not an address within the passed in elf_image.
+ */
+vaddr_t
+elf_entry_point(const void *elf_image)
+{
+       const struct elfhdr *ehdr = elf_image;
+       return ehdr->e_entry;
+}
+
+/**
+ * Determines the address of an ELF executable's program header table.
+ * Note: The address returned is in the context of the executing ELF
+ *       image, not an address within the passed in elf_image.
+ */
+vaddr_t
+elf_phdr_table_addr(const void *elf_image)
+{
+       const struct elfhdr *ehdr = elf_image;
+       struct elf_phdr *phdr_array, *phdr;
+       unsigned int i;
+
+       phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdr_array[i];
+               if (phdr->p_type == PT_LOAD)
+                       return phdr->p_vaddr - phdr->p_offset + ehdr->e_phoff;
+       }
+       return 0;
+}
+
+/**
+ * Returns the number of entries in an ELF executable's program header table.
+ */
+unsigned int
+elf_num_phdrs(const void *elf_image)
+{
+       const struct elfhdr *ehdr = elf_image;
+       return ehdr->e_phnum;
+}
+
+/**
+ * Determines where the UNIX heap should start for a given ELF executable.
+ * Note: The address returned is in the context of the executing ELF
+ *       image, not an address relative to the passed in elf_image.
+ */
+vaddr_t
+elf_heap_start(const void *elf_image)
+{
+       const struct elfhdr *ehdr;
+       const struct elf_phdr *phdr_array;
+       const struct elf_phdr *phdr;
+       vaddr_t end, heap_start=0;
+       size_t i;
+
+       /* Locate the program header array (in this context) */
+       ehdr       = elf_image;
+       phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdr_array[i];
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               /* Calculate the end of the LOAD segment in memory */
+               end = phdr->p_vaddr + phdr->p_memsz;
+
+               if (end > heap_start)
+                       heap_start = end;
+       }
+
+       return heap_start;
+}
+
+/**
+ * Given an argument string like "arg1=foo arg2=bar", parses it into
+ * an argv[] or envp[] style array of string pointers. Useful for
+ * constructing the argv and envp arguments to elf_init_stack().
+ */
+int
+elf_init_str_array(
+       size_t  size,
+       char *  ptrs[],
+       char *  str
+)
+{ 
+       size_t pos = 0;
+       char *tmp;
+
+       while (strlen(str)) {
+               /* move past white space */
+               while (*str && isspace(*str))
+                       ++str;
+
+               tmp = str;
+
+               /* find the end of the string */
+               while (*str && !isspace(*str))
+                       ++str;
+
+               *str++ = 0;
+
+               if (strlen(tmp)) {
+                       if (pos == size - 1)
+                               return -1;
+                       ptrs[pos++] = tmp; 
+               }
+       
+       }
+       ptrs[pos] = "";
+       return 0;
+}
+
+/**
+ * Writes an auxiliary info table entry.
+ */
+static void
+write_aux(
+       struct aux_ent * table,
+       int              index,
+       unsigned long    id,
+       unsigned long    val
+)
+{
+       table[index].id  = id;
+       table[index].val = val;
+}
+
+/**
+ * Determines the value of the current stack pointer in the target
+ * address space. The sp argument is the stack pointer in this context
+ * (i.e., the context this code is executing in), stack_mapping is the
+ * address of the stack in this context, stack_start is the address
+ * of the stack in the target address space, and extent is the size
+ * of the stack.
+ */
+static vaddr_t
+sp_in_aspace(void *sp,
+             void *stack_mapping, vaddr_t stack_start, size_t extent)
+{
+       vaddr_t stack_end    = (vaddr_t)stack_mapping + extent;
+       vaddr_t stack_vend   = stack_start + extent;
+       size_t  stack_offset = stack_end - (vaddr_t)sp;
+
+       return stack_vend - stack_offset;
+}
+
+/**
+ * Sets up the initial stack for a new task.  This includes storing the
+ * argv[] argument array, envp[] environment array, and auxiliary info table
+ * to the top of the user stack in the format that the C library expects them.
+ * Eventually the arguments get passed to the application's
+ * main(argc, argv, envp) function.
+ * 
+ * If successful, the initial stack pointer value that should be used when
+ * starting the new task is returned in >stack_ptr.
+ *
+ * This function sets up the initial stack as follows (stack grows down):
+ *
+ *                 Environment Strings
+ *                 Argument Strings
+ *                 Platform String
+ *                 Auxiliary Info Table
+ *                 envp[]
+ *                 argv[]
+ *                 argc
+ *
+ * Arguments:
+ *       [IN]  elf_image     The ELF executable, needed to setup aux info.
+ *       [IN]  stack_mapping Where the stack is mapped in this context.
+ *       [IN]  stack_start   Where the stack is located in the target aspace.
+ *       [IN]  stack_extent  Size of the stack.
+ *       [IN]  argv[]        Array of pointers to argument strings.
+ *       [IN]  envp[]        Array of pointers to environment strings.
+ *       [IN]  uid           User ID of the task
+ *       [IN]  gid           Group ID of the task
+ *       [IN]  hwcap         Hardware capability bitfield
+ *                           (used for AT_HWCAP entry in aux info table)
+ *       [OUT] stack_ptr     The initial stack pointer value for the new task.
+ *                           (note this is an address in the target aspace)
+ *
+ * Returns:
+ *       Success: 0
+ *       Failure: Error Code, stack may have been partially initialized
+ */
+int
+elf_init_stack(
+       void *    elf_image,
+       void *    stack_mapping,
+       vaddr_t   stack_start,
+       size_t    stack_extent,
+       char *    argv[],
+       char *    envp[],
+       uid_t     uid,
+       gid_t     gid,
+       uint32_t  hwcap,
+       vaddr_t * stack_ptr
+)
+{
+       size_t i, len;
+       uintptr_t sp;
+       const char *platform_str = ELF_PLATFORM;
+       struct aux_ent auxv[AT_ENTRIES];
+       size_t argc=0, envc=0, auxc=0;
+       size_t arg_len=0, env_len=0, auxv_len=0;
+       size_t platform_str_len=0;
+
+       char *strings_sp;
+       char *platform_str_sp;
+       unsigned long *auxv_sp;
+       unsigned long *envp_sp;
+       unsigned long *argv_sp;
+       unsigned long *argc_sp;
+
+       /* Count # of arguments and their total string length */
+       while ((len = strlen(argv[argc])) != 0) {
+               arg_len += (len + 1);
+               ++argc;
+       }
+
+       /* Count # of environment variables and their total string length */
+       while ((len = strlen(envp[envc])) != 0) {
+               env_len += (len + 1);
+               ++envc;
+       }
+
+       /* Calculate length of the arch's platform string, if there is one */
+       if (platform_str)
+               platform_str_len = strlen(platform_str) + 1;
+
+       /* Make room on stack for arg, env, and platform strings */
+       sp = (uintptr_t)((vaddr_t)stack_mapping + stack_extent);
+       sp -= (arg_len + env_len + platform_str_len);
+       strings_sp = (void *) sp;
+
+       /* Build the auxilliary information table */
+       write_aux(auxv, auxc++, AT_HWCAP, hwcap);
+       write_aux(auxv, auxc++, AT_PAGESZ, ELF_EXEC_PAGESIZE);
+       write_aux(auxv, auxc++, AT_CLKTCK, 1000000l);
+       write_aux(auxv, auxc++, AT_PHDR, elf_phdr_table_addr(elf_image));
+       write_aux(auxv, auxc++, AT_PHENT, sizeof(struct elf_phdr));
+       write_aux(auxv, auxc++, AT_PHNUM, elf_num_phdrs(elf_image));
+       write_aux(auxv, auxc++, AT_BASE, 0);
+       write_aux(auxv, auxc++, AT_FLAGS, 0);
+       write_aux(auxv, auxc++, AT_ENTRY, elf_entry_point(elf_image));
+       write_aux(auxv, auxc++, AT_UID, uid);
+       write_aux(auxv, auxc++, AT_EUID, uid);
+       write_aux(auxv, auxc++, AT_GID, gid);
+       write_aux(auxv, auxc++, AT_EGID, gid);
+       write_aux(auxv, auxc++, AT_SECURE, 0);
+       if (platform_str) {
+               platform_str_sp = strings_sp;
+               write_aux(
+                       auxv, auxc++, AT_PLATFORM,
+                       sp_in_aspace(platform_str_sp,
+                                    stack_mapping, stack_start,
+                                    stack_extent)
+               );
+       }
+       write_aux(auxv, auxc++, AT_NULL, 0);
+
+       /* Make room on stack for aux info table */
+       auxv_len = auxc * sizeof(struct aux_ent);
+       sp -= auxv_len;
+
+       /* Make room on stack for argc, argv[], envp[] */
+       sp -= ((1 + (argc + 1) + (envc + 1)) * sizeof(unsigned long));
+
+       /* Align stack to 16-byte boundary */
+       sp = round_down(sp, 16);
+
+       /* Calculate stack address to store argc, argv[], envp[], and auxv[] */
+       argc_sp = (unsigned long *) sp;
+       argv_sp = argc_sp  + 1;
+       envp_sp = argv_sp  + argc + 1;
+       auxv_sp = envp_sp  + envc + 1;
+
+       /* Store arch's platform string, if there is one */
+       if (platform_str) {
+               memcpy(strings_sp, platform_str, platform_str_len);
+               strings_sp += platform_str_len;
+       }
+
+       /* Store the auxiliary information array */
+       memcpy(auxv_sp, auxv, auxv_len);
+
+       /* Store argv[] */
+       for (i = 0; i < argc; i++) {
+               len = strlen(argv[i]) + 1;
+               memcpy(strings_sp, argv[i], len);
+               argv_sp[i] = sp_in_aspace(strings_sp,
+                                         stack_mapping, stack_start,
+                                         stack_extent),
+               strings_sp += len;
+       }
+       argv_sp[i] = 0;  /* NULL terminate argv[] */
+
+       /* Store envp[] */
+       for (i = 0; i < envc; i++) {
+               len = strlen(envp[i]) + 1;
+               memcpy(strings_sp, envp[i], len);
+               envp_sp[i] = sp_in_aspace(strings_sp,
+                                         stack_mapping, stack_start,
+                                         stack_extent),
+               strings_sp += len;
+       }
+       envp_sp[i] = 0;  /* NULL terminate argv[] */
+
+       /* Store argc */
+       *argc_sp = argc;
+
+       if (stack_ptr) {
+               *stack_ptr = sp_in_aspace((void *)sp,
+                                         stack_mapping, stack_start,
+                                         stack_extent);
+       }
+       return 0;
+}
+
+/**
+ * A "default" alloc_pmem() function for use with elf_load_executable().
+ * A user may wish to define a custom replacement alloc_pmem() function
+ * to, for example, keep track of the physical memory that is allocated.
+ */
+paddr_t
+elf_dflt_alloc_pmem(size_t size, size_t alignment, uintptr_t arg)
+{
+       struct pmem_region result;
+
+       if (pmem_alloc_umem(size, alignment, &result))
+               return 0;
+
+       /* Mark the memory as being used by the init task */
+       result.type = PMEM_TYPE_INIT_TASK;
+       BUG_ON(pmem_update(&result));
+       
+       return result.start;
+}
+
+static int
+load_writable_segment(
+       void *            elf_image,
+       struct elf_phdr * phdr,
+       id_t              aspace_id,
+       vaddr_t           start,
+       size_t            extent,
+       vmpagesize_t      pagesz,
+       uintptr_t         alloc_pmem_arg,
+       paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
+)
+{
+       int status;
+       paddr_t pmem;
+       vaddr_t local_start;
+       vaddr_t src, dst;
+       id_t my_aspace_id;
+
+       /* Figure out my address space ID */
+       if ((status = aspace_get_myid(&my_aspace_id)))
+               return status;
+
+       /* Allocate physical memory for the segment */
+       if (!(pmem = alloc_pmem(extent, pagesz, alloc_pmem_arg)))
+               return -ENOMEM;
+
+       /* Map the segment into the target address space */
+       status =
+       aspace_map_region(
+               aspace_id,
+               start,
+               extent,
+               elf_pflags_to_vmflags(phdr->p_flags),
+               pagesz,
+               "ELF",
+               pmem
+       );
+       if (status)
+               return status;
+
+       /* Map the segment into this address space */
+       status =
+       aspace_map_region_anywhere(
+               my_aspace_id,
+               &local_start,
+               extent,
+               (VM_USER|VM_READ|VM_WRITE),
+               pagesz,
+               "temporary",
+               pmem
+       );
+       if (status)
+               return status;
+
+       /* Copy segment data from ELF image into the target address space
+        * (via its temporary mapping in our address space) */
+       dst = local_start + (phdr->p_vaddr - start);
+       src = (vaddr_t)elf_image + phdr->p_offset;
+       memcpy((void *)dst, (void *)src, phdr->p_filesz);
+
+       /* Unmap the segment from this address space */
+       status = aspace_del_region(my_aspace_id, local_start, extent);
+       if (status)
+               return status;
+
+       return 0;
+}
+
+static int
+load_readonly_segment(
+       paddr_t           elf_image_paddr,
+       struct elf_phdr * phdr,
+       id_t              aspace_id,
+       vaddr_t           start,
+       size_t            extent,
+       vmpagesize_t      pagesz
+)
+{
+       return aspace_map_region(
+               aspace_id,
+               start,
+               extent,
+               elf_pflags_to_vmflags(phdr->p_flags),
+               pagesz,
+               "ELF (mapped)",
+               elf_image_paddr +
+                       round_down(phdr->p_offset, pagesz)
+       );
+}
+
+/**
+ * Loads an ELF executable image into the specified address space. 
+ *
+ * Arguments:
+ *       [IN]  elf_image:        Location of ELF image in this address space.
+ *       [IN]  elf_image_paddr:  Location of ELF image in physical memory.
+ *       [IN]  aspace_id:        Address space to load ELF image into.
+ *       [IN]  pagesz:           Page size to use when mapping ELF image.
+ *       [IN]  alloc_pmem_arg:   Argument to pass to alloc_pmem().
+ *       [IN]  alloc_pmem:       Function pointer to use to allocate physical
+ *                               memory for the region.  alloc_mem() returns 
+ *                               the physical address of the memory allocated.
+ *
+ * Returns:
+ *       Success: 0
+ *       Failure: Error Code, the target address space is left in an
+ *                undefined state and should be destroyed.
+ */
+int
+elf_load_executable(
+       void *       elf_image,
+       paddr_t      elf_image_paddr,
+       id_t         aspace_id,
+       vmpagesize_t pagesz,
+       uintptr_t    alloc_pmem_arg,
+       paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
+)
+{
+       struct elfhdr *   ehdr;
+       struct elf_phdr * phdr_array;
+       struct elf_phdr * phdr;
+       size_t            i;
+       vaddr_t           start, end;
+       size_t            extent;
+       size_t            num_load_segments=0;
+       int               status;
+
+       /* Locate the program header array (in this context) */
+       ehdr       = elf_image;
+       phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
+
+       /* Set up a region for each program segment */
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdr_array[i];
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               /* Calculate the segment's bounds */
+               start  = round_down(phdr->p_vaddr, pagesz);
+               end    = round_up(phdr->p_vaddr + phdr->p_memsz, pagesz);
+               extent = end - start;
+
+               if (phdr->p_flags & PF_W) {
+                       /* Writable segments must be copied into the
+                        * target address space */
+                       status =
+                       load_writable_segment(
+                               elf_image,
+                               phdr,
+                               aspace_id,
+                               start,
+                               extent,
+                               pagesz,
+                               alloc_pmem_arg,
+                               alloc_pmem
+                       );
+                       if (status)
+                               return status;
+               } else {
+                       /* Read-only segments are mapped directly
+                        * from the ELF image */
+                       status =
+                       load_readonly_segment(
+                               elf_image_paddr,
+                               phdr,
+                               aspace_id,
+                               start,
+                               extent,
+                               pagesz
+                       );
+                       if (status)
+                               return status;
+               }
+
+               ++num_load_segments;
+       }
+
+       return (num_load_segments) ? 0 : -ENOENT;
+}
+
+static int
+make_region(
+       id_t         aspace_id,
+       vaddr_t      start,
+       size_t       extent,
+       vmflags_t    flags,
+       vmpagesize_t pagesz,
+       const char * name,
+       uintptr_t    alloc_pmem_arg,
+       paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg),
+       paddr_t *    pmem
+)
+{
+       int status;
+
+       *pmem = alloc_pmem(extent, pagesz, alloc_pmem_arg);
+       if (*pmem == 0) {
+               print("Failed to allocate physical memory for %s.", name);
+               return -ENOMEM;
+       }
+
+       status = aspace_map_region(aspace_id, start, extent,
+                                  flags, pagesz,
+                                  name, *pmem);
+       if (status) {
+               print("Failed to map physical memory for %s (status=%d).",
+                      name, status);
+               return status;
+       }
+
+       return 0;
+}
+
+/**
+ * Maximum number of arguments and environment variables that may
+ * be passed to the new task created by elf_load().
+ */
+#define MAX_ARGC 32
+#define MAX_ENVC 32
+
+/**
+ * Kitchen-sink ELF image load function.
+ * If something more custom is desired, this function can be used as a guide
+ * for what needs to be done to load an ELF executable and setup the
+ * accompanying address space.
+ */
+int
+elf_load(
+       void *          elf_image,
+       paddr_t         elf_image_paddr,
+       const char *    name,
+       id_t            desired_aspace_id,
+       vmpagesize_t    pagesz,
+       size_t          heap_size,
+       size_t          stack_size,
+       char *          argv_str,
+       char *          envp_str,
+       start_state_t * start_state,
+       uintptr_t       alloc_pmem_arg,
+       paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
+)
+{
+       int status;
+       char *argv[MAX_ARGC] = { (char *)name };
+       char *envp[MAX_ENVC];
+       id_t my_aspace_id, aspace_id;
+       vaddr_t heap_start, stack_start, stack_end, stack_ptr;
+       vaddr_t local_stack_start;
+       size_t heap_extent, stack_extent;
+       paddr_t heap_pmem, stack_pmem;
+       uint32_t hwcap;
+
+       if (!elf_image || !start_state || !alloc_pmem)
+               return -EINVAL;
+
+       if (elf_init_str_array(MAX_ARGC-1, argv+1, argv_str)) {
+               print("Too many ARGV strings.");
+               return -EINVAL;
+       }
+
+       if (elf_init_str_array(MAX_ENVC, envp, envp_str)) {
+               print("Too many ENVP strings.");
+               return -EINVAL;
+       }
+
+       if ((status = aspace_create(desired_aspace_id, "init_task", &aspace_id))) {
+               print("Failed to create aspace (status=%d).", status);
+               return status;
+       }
+
+       /* Load the ELF executable's LOAD segments */
+       status =
+       elf_load_executable(
+               elf_image,       /* where I can access the ELF image */
+               elf_image_paddr, /* where it is in physical memory */
+               aspace_id,       /* the address space to map it into */
+               pagesz,          /* page size to map it with */
+               0,               /* arg to pass to alloc_pmem */
+               alloc_pmem       /* func to use to allocate phys mem */
+       );
+       if (status) {
+               print("Failed to load ELF image (status=%d).", status);
+               return status;
+       }
+
+       /* Create the UNIX heap */
+       heap_start  = round_up(elf_heap_start(elf_image), pagesz);
+       heap_extent = round_up(heap_size, pagesz);
+       status =
+       make_region(
+               aspace_id,
+               heap_start,
+               heap_extent,
+               (VM_USER|VM_READ|VM_WRITE|VM_EXEC|VM_HEAP),
+               pagesz,
+               "heap",
+               alloc_pmem_arg,
+               alloc_pmem,
+               &heap_pmem
+       );
+       if (status) {
+               print("Failed to create heap (status=%d).", status);
+               return status;
+       }
+
+       /* Create the stack region */
+       stack_end    = SMARTMAP_ALIGN;
+       stack_start  = round_down(stack_end - stack_size, pagesz);
+       stack_extent = stack_end - stack_start;
+       status = 
+       make_region(
+               aspace_id,
+               stack_start,
+               stack_extent,
+               (VM_USER|VM_READ|VM_WRITE|VM_EXEC),
+               pagesz,
+               "stack",
+               alloc_pmem_arg,
+               alloc_pmem,
+               &stack_pmem
+       );
+       if (status) {
+               print("Failed to create stack (status=%d).", status);
+               return status;
+       }
+
+       /* Map the stack region into this address space */
+       if ((status = aspace_get_myid(&my_aspace_id)))
+               return status;
+       status =
+       aspace_map_region_anywhere(
+               my_aspace_id,
+               &local_stack_start,
+               stack_extent,
+               (VM_USER|VM_READ|VM_WRITE),
+               pagesz,
+               "temporary",
+               stack_pmem
+       );
+       if (status) {
+               print("Failed to map stack locally (status=%d).", status);
+               return status;
+       }
+
+       /* Initialize the stack */
+       status = elf_hwcap(start_state->cpu_id, &hwcap);
+       if (status) {
+               print("Failed to get hw capabilities (status=%d).", status);
+               return status;
+       }
+       status =
+       elf_init_stack(
+               elf_image,
+               (void *)local_stack_start,  /* Where I can access it */
+               stack_start,                /* Where it is in target aspace */
+               stack_extent,
+               argv, envp,
+               start_state->uid, start_state->gid,
+               hwcap,
+               &stack_ptr
+       );
+       if (status) {
+               print("Failed to initialize stack (status=%d).", status);
+               return status;
+       }
+
+       start_state->aspace_id   = aspace_id;
+       start_state->entry_point = elf_entry_point(elf_image);
+       start_state->stack_ptr   = stack_ptr;
+
+       return 0;
+}
diff --git a/kitten/user/liblwk/include/lwk/liblwk.h b/kitten/user/liblwk/include/lwk/liblwk.h
new file mode 100644 (file)
index 0000000..f2d7e1e
--- /dev/null
@@ -0,0 +1,16 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#ifndef _LIBLWK_H_
+#define _LIBLWK_H_
+
+#include <lwk/types.h>
+#include <lwk/errno.h>
+#include <lwk/print.h>
+#include <lwk/string.h>
+#include <lwk/pmem.h>
+#include <lwk/aspace.h>
+#include <lwk/task.h>
+#include <lwk/elf.h>
+#include <lwk/auxvec.h>
+
+#endif
diff --git a/kitten/user/liblwk/pmem.c b/kitten/user/liblwk/pmem.c
new file mode 100644 (file)
index 0000000..800ffaf
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/liblwk.h>
+
+const char *
+pmem_type_to_string(pmem_type_t type)
+{
+       switch(type) {
+               case PMEM_TYPE_BOOTMEM:     return "BOOTMEM";     break;
+               case PMEM_TYPE_BIGPHYSAREA: return "BIGPHYSAREA"; break;
+               case PMEM_TYPE_INITRD:      return "INITRD";      break;
+               case PMEM_TYPE_INIT_TASK:   return "INIT_TASK";   break;
+               case PMEM_TYPE_KMEM:        return "KMEM";        break;
+               case PMEM_TYPE_UMEM:        return "UMEM";        break;
+       }
+       return "UNKNOWN";
+}
+
+void
+pmem_region_unset_all(struct pmem_region *rgn)
+{
+       rgn->type_is_set      = false;
+       rgn->lgroup_is_set    = false;
+       rgn->allocated_is_set = false;
+       rgn->name_is_set      = false;
+}
+
+int
+pmem_alloc_umem(size_t size, size_t alignment, struct pmem_region *rgn)
+{
+       struct pmem_region constraint, result;
+
+       /* Find and allocate a chunk of PMEM_TYPE_UMEM physical memory */
+       pmem_region_unset_all(&constraint);
+       constraint.start     = 0;
+       constraint.end       = (paddr_t)(-1);
+       constraint.type      = PMEM_TYPE_UMEM; constraint.type_is_set = true;
+       constraint.allocated = false;          constraint.allocated_is_set = true;
+
+       if (pmem_alloc(size, alignment, &constraint, &result))
+               return -ENOMEM;
+
+       *rgn = result;
+       return 0;
+}
+
+bool
+pmem_is_umem(paddr_t start, size_t extent)
+{
+       struct pmem_region query, result;
+       int status;
+
+       pmem_region_unset_all(&query);
+       query.start = start;
+       query.end   = start + extent;
+       query.type  = PMEM_TYPE_UMEM; query.type_is_set = true; 
+       result.end  = 0;
+
+       while ((status = pmem_query(&query, &result)) == 0) {
+               if (result.start != query.start)
+                       return false;
+               if (result.end == query.end)
+                       break;
+               query.start = result.end;
+       }
+       return (status) ? false : true;
+}
diff --git a/kitten/user/liblwk/syscalls.c b/kitten/user/liblwk/syscalls.c
new file mode 100644 (file)
index 0000000..002cf16
--- /dev/null
@@ -0,0 +1,201 @@
+/* Copyright (c) 2008, Sandia National Laboratories */
+
+#include <lwk/unistd.h>
+#include <lwk/liblwk.h>
+
+/**
+ * There is no way to specify inline assembly constraints for %r10 (arg4),
+ * %r8 (arg5), and %r9 (arg6), so the macros below specify the registers
+ * to use for local variables as a work-around.
+ *
+ * GCC BUG? -- For some unknown reason, the register specified to store
+ *             a local variable is not always honored if the variable
+ *             is assigned when it is declared.  Work-around by declaring
+ *             and assigning on separate lines.
+ */
+#define SYSCALL0(name)                                                 \
+int name(void) {                                               \
+       int status;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name)                             \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+#define SYSCALL1(name, type1)                                  \
+int name(type1 arg1) {                                         \
+       int status;                                             \
+       register type1 rdi asm("rdi");                          \
+       rdi = arg1;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name),                            \
+                 "r" (rdi)                                     \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+#define SYSCALL2(name, type1, type2)                           \
+int name(type1 arg1, type2 arg2) {                             \
+       int status;                                             \
+       register type1 rdi asm("rdi");                          \
+       register type2 rsi asm("rsi");                          \
+       rdi = arg1;                                             \
+       rsi = arg2;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name),                            \
+                 "r" (rdi),                                    \
+                 "r" (rsi)                                     \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+#define SYSCALL3(name, type1, type2, type3)                    \
+int name(type1 arg1, type2 arg2, type3 arg3) {                 \
+       int status;                                             \
+       register type1 rdi asm("rdi");                          \
+       register type2 rsi asm("rsi");                          \
+       register type3 rdx asm("rdx");                          \
+       rdi = arg1;                                             \
+       rsi = arg2;                                             \
+       rdx = arg3;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name),                            \
+                 "r" (rdi),                                    \
+                 "r" (rsi),                                    \
+                 "r" (rdx)                                     \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+#define SYSCALL4(name, type1, type2, type3, type4)             \
+int name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {     \
+       int status;                                             \
+       register type1 rdi asm("rdi");                          \
+       register type2 rsi asm("rsi");                          \
+       register type3 rdx asm("rdx");                          \
+       register type4 r10 asm("r10");                          \
+       rdi = arg1;                                             \
+       rsi = arg2;                                             \
+       rdx = arg3;                                             \
+       r10 = arg4;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name),                            \
+                 "r" (rdi),                                    \
+                 "r" (rsi),                                    \
+                 "r" (rdx),                                    \
+                 "r" (r10)                                     \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+#define SYSCALL5(name, type1, type2, type3, type4, type5)      \
+int name(type1 arg1, type2 arg2, type3 arg3, type4 arg4,       \
+         type5 arg5) {                                         \
+       int status;                                             \
+       register type1 rdi asm("rdi");                          \
+       register type2 rsi asm("rsi");                          \
+       register type3 rdx asm("rdx");                          \
+       register type4 r10 asm("r10");                          \
+       register type5 r8  asm("r8");                           \
+       rdi = arg1;                                             \
+       rsi = arg2;                                             \
+       rdx = arg3;                                             \
+       r10 = arg4;                                             \
+       r8  = arg5;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name),                            \
+                 "r" (rdi),                                    \
+                 "r" (rsi),                                    \
+                 "r" (rdx),                                    \
+                 "r" (r10),                                    \
+                 "r" (r8)                                      \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+#define SYSCALL6(name, type1, type2, type3, type4, type5, type6)\
+int name(type1 arg1, type2 arg2, type3 arg3, type4 arg4,       \
+         type5 arg5, type6 arg6) {                             \
+       int status;                                             \
+       register type1 rdi asm("rdi");                          \
+       register type2 rsi asm("rsi");                          \
+       register type3 rdx asm("rdx");                          \
+       register type4 r10 asm("r10");                          \
+       register type5 r8  asm("r8");                           \
+       register type6 r9  asm("r9");                           \
+       rdi = arg1;                                             \
+       rsi = arg2;                                             \
+       rdx = arg3;                                             \
+       r10 = arg4;                                             \
+       r8  = arg5;                                             \
+       r9  = arg6;                                             \
+       asm volatile(                                           \
+               "syscall"                                       \
+               : "=a" (status)                                 \
+               : "0" (__NR_##name),                            \
+                 "r" (rdi),                                    \
+                 "r" (rsi),                                    \
+                 "r" (rdx),                                    \
+                 "r" (r10),                                    \
+                 "r" (r8),                                     \
+                 "r" (r9)                                      \
+               : "memory", "rcx", "r11", "cc"                  \
+       );                                                      \
+       return status;                                          \
+}
+
+/**
+ * Physical memory management. 
+ */
+SYSCALL1(pmem_add, const struct pmem_region *);
+SYSCALL1(pmem_update, const struct pmem_region *);
+SYSCALL2(pmem_query, const struct pmem_region *, struct pmem_region *);
+SYSCALL4(pmem_alloc, size_t, size_t,
+         const struct pmem_region *, struct pmem_region *);
+
+/**
+ * Address space management.
+ */
+SYSCALL1(aspace_get_myid, id_t *);
+SYSCALL3(aspace_create, id_t, const char *, id_t *);
+SYSCALL1(aspace_destroy, id_t);
+SYSCALL5(aspace_find_hole, id_t, vaddr_t, size_t, size_t, vaddr_t *);
+SYSCALL6(aspace_add_region,
+         id_t, vaddr_t, size_t, vmflags_t, vmpagesize_t, const char *);
+SYSCALL3(aspace_del_region, id_t, vaddr_t, size_t);
+SYSCALL4(aspace_map_pmem, id_t, paddr_t, vaddr_t, size_t);
+SYSCALL3(aspace_unmap_pmem, id_t, vaddr_t, size_t);
+SYSCALL4(aspace_smartmap, id_t, id_t, vaddr_t, size_t);
+SYSCALL2(aspace_unsmartmap, id_t, id_t);
+SYSCALL1(aspace_dump2console, id_t);
+
+/**
+ * Task management.
+ */
+SYSCALL1(task_get_myid, id_t *);
+SYSCALL4(task_create, id_t, const char *, const start_state_t *, id_t *);
+SYSCALL1(task_exit, int);
+SYSCALL0(task_yield);
+
+/**
+ * ELF related system calls.
+ */
+SYSCALL2(elf_hwcap, id_t, uint32_t *);
index 0cfd820..8712934 100644 (file)
@@ -17,7 +17,6 @@
 # Required software to build GeekOS:
 # - GNU Make (http://www.gnu.org/software/make)
 # - gcc 2.95.2 generating code for target (i386/ELF) and host platforms
-# - nasm (http://nasm.sourceforge.net)
 # - Perl5, AWK (any version), egrep
 #
 # Cygwin (http://cygwin.com) may be used to build GeekOS.
@@ -52,11 +51,18 @@ VPATH := $(PROJECT_ROOT)/src
 # DEBUG=1 means VMM_DEBUG, VMM_INFO, and VMM_TRACE are enabled
 # as are SERIAL_PRINT_DEBUG
 # 
+
+ifeq ($(LEAN_AND_MEAN),1) 
+DEBUG=0
+DEBUG_SECTIONS=
+else
 DEBUG=1
 DEBUG_SECTIONS= 
+endif
+
 
 ifeq ($(DEBUG_ALL),1)
-  DEBUG_SECTIONS:= $(DEBUG_SECTIONS) -DDEBUG_SHADOW_PAGING -DDEBUG_CTRL_REGS -DDEBUG_INTERRUPTS -DDEBUG_IO -DDEBUG_KEYBOARD -DDEBUG_PIC -DDEBUG_PIT -DDEBUG_NVRAM -DDEBUG_EMULATOR -DDEBUG_GENERIC -DDEBUG_RAMDISK
+  DEBUG_SECTIONS:= $(DEBUG_SECTIONS) -DDEBUG_SHADOW_PAGING -DDEBUG_CTRL_REGS -DDEBUG_INTERRUPTS -DDEBUG_IO -DDEBUG_KEYBOARD -DDEBUG_PIC -DDEBUG_PIT -DDEBUG_NVRAM -DDEBUG_EMULATOR -DDEBUG_GENERIC -DDEBUG_RAMDISK -DDEBUG_XED -DDEBUG_HALT -DDEBUG_DEV_MGR
 endif
 
 ifeq ($(DEBUG_SHADOW_PAGING),1)
@@ -78,7 +84,7 @@ endif
 ifeq ($(DEBUG_INTERRUPTS),1)
 DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_INTERRUPTS
 else 
-ifeq ($(DEBUG_DEBUG_INTERRUPTS),0) 
+ifeq ($(DEBUG_INTERRUPTS),0) 
 DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_INTERRUPTS
 endif
 endif
@@ -147,33 +153,44 @@ DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_RAMDISK
 endif
 endif
 
-
-#DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DTEST_NE2K
-
-ifeq ($(DEBUG),1)
-  JRLDEBUG= -DSERIAL_PRINT_DEBUG=1 -DSERIAL_PRINT_DEBUG_LEVEL=10 -DSERIAL_PRINT=1 -DVMM_DEBUG=1 -DVMM_INFO=1 -DVMM_TRACE=1 $(DEBUG_SECTIONS)
-
+ifeq ($(TRACE_RAMDISK),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DTRACE_RAMDISK
 else
-  JRLDEBUG= -DSERIAL_PRINT_DEBUG=0 -DSERIAL_PRINT_DEBUG_LEVEL=999999 -DSERIAL_PRINT=0 -DVMM_DEBUG=0 -DVMM_INFO=0 -DVMM_TRACE=0
+ifeq ($(TRACE_RAMDSK),0)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UTRACE_RAMDISK
+endif
 endif
 
+ifeq ($(DEBUG_XED),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_XED
+else 
+ifeq ($(DEBUG_XED),0) 
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_XED
+endif
+endif
 
-#
-# DECODER is the decoder that will be used 
-# currently we only support xed
-#
-DECODER=XED
+ifeq ($(DEBUG_HALT),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_HALT
+else 
+ifeq ($(DEBUG_HALT),0) 
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_HALT
+endif
+endif
 
-DECODER_FLAGS=
-DECODER_SRCS=
-DECODER_LIBS=
+ifeq ($(DEBUG_DEV_MGR),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_DEV_MGR
+else 
+ifeq ($(DEBUG_DEV_MGR),0)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_DEV_MGR
+endif
+endif
 
-ifeq ($(DECODER),XED)
-DECODER_SRCS := vmm_xed.c
-DECODER_FLAGS :=  -L../lib/xed
-DECODER_LIBS := $(PROJECT_ROOT)/lib/xed/libxed.a
+#DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DTEST_NE2K
+
+ifeq ($(DEBUG),1)
+  JRLDEBUG=  -DVMM_DEBUG -DVMM_INFO -DVMM_TRACE $(DEBUG_SECTIONS)
 else
-# This is an error
+
 endif
 
 
@@ -213,55 +230,78 @@ endif
 ALL_TARGETS := vmm vm_kernel
 
 
+VMM_OBJS := \
+       palacios/vm_guest.o \
+       palacios/svm.o \
+       palacios/svm_handler.o \
+       palacios/vmm.o \
+       palacios/vmm_util.o \
+       palacios/vmm_ctrl_regs.o \
+       palacios/vmcb.o \
+       palacios/vmm_mem.o \
+       palacios/vmm_paging.o \
+       palacios/vmm_io.o \
+       palacios/vmm_debug.o \
+       palacios/svm_io.o \
+       palacios/vmm_intr.o \
+       palacios/vmm_time.o \
+       palacios/vmm_shadow_paging.o \
+       palacios/vm_guest_mem.o \
+       palacios/vm_dev.o \
+       palacios/vmm_dev_mgr.o \
+       palacios/vmm_decoder.o \
+       palacios/svm_halt.o \
+       palacios/svm_pause.o \
+       palacios/svm_wbinvd.o \
+       palacios/vmm_config.o \
+       palacios/vmm_hashtable.o \
+       palacios/vmm_string.o \
+       palacios/vmm_emulator.o \
+       palacios/vmm_queue.o \
+       palacios/vmm_host_events.o \
+       palacios/svm_lowlevel.o \
 
-
-
-
-VMM_ASM_SRCS :=  svm_lowlevel.asm vmm_lowlevel.asm\
-#                      vmx_lowlevel.asm
-
-VMM_ASM_OBJS := $(VMM_ASM_SRCS:%.asm=palacios/%.o)
-
-
-VMM_C_SRCS :=   vm_guest.c \
-               svm.c svm_handler.c vmm.c vmm_util.c vmm_ctrl_regs.c \
-               vmcb.c vmm_mem.c vmm_paging.c vmm_io.c vmm_debug.c svm_io.c \
-               vmm_intr.c vmm_time.c \
-               vmm_shadow_paging.c vm_guest_mem.c  \
-                vm_dev.c vmm_dev_mgr.c vmm_decoder.c \
-                svm_halt.c svm_pause.c svm_wbinvd.c \
-               vmm_config.c vmm_hashtable.c \
-               vmm_string.c vmm_emulator.c vmm_queue.c\
-                $(DECODER_SRCS)
 #              vmx.c vmcs_gen.c vmcs.c
 
-VMM_C_OBJS := $(VMM_C_SRCS:%.c=palacios/%.o)
-
-VMM_OBJS := $(VMM_C_OBJS) $(VMM_ASM_OBJS)
-
-
-
-XED_C_SRCS := v3-xed-compat.c
+# Extra C flags for the VMM objects
+$(VMM_OBJS) :: EXTRA_CFLAGS = \
+       $(JRLDEBUG) \
 
-XED_C_OBJS := $(XED_C_SRCS:%.c=xed/%.o)
 
-XED_GAS_SRCS := v3-udiv-compat.s
 
-XED_GAS_OBJS := $(XED_GAS_SRCS:%.s=xed/%.o)
+XED_OBJS := \
+       xed/v3-xed-compat.o \
+       xed/v3-udiv-compat.o \
 
-XED_OBJS := $(XED_C_OBJS) $(XED_GAS_OBJS)
+$(XED_OBJS) :: EXTRA_CFLAGS =
 
 
+DEVICES_OBJS := \
+       devices/generic.o \
+       devices/keyboard.o \
+       devices/nvram.o \
+       devices/timer.o \
+       devices/simple_pic.o \
+       devices/8259a.o \
+       devices/8254.o \
+       devices/serial.o \
+       devices/ramdisk.o \
+       devices/cdrom.o \
+       devices/bochs_debug.o \
 
-DEVICE_C_SRCS := generic.c keyboard.c nvram.c timer.c simple_pic.c 8259a.c 8254.c serial.c ramdisk.c cdrom.c
-
-DEVICE_C_OBJS := $(DEVICE_C_SRCS:%.c=devices/%.o)
-
-DEVICE_OBJS := $(DEVICE_C_OBJS)
-
-V3LIBS := $(DECODER_LIBS)
+$(DEVICES_OBJS) :: EXTRA_CFLAGS =
 
+#
+# DECODER is the decoder that will be used 
+# currently we only support xed
+#
+DECODER=XED
 
+ifeq ($(DECODER),XED)
+VMM_OBJS += palacios/vmm_xed.o
+else
+# This is an error
+endif
 
 
 
@@ -270,16 +310,23 @@ V3LIBS := $(DECODER_LIBS)
 #   This section defines programs that are used to build GeekOS.
 # ----------------------------------------------------------------------
 
-
+ifeq ($(ARCH),64)
+V3_ARCH := __V3_64BIT__
+else 
 V3_ARCH := __V3_32BIT__
-#V3_ARCH := __V3_64BIT__
+endif
+
 
 # Uncomment if cross compiling
 #TARGET_CC_PREFIX :=  $(PROJECT_ROOT)/../devtools/i386/bin/i386-elf-
 #TARGET_CC_PREFIX :=  i386-elf-
 
 # Target C compiler.  gcc 2.95.2 or later should work.
+ifeq ($(ARCH),64)
+TARGET_CC := $(TARGET_CC_PREFIX)gcc -m64
+else 
 TARGET_CC := $(TARGET_CC_PREFIX)gcc -m32
+endif
 #TARGET_CC := $(TARGET_CC_PREFIX)gcc34 -m32
 
 
@@ -302,7 +349,15 @@ TARGET_OBJCOPY := $(TARGET_CC_PREFIX)objcopy
 NASM := $(PROJECT_ROOT)/../devtools/bin/nasm
 #NASM := /opt/vmm-tools/bin/nasm
 
+CPP := cpp
+
+
+ifeq ($(ARCH),64)
+AS = as --64
+else 
 AS = as --32
+endif
+
 
 # Tool to build PFAT filesystem images.
 BUILDFAT := tools/builtFat.exe
@@ -329,17 +384,22 @@ FD_SECTORS_PER_TRACK := $(PERL) $(PROJECT_ROOT)/scripts/numsecs_per_track
 # ----------------------------------------------------------------------
 
 # Flags used for all C source files
-#GENERAL_OPTS := -O -Wall $(EXTRA_C_OPTS) $(VMM_FLAGS) -fPIC #-fvisibility=hidden
-GENERAL_OPTS :=  -Wall $(EXTRA_C_OPTS) $(VMM_FLAGS) -fPIC #-fvisibility=hidden
-CC_GENERAL_OPTS := $(GENERAL_OPTS) -Werror 
-
-# Flags used for VMM C source files
-CC_VMM_OPTS := -g -I$(PROJECT_ROOT)/include -D__V3VEE__ -D$(V3_ARCH) $(DECODER_FLAGS) $(JRLDEBUG)
-
-# Flags used for VMM C ASM files
-NASM_VMM_OPTS := -I$(PROJECT_ROOT)/src/palacios/ -f elf $(EXTRA_NASM_OPTS)
 
+CC_GENERAL_OPTS = \
+       -O \
+       -Wall \
+       -g \
+       -D__V3VEE__ \
+       -D$(V3_ARCH) \
+       $(EXTRA_C_OPTS) \
+       $(VMM_FLAGS) \
+       -I$(PROJECT_ROOT)/include \
+       -fPIC \
+       -Werror \
+       -Wp,-MD,$(@D)/.$(@F).d \
+       -Wp,-MT,$@ \
 
+#-fvisibility=hidden
 
 
 
@@ -351,26 +411,51 @@ OBJCOPY_FLAGS := -R .dynamic -R .note -R .comment
 #   Describes how to compile the source files.
 # ----------------------------------------------------------------------
 
-
-
-palacios/%.o : palacios/%.c
-       $(TARGET_CC) -c $(CC_GENERAL_OPTS) $(CC_VMM_OPTS) $< -o palacios/$*.o
-
-palacios/%.o : palacios/%.asm
-       $(NASM) $(NASM_VMM_OPTS) $< -o palacios/$*.o
-
-devices/%.o : devices/%.c
-       $(TARGET_CC) -c $(CC_GENERAL_OPTS) $(CC_VMM_OPTS) $< -o devices/$*.o
-
-devices/%.o : devices/%.asm
-       $(NASM) $(NASM_VMM_OPTS) $< -o devices/$*.o
-
-
-xed/%.o : xed/%.c
-       $(TARGET_CC) -c $(CC_GENERAL_OPTS) $(CC_VMM_OPTS) $< -o xed/$*.o
-
-xed/%.o : xed/%.s
-       $(AS) $< -o xed/$*.o
+# Compilation of kernel C source files
+# Usage:
+#      $(call build,TAG,commandline)
+#
+# If V=1 on the command line or the environment, then the actual
+# command executed will be echoed to the terminal.  Otherwise
+# only the tag and the output file will be printed to make
+# any warnings stand out from the compile messages.
+#
+build = \
+       @if [ -z "$V" ]; then \
+               echo '    [$1]  $@'; \
+               $2; \
+       else \
+               echo '$2'; \
+               $2; \
+       fi
+
+
+
+CC_COMPILE = \
+       $(call build,CC,$(TARGET_CC) \
+               $(CC_GENERAL_OPTS) \
+               $(EXTRA_CFLAGS) \
+               -c \
+               $< \
+               -o $@ \
+       )
+
+AS_COMPILE = \
+       $(call build,AS,$(TARGET_CC) \
+               $(CC_GENERAL_OPTS) \
+               $(EXTRA_CFLAGS) \
+               -c \
+               $< \
+               -o $@ \
+       )
+
+
+%.o: %.c
+       $(CC_COMPILE)
+%.o: %.S
+       $(AS_COMPILE)
+%.o: %.s
+       $(AS_COMPILE)
 
 
 # ----------------------------------------------------------------------
@@ -401,8 +486,6 @@ rombios_link:
 vgabios_link:
        ln -s -f ../src/vmboot/vgabios/VGABIOS-lgpl-latest.bin vgabios
 
-force_lwip:
-       (cd ../src/lwip/build; make clean; make)
 
 force_rombios: rombios_link
        (cd ../src/vmboot/rombios; make clean; make)
@@ -413,7 +496,7 @@ force_vgabios: vgabios_link
 force_payload: force_rombios force_vgabios
        ../scripts/make_payload.pl payload_layout.txt vm_kernel
 
-inter1: force_payload force_lwip
+inter1: force_payload
        -make clean
 
 world: inter1 vmm
@@ -429,15 +512,13 @@ palacios/vmm.bin : palacios/vmm.lib
 
 
 # The kernel executable and symbol map.
-palacios/vmm.lib: $(VMM_OBJS) $(DEVICE_OBJS) $(XED_OBJS) vm_kernel
-#      $(TARGET_LD) -o palacios/vmm.lib  \
-#              $(DECODER_FLAGS) \
-#               $(VMM_OBJS) $(DEVICE_OBJS) $(XED_OBJS) $(V3LIBS) -b binary vm_kernel
-#      $(TARGET_NM) palacios/vmm.lib > palacios/vmm.syms
-       $(TARGET_AR) rcs libv3vee.a  \
-                $(VMM_OBJS) $(DEVICE_OBJS) $(XED_OBJS)
-
+palacios/vmm.lib: libv3vee.a
+libv3vee.a: \
+       $(VMM_OBJS) \
+       $(DEVICES_OBJS) \
+       $(XED_OBJS) \
 
+       $(call build,AR,$(TARGET_AR) rcs $@ $^)
 
 force:
 
@@ -447,26 +528,10 @@ force:
 
 # Clean build directories of generated files
 clean :
-       for d in palacios devices; do \
-               (cd $$d && rm -f *); \
+       for d in palacios devices xed; do \
+               (cd $$d && rm -f * .*.d); \
        done
 
 
-# Build header file dependencies, so source files are recompiled when
-# header files they depend on are modified.
-depend : $(GENERATED_LIBC_SRCS)
-
-       $(TARGET_CC) -M $(CC_GENERAL_OPTS) $(CC_KERNEL_OPTS) \
-               $(VMM_C_SRCS:%.c=$(PROJECT_ROOT)/src/palacios/%.c) \
-               | $(PERL) -n -e 's,^(\S),palacios/$$1,;print' \
-               >> depend.mak
-       $(TARGET_CC) -M $(CC_GENERAL_OPTS) $(CC_KERNEL_OPTS) \
-               $(DEVICE_C_SRCS:%.c=$(PROJECT_ROOT)/src/devices/%.c) \
-               | $(PERL) -n -e 's,^(\S),devices/$$1,;print' \
-               >> depend.mak
-
-# By default, there are no header file dependencies.
-depend.mak :
-       touch $@
-
-include depend.mak
+# Include all of the generated dependency files if they exist
+-include */.*.o.d
index cbd9d7e..e57922d 100644 (file)
  */
 
 
-#ifndef __8237_DMA_H
-#define __8237_DMA_H
+#ifndef __DEVICES_8237_DMA_H__
+#define __DEVICES_8237_DMA_H__
 
+#ifdef __V3VEE__
 
-#include <palacios/vm_dev.h>
 
-struct vm_device * create_dma();
+#include <palacios/vm_dev.h>
 
+struct vm_device * v3_create_dma();
 
 
+#endif // ! __V3VEE__
 
 #endif
index bceb746..c5efc0f 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __8254_H
-#define __8254_H
+#ifndef __DEVICES_8254_H__
+#define __DEVICES_8254_H__
 
-#include <palacios/vm_dev.h>
+#ifdef __V3VEE__
 
 
 
-struct vm_device * create_pit();
+#include <palacios/vm_dev.h>
 
+struct vm_device * v3_create_pit();
 
 
 
+#endif // ! __V3VEE__
 
 #endif
index 9079d41..3bc375b 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __8259A_H
-#define __8259A_H
+#ifndef __DEVICES_8259A_H__
+#define __DEVICES_8259A_H__
+
+#ifdef __V3VEE__
+
+
 
 #include <palacios/vm_dev.h>
 
+struct vm_device * v3_create_pic();
+
 
-struct vm_device * create_pic();
 
+#endif // ! __V3VEE__
 
 #endif
diff --git a/palacios/include/devices/bochs_debug.h b/palacios/include/devices/bochs_debug.h
new file mode 100644 (file)
index 0000000..d441202
--- /dev/null
@@ -0,0 +1,32 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __DEVICES_BOCHS_DEBUG_H__
+#define __DEVICES_BOCHS_DEBUG_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vm_dev.h>
+
+struct vm_device * v3_create_bochs_debug();
+
+
+#endif // ! __V3VEE__
+
+#endif
index 5f5979a..c4f5b46 100644 (file)
@@ -18,8 +18,8 @@
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __DEVICES_CDROM_H_
-#define __DEVICES_CDROM_H_
+#ifndef __DEVICES_CDROM_H__
+#define __DEVICES_CDROM_H__
 
 
 #ifdef __V3VEE__
index 3dd33bc..664466e 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __GENERIC_H__
-#define __GENERIC_H__
+
+
+#ifndef __DEVICES_GENERIC_H__
+#define __DEVICES_GENERIC_H__
+
+#ifdef __V3VEE__
 
 
 #include <palacios/vm_dev.h>
@@ -53,6 +57,9 @@ int v3_generic_add_mem_range(struct vm_device * dev, void * start, void * end, u
 int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type);
 
 // The lists given are null terminated
-struct vm_device * create_generic();  
+struct vm_device * v3_create_generic();  
+
+
+#endif // ! __V3VEE__
 
 #endif
index 66630fe..fd6cf04 100644 (file)
  * 
  */
 
-#ifndef __IDE_H__
-#define __IDE_H__
-
+#ifndef __DEVICES_IDE_H__
+#define __DEVICES_IDE_H__
 
 #ifdef __V3VEE__
+
+
 #include <palacios/vmm_types.h>
 
 
index 64ad387..d2923be 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __KEYBOARD_H
-#define __KEYBOARD_H
+#ifndef __DEVICES_KEYBOARD_H__
+#define __DEVICES_KEYBOARD_H__
+
+#ifdef __V3VEE__
+
+
 
 #include <palacios/vm_dev.h>
 
-//
-// The underlying driver needs to call this on each key that
-// it wants to inject into the VMM for delivery to a VM
-//
-void deliver_key_to_vmm(uchar_t status, uchar_t scancode);
-// And call this one each streaming mouse event
-// that the VMM should deliver
-void deliver_mouse_to_vmm(uchar_t mouse_packet[3]);
+struct vm_device * v3_create_keyboard();
+
+
 
-struct vm_device *create_keyboard();
+#endif // ! __V3VEE__
 
 #endif
index cd6328c..711d8f7 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __NVRAM_H
-#define __NVRAM_H
+#ifndef __DEVICES_NVRAM_H__
+#define __DEVICES_NVRAM_H__
+
+#ifdef __V3VEE__
+
 
 #include <palacios/vm_dev.h>
 
-struct vm_device *create_nvram();
+struct vm_device * v3_create_nvram();
+
+
 
-// The host os needs to call this
-void deliver_timer_interrupt_to_vmm(uint_t period_us);
+#endif // ! __V3VEE__
 
 #endif
index be30d5a..017512d 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __DEVICES_RAMDISK_H_
-#define __DEVICES_RAMDISK_H_
+#ifndef __DEVICES_RAMDISK_H__
+#define __DEVICES_RAMDISK_H__
+
+#ifdef __V3VEE__
+
+
 
 #include <palacios/vmm_types.h>
 #include <palacios/vm_dev.h>
@@ -28,6 +32,9 @@ struct cdrom_ops;
 
 int v3_ramdisk_register_cdrom(struct vm_device * ide_dev, uint_t busID, uint_t driveID, struct cdrom_ops * cd, void * private_data);
 
-struct vm_device * create_ramdisk(void);
+struct vm_device * v3_create_ramdisk();
+
+
+#endif // ! __V3VEE__
 
 #endif
index 36bd07c..f9be921 100644 (file)
  */
 
 
-#ifndef __SERIAL_H__
-#define __SERIAL_H__
+#ifndef __DEVICES_SERIAL_H__
+#define __DEVICES_SERIAL_H__
+
+#ifdef __V3VEE__
 
 
 
 #include <palacios/vm_dev.h>
 
+struct vm_device * v3_create_serial();
+
 
 
-struct vm_device * create_serial();
+#endif // ! __V3VEE__
 
 #endif
index 58fac51..0a49b10 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __SIMPLE_PIC_H
-#define __SIMPLE_PIC_H
+#ifndef __DEVICES_SIMPLE_PIC_H__
+#define __DEVICES_SIMPLE_PIC_H__
+
+#ifdef __V3VEE__
+
+
 #include <palacios/vm_dev.h>
 
-struct vm_device * create_simple_pic();
+struct vm_device * v3_create_simple_pic();
+
+
+#endif // ! __V3VEE__
 
 #endif
index 9a794e2..e38c307 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __TIMER_H
-#define __TIMER_H
+#ifndef __DEVICES_TIMER_H__
+#define __DEVICES_TIMER_H__
 
-#include <palacios/vm_dev.h>
+#ifdef __V3VEE__
 
 
+#include <palacios/vm_dev.h>
 
-struct vm_device * create_timer();
+struct vm_device * v3_create_timer();
 
 
 
+#endif // ! __V3VEE__
 
 #endif
index 066ab7c..b522ee3 100644 (file)
@@ -81,8 +81,8 @@
 
 
 
-void Init_SVM(struct vmm_ctrl_ops * vmm_ops);
-int is_svm_capable();
+void v3_init_SVM(struct v3_ctrl_ops * vmm_ops);
+int v3_is_svm_capable();
 
 #endif
 
index 009bcc9..1a29fc2 100644 (file)
@@ -27,7 +27,7 @@
 #include <palacios/vmm.h>
 
 
-int handle_svm_halt(struct guest_info * info);
+int v3_handle_svm_halt(struct guest_info * info);
 
 #endif // ! __V3VEE__
 
index 25e0fc1..e2425ac 100644 (file)
 /******************************************/
 
 
-
-
-static const uchar_t VMEXIT_CR0_READ_STR[] = "VMEXIT_CR0_READ";
-static const uchar_t VMEXIT_CR1_READ_STR[] = "VMEXIT_CR1_READ";
-static const uchar_t VMEXIT_CR2_READ_STR[] = "VMEXIT_CR2_READ";
-static const uchar_t VMEXIT_CR3_READ_STR[] = "VMEXIT_CR3_READ";
-static const uchar_t VMEXIT_CR4_READ_STR[] = "VMEXIT_CR4_READ";
-static const uchar_t VMEXIT_CR5_READ_STR[] = "VMEXIT_CR5_READ";
-static const uchar_t VMEXIT_CR6_READ_STR[] = "VMEXIT_CR6_READ";
-static const uchar_t VMEXIT_CR7_READ_STR[] = "VMEXIT_CR7_READ";
-static const uchar_t VMEXIT_CR8_READ_STR[] = "VMEXIT_CR8_READ";
-static const uchar_t VMEXIT_CR9_READ_STR[] = "VMEXIT_CR9_READ";
-static const uchar_t VMEXIT_CR10_READ_STR[] = "VMEXIT_CR10_READ";
-static const uchar_t VMEXIT_CR11_READ_STR[] = "VMEXIT_CR11_READ";
-static const uchar_t VMEXIT_CR12_READ_STR[] = "VMEXIT_CR12_READ";
-static const uchar_t VMEXIT_CR13_READ_STR[] = "VMEXIT_CR13_READ";
-static const uchar_t VMEXIT_CR14_READ_STR[] = "VMEXIT_CR14_READ";
-static const uchar_t VMEXIT_CR15_READ_STR[] = "VMEXIT_CR15_READ";
-static const uchar_t VMEXIT_CR0_WRITE_STR[] = "VMEXIT_CR0_WRITE";
-static const uchar_t VMEXIT_CR1_WRITE_STR[] = "VMEXIT_CR1_WRITE";
-static const uchar_t VMEXIT_CR2_WRITE_STR[] = "VMEXIT_CR2_WRITE";
-static const uchar_t VMEXIT_CR3_WRITE_STR[] = "VMEXIT_CR3_WRITE";
-static const uchar_t VMEXIT_CR4_WRITE_STR[] = "VMEXIT_CR4_WRITE";
-static const uchar_t VMEXIT_CR5_WRITE_STR[] = "VMEXIT_CR5_WRITE";
-static const uchar_t VMEXIT_CR6_WRITE_STR[] = "VMEXIT_CR6_WRITE";
-static const uchar_t VMEXIT_CR7_WRITE_STR[] = "VMEXIT_CR7_WRITE";
-static const uchar_t VMEXIT_CR8_WRITE_STR[] = "VMEXIT_CR8_WRITE";
-static const uchar_t VMEXIT_CR9_WRITE_STR[] = "VMEXIT_CR9_WRITE";
-static const uchar_t VMEXIT_CR10_WRITE_STR[] = "VMEXIT_CR10_WRITE";
-static const uchar_t VMEXIT_CR11_WRITE_STR[] = "VMEXIT_CR11_WRITE";
-static const uchar_t VMEXIT_CR12_WRITE_STR[] = "VMEXIT_CR12_WRITE";
-static const uchar_t VMEXIT_CR13_WRITE_STR[] = "VMEXIT_CR13_WRITE";
-static const uchar_t VMEXIT_CR14_WRITE_STR[] = "VMEXIT_CR14_WRITE";
-static const uchar_t VMEXIT_CR15_WRITE_STR[] = "VMEXIT_CR15_WRITE";
-static const uchar_t VMEXIT_DR0_READ_STR[] = "VMEXIT_DR0_READ";
-static const uchar_t VMEXIT_DR1_READ_STR[] = "VMEXIT_DR1_READ";
-static const uchar_t VMEXIT_DR2_READ_STR[] = "VMEXIT_DR2_READ";
-static const uchar_t VMEXIT_DR3_READ_STR[] = "VMEXIT_DR3_READ";
-static const uchar_t VMEXIT_DR4_READ_STR[] = "VMEXIT_DR4_READ";
-static const uchar_t VMEXIT_DR5_READ_STR[] = "VMEXIT_DR5_READ";
-static const uchar_t VMEXIT_DR6_READ_STR[] = "VMEXIT_DR6_READ";
-static const uchar_t VMEXIT_DR7_READ_STR[] = "VMEXIT_DR7_READ";
-static const uchar_t VMEXIT_DR8_READ_STR[] = "VMEXIT_DR8_READ";
-static const uchar_t VMEXIT_DR9_READ_STR[] = "VMEXIT_DR9_READ";
-static const uchar_t VMEXIT_DR10_READ_STR[] = "VMEXIT_DR10_READ";
-static const uchar_t VMEXIT_DR11_READ_STR[] = "VMEXIT_DR11_READ";
-static const uchar_t VMEXIT_DR12_READ_STR[] = "VMEXIT_DR12_READ";
-static const uchar_t VMEXIT_DR13_READ_STR[] = "VMEXIT_DR13_READ";
-static const uchar_t VMEXIT_DR14_READ_STR[] = "VMEXIT_DR14_READ";
-static const uchar_t VMEXIT_DR15_READ_STR[] = "VMEXIT_DR15_READ";
-static const uchar_t VMEXIT_DR0_WRITE_STR[] = "VMEXIT_DR0_WRITE";
-static const uchar_t VMEXIT_DR1_WRITE_STR[] = "VMEXIT_DR1_WRITE";
-static const uchar_t VMEXIT_DR2_WRITE_STR[] = "VMEXIT_DR2_WRITE";
-static const uchar_t VMEXIT_DR3_WRITE_STR[] = "VMEXIT_DR3_WRITE";
-static const uchar_t VMEXIT_DR4_WRITE_STR[] = "VMEXIT_DR4_WRITE";
-static const uchar_t VMEXIT_DR5_WRITE_STR[] = "VMEXIT_DR5_WRITE";
-static const uchar_t VMEXIT_DR6_WRITE_STR[] = "VMEXIT_DR6_WRITE";
-static const uchar_t VMEXIT_DR7_WRITE_STR[] = "VMEXIT_DR7_WRITE";
-static const uchar_t VMEXIT_DR8_WRITE_STR[] = "VMEXIT_DR8_WRITE";
-static const uchar_t VMEXIT_DR9_WRITE_STR[] = "VMEXIT_DR9_WRITE";
-static const uchar_t VMEXIT_DR10_WRITE_STR[] = "VMEXIT_DR10_WRITE";
-static const uchar_t VMEXIT_DR11_WRITE_STR[] = "VMEXIT_DR11_WRITE";
-static const uchar_t VMEXIT_DR12_WRITE_STR[] = "VMEXIT_DR12_WRITE";
-static const uchar_t VMEXIT_DR13_WRITE_STR[] = "VMEXIT_DR13_WRITE";
-static const uchar_t VMEXIT_DR14_WRITE_STR[] = "VMEXIT_DR14_WRITE";
-static const uchar_t VMEXIT_DR15_WRITE_STR[] = "VMEXIT_DR15_WRITE";
-static const uchar_t VMEXIT_EXCP0_STR[] = "VMEXIT_EXCP0";
-static const uchar_t VMEXIT_EXCP1_STR[] = "VMEXIT_EXCP1";
-static const uchar_t VMEXIT_EXCP2_STR[] = "VMEXIT_EXCP2";
-static const uchar_t VMEXIT_EXCP3_STR[] = "VMEXIT_EXCP3";
-static const uchar_t VMEXIT_EXCP4_STR[] = "VMEXIT_EXCP4";
-static const uchar_t VMEXIT_EXCP5_STR[] = "VMEXIT_EXCP5";
-static const uchar_t VMEXIT_EXCP6_STR[] = "VMEXIT_EXCP6";
-static const uchar_t VMEXIT_EXCP7_STR[] = "VMEXIT_EXCP7";
-static const uchar_t VMEXIT_EXCP8_STR[] = "VMEXIT_EXCP8";
-static const uchar_t VMEXIT_EXCP9_STR[] = "VMEXIT_EXCP9";
-static const uchar_t VMEXIT_EXCP10_STR[] = "VMEXIT_EXCP10";
-static const uchar_t VMEXIT_EXCP11_STR[] = "VMEXIT_EXCP11";
-static const uchar_t VMEXIT_EXCP12_STR[] = "VMEXIT_EXCP12";
-static const uchar_t VMEXIT_EXCP13_STR[] = "VMEXIT_EXCP13";
-static const uchar_t VMEXIT_EXCP14_STR[] = "VMEXIT_EXCP14";
-static const uchar_t VMEXIT_EXCP15_STR[] = "VMEXIT_EXCP15";
-static const uchar_t VMEXIT_EXCP16_STR[] = "VMEXIT_EXCP16";
-static const uchar_t VMEXIT_EXCP17_STR[] = "VMEXIT_EXCP17";
-static const uchar_t VMEXIT_EXCP18_STR[] = "VMEXIT_EXCP18";
-static const uchar_t VMEXIT_EXCP19_STR[] = "VMEXIT_EXCP19";
-static const uchar_t VMEXIT_EXCP20_STR[] = "VMEXIT_EXCP20";
-static const uchar_t VMEXIT_EXCP21_STR[] = "VMEXIT_EXCP21";
-static const uchar_t VMEXIT_EXCP22_STR[] = "VMEXIT_EXCP22";
-static const uchar_t VMEXIT_EXCP23_STR[] = "VMEXIT_EXCP23";
-static const uchar_t VMEXIT_EXCP24_STR[] = "VMEXIT_EXCP24";
-static const uchar_t VMEXIT_EXCP25_STR[] = "VMEXIT_EXCP25";
-static const uchar_t VMEXIT_EXCP26_STR[] = "VMEXIT_EXCP26";
-static const uchar_t VMEXIT_EXCP27_STR[] = "VMEXIT_EXCP27";
-static const uchar_t VMEXIT_EXCP28_STR[] = "VMEXIT_EXCP28";
-static const uchar_t VMEXIT_EXCP29_STR[] = "VMEXIT_EXCP29";
-static const uchar_t VMEXIT_EXCP30_STR[] = "VMEXIT_EXCP30";
-static const uchar_t VMEXIT_EXCP31_STR[] = "VMEXIT_EXCP31";
-static const uchar_t VMEXIT_INTR_STR[] = "VMEXIT_INTR";
-static const uchar_t VMEXIT_NMI_STR[] = "VMEXIT_NMI";
-static const uchar_t VMEXIT_SMI_STR[] = "VMEXIT_SMI";
-static const uchar_t VMEXIT_INIT_STR[] = "VMEXIT_INIT";
-static const uchar_t VMEXIT_VINITR_STR[] = "VMEXIT_VINITR";
-static const uchar_t VMEXIT_CR0_SEL_WRITE_STR[] = "VMEXIT_CR0_SEL_WRITE";
-static const uchar_t VMEXIT_IDTR_READ_STR[] = "VMEXIT_IDTR_READ";
-static const uchar_t VMEXIT_GDTR_READ_STR[] = "VMEXIT_GDTR_READ";
-static const uchar_t VMEXIT_LDTR_READ_STR[] = "VMEXIT_LDTR_READ";
-static const uchar_t VMEXIT_TR_READ_STR[] = "VMEXIT_TR_READ";
-static const uchar_t VMEXIT_IDTR_WRITE_STR[] = "VMEXIT_IDTR_WRITE";
-static const uchar_t VMEXIT_GDTR_WRITE_STR[] = "VMEXIT_GDTR_WRITE";
-static const uchar_t VMEXIT_LDTR_WRITE_STR[] = "VMEXIT_LDTR_WRITE";
-static const uchar_t VMEXIT_TR_WRITE_STR[] = "VMEXIT_TR_WRITE";
-static const uchar_t VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
-static const uchar_t VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
-static const uchar_t VMEXIT_PUSHF_STR[] = "VMEXIT_PUSHF";
-static const uchar_t VMEXIT_POPF_STR[] = "VMEXIT_POPF";
-static const uchar_t VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
-static const uchar_t VMEXIT_RSM_STR[] = "VMEXIT_RSM";
-static const uchar_t VMEXIT_IRET_STR[] = "VMEXIT_IRET";
-static const uchar_t VMEXIT_SWINT_STR[] = "VMEXIT_SWINT";
-static const uchar_t VMEXIT_INVD_STR[] = "VMEXIT_INVD";
-static const uchar_t VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
-static const uchar_t VMEXIT_HLT_STR[] = "VMEXIT_HLT";
-static const uchar_t VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
-static const uchar_t VMEXIT_INVLPGA_STR[] = "VMEXIT_INVLPGA";
-static const uchar_t VMEXIT_IOIO_STR[] = "VMEXIT_IOIO";
-static const uchar_t VMEXIT_MSR_STR[] = "VMEXIT_MSR";
-static const uchar_t VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
-static const uchar_t VMEXIT_FERR_FREEZE_STR[] = "VMEXIT_FERR_FREEZE";
-static const uchar_t VMEXIT_SHUTDOWN_STR[] = "VMEXIT_SHUTDOWN";
-static const uchar_t VMEXIT_VMRUN_STR[] = "VMEXIT_VMRUN";
-static const uchar_t VMEXIT_VMMCALL_STR[] = "VMEXIT_VMMCALL";
-static const uchar_t VMEXIT_VMLOAD_STR[] = "VMEXIT_VMLOAD";
-static const uchar_t VMEXIT_VMSAVE_STR[] = "VMEXIT_VMSAVE";
-static const uchar_t VMEXIT_STGI_STR[] = "VMEXIT_STGI";
-static const uchar_t VMEXIT_CLGI_STR[] = "VMEXIT_CLGI";
-static const uchar_t VMEXIT_SKINIT_STR[] = "VMEXIT_SKINIT";
-static const uchar_t VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
-static const uchar_t VMEXIT_ICEBP_STR[] = "VMEXIT_ICEBP";
-static const uchar_t VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
-static const uchar_t VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
-static const uchar_t VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
-static const uchar_t VMEXIT_MWAIT_CONDITIONAL_STR[] = "VMEXIT_MWAIT_CONDITIONAL";
-static const uchar_t VMEXIT_NPF_STR[] = "VMEXIT_NPF";
-static const uchar_t VMEXIT_INVALID_VMCB_STR[] = "VMEXIT_INVALID_VMCB";
-
-
-const uchar_t * vmexit_code_to_str(uint_t exit_code);
-
-
-
-int handle_shadow_paging(struct guest_info * info);
-
-int handle_svm_intr(struct guest_info * info);
-
-int handle_svm_exit(struct guest_info * info);
+int v3_handle_svm_exit(struct guest_info * info);
 
 #endif // ! __V3VEE__
 
index c60796f..b1db99c 100644 (file)
@@ -43,10 +43,10 @@ struct svm_io_info {
 };
 
 
-int handle_svm_io_in(struct guest_info * info);
-int handle_svm_io_ins(struct guest_info * info);
-int handle_svm_io_out(struct guest_info * info);
-int handle_svm_io_outs(struct guest_info * info);
+int v3_handle_svm_io_in(struct guest_info * info);
+int v3_handle_svm_io_ins(struct guest_info * info);
+int v3_handle_svm_io_out(struct guest_info * info);
+int v3_handle_svm_io_outs(struct guest_info * info);
 
 #endif // !__V3VEE__
 
index b7c326c..5f119f6 100644 (file)
@@ -28,7 +28,7 @@
 #include <palacios/vmm.h>
 
 
-int handle_svm_pause(struct guest_info * info);
+int v3_handle_svm_pause(struct guest_info * info);
 
 
 #endif // ! __V3VEE__
index 3775b45..e373faf 100644 (file)
@@ -27,7 +27,7 @@
 #include <palacios/vmm.h>
 
 
-int handle_svm_wbinvd(struct guest_info * info);
+int v3_handle_svm_wbinvd(struct guest_info * info);
 
 
 #endif // ! __V3VEE__
index 7cbebd4..8bd93a9 100644 (file)
@@ -72,33 +72,33 @@ struct vm_device {
 
 
 
-struct vm_device * allocate_device();
-struct vm_device * create_device(char * name, struct vm_device_ops * ops, void * private_data);
-void free_device(struct vm_device * dev);
 
+struct vm_device * v3_create_device(char * name, struct vm_device_ops * ops, void * private_data);
+void v3_free_device(struct vm_device * dev);
 
 
-int dev_hook_io(struct vm_device   *dev,
+
+int v3_dev_hook_io(struct vm_device   *dev,
                ushort_t            port,
                int (*read)(ushort_t port, void * dst, uint_t length, struct vm_device * dev),
                int (*write)(ushort_t port, void * src, uint_t length, struct vm_device * dev));
 
-int dev_unhook_io(struct vm_device   *dev,
+int v3_dev_unhook_io(struct vm_device   *dev,
                  ushort_t            port);
 
-int dev_hook_mem(struct vm_device   *dev,
+int v3_dev_hook_mem(struct vm_device   *dev,
                 void               *start,
                 void               *end);
 
-int dev_unhook_mem(struct vm_device   * dev,
+int v3_dev_unhook_mem(struct vm_device   * dev,
                   void               * start,
                   void               * end);
 
 
-int dev_hook_irq(struct vm_device * dev,
+int v3_dev_hook_irq(struct vm_device * dev,
                 uint_t irq, 
                 int (*handler)(uint_t irq, struct vm_device * dev));
-int dev_unhook_irq(struct vm_device * dev, uint_t irq);
+int v3_dev_unhook_irq(struct vm_device * dev, uint_t irq);
 
 
 
index 1bd6a8d..010fc76 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __VM_GUEST_H
-#define __VM_GUEST_H
+#ifndef __VM_GUEST_H__
+#define __VM_GUEST_H__
 
 #ifdef __V3VEE__
 
-
-#include <palacios/vmm_mem.h>
 #include <palacios/vmm_types.h>
+#include <palacios/vmm_mem.h>
 #include <palacios/vmm_io.h>
 #include <palacios/vmm_shadow_paging.h>
 #include <palacios/vmm_intr.h>
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vmm_time.h>
 #include <palacios/vmm_emulator.h>
+#include <palacios/vmm_host_events.h>
+
 
-typedef ullong_t v3_reg_t;
 
 
 
@@ -103,20 +103,14 @@ struct vmm_io_map;
 struct emulation_state;
 struct v3_intr_state;
 
-struct vm_ctrl_ops {
-  int (*raise_irq)(struct guest_info * info, int irq);
-  int (*lower_irq)(struct guest_info * info, int irq);
-};
 
 
+typedef enum {SHADOW_PAGING, NESTED_PAGING} v3_paging_mode_t;
+typedef enum {VM_RUNNING, VM_STOPPED, VM_SUSPENDED, VM_ERROR, VM_EMULATING} v3_vm_operating_mode_t;
 
 
-typedef enum {SHADOW_PAGING, NESTED_PAGING} vmm_paging_mode_t;
-typedef enum {VM_RUNNING, VM_STOPPED, VM_SUSPENDED, VM_ERROR, VM_EMULATING} vm_operating_mode_t;
-
-
-typedef enum {REAL, /*UNREAL,*/ PROTECTED, PROTECTED_PAE, LONG, LONG_32_COMPAT, LONG_16_COMPAT} vm_cpu_mode_t;
-typedef enum {PHYSICAL_MEM, VIRTUAL_MEM} vm_mem_mode_t;
+typedef enum {REAL, /*UNREAL,*/ PROTECTED, PROTECTED_PAE, LONG, LONG_32_COMPAT, LONG_16_COMPAT} v3_vm_cpu_mode_t;
+typedef enum {PHYSICAL_MEM, VIRTUAL_MEM} v3_vm_mem_mode_t;
 
 
 
@@ -129,7 +123,7 @@ struct guest_info {
 
   struct vm_time time_state;
   
-  vmm_paging_mode_t shdw_pg_mode;
+  v3_paging_mode_t shdw_pg_mode;
   struct shadow_page_state shdw_pg_state;
   addr_t direct_map_pt;
   // nested_paging_t nested_page_state;
@@ -143,8 +137,10 @@ struct guest_info {
 
   struct vmm_dev_mgr  dev_mgr;
 
-  vm_cpu_mode_t cpu_mode;
-  vm_mem_mode_t mem_mode;
+  struct v3_host_events host_event_hooks;
+
+  v3_vm_cpu_mode_t cpu_mode;
+  v3_vm_mem_mode_t mem_mode;
 
 
   struct v3_gprs vm_regs;
@@ -152,11 +148,9 @@ struct guest_info {
   struct v3_dbg_regs dbg_regs;
   struct v3_segments segments;
 
-  struct vm_ctrl_ops vm_ops;
-
   struct emulation_state emulator;
 
-  vm_operating_mode_t run_state;
+  v3_vm_operating_mode_t run_state;
   void * vmm_data;
 
   /* TEMP */
@@ -165,13 +159,13 @@ struct guest_info {
 };
 
 
-vm_cpu_mode_t get_cpu_mode(struct guest_info * info);
-vm_mem_mode_t get_mem_mode(struct guest_info * info);
+v3_vm_cpu_mode_t v3_get_cpu_mode(struct guest_info * info);
+v3_vm_mem_mode_t v3_get_mem_mode(struct guest_info * info);
 
 
-void PrintV3Segments(struct guest_info * info);
-void PrintV3CtrlRegs(struct guest_info * info);
-void PrintV3GPRs(struct guest_info * info);
+void v3_print_segments(struct guest_info * info);
+void v3_print_ctrl_regs(struct guest_info * info);
+void v3_print_GPRs(struct guest_info * info);
 
 #endif // ! __V3VEE__
 
index ad139e8..f7a612d 100644 (file)
@@ -17,8 +17,8 @@
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __VMM_H
-#define __VMM_H
+#ifndef __VMM_H__
+#define __VMM_H__
 
 
 #include <palacios/vm_guest.h>
 
 /* utility definitions */
 
-#if VMM_DEBUG
+#ifdef VMM_DEBUG
 #define PrintDebug(fmt, args...)                       \
   do {                                                 \
-    extern struct vmm_os_hooks * os_hooks;             \
+    extern struct v3_os_hooks * os_hooks;              \
     if ((os_hooks) && (os_hooks)->print_debug) {       \
       (os_hooks)->print_debug((fmt), ##args);          \
     }                                                  \
@@ -50,7 +50,7 @@
 
 #define PrintError(fmt, args...)                                       \
   do {                                                                 \
-    extern struct vmm_os_hooks * os_hooks;                             \
+    extern struct v3_os_hooks * os_hooks;                              \
     if ((os_hooks) && (os_hooks)->print_debug) {                       \
       (os_hooks)->print_debug("%s(%d): " fmt, __FILE__, __LINE__, ##args); \
     }                                                                  \
 
 
 
-#if VMM_INFO
+#ifdef VMM_INFO
 #define PrintInfo(fmt, args...)                        \
   do {                                                 \
-    extern struct vmm_os_hooks * os_hooks;             \
+    extern struct v3_os_hooks * os_hooks;              \
     if ((os_hooks) && (os_hooks)->print_info) {                \
       (os_hooks)->print_info((fmt), ##args);           \
     }                                                  \
 #endif
 
 
-#if VMM_TRACE
+#ifdef VMM_TRACE
 #define PrintTrace(fmt, args...)                                       \
   do {                                                                 \
-    extern struct vmm_os_hooks * os_hooks;                             \
+    extern struct v3_os_hooks * os_hooks;                              \
     if ((os_hooks) && (os_hooks)->print_trace) {                       \
       (os_hooks)->print_trace(fmt, ##args);                            \
     }                                                                  \
@@ -86,7 +86,7 @@
 
 #define V3_AllocPages(num_pages)                       \
   ({                                                   \
-    extern struct vmm_os_hooks * os_hooks;             \
+    extern struct v3_os_hooks * os_hooks;              \
     void * ptr = 0;                                    \
     if ((os_hooks) && (os_hooks)->allocate_pages) {    \
       ptr = (os_hooks)->allocate_pages(num_pages);     \
 
 #define V3_FreePage(page)                      \
   do {                                         \
-    extern struct vmm_os_hooks * os_hooks;     \
+    extern struct v3_os_hooks * os_hooks;      \
     if ((os_hooks) && (os_hooks)->free_page) { \
       (os_hooks)->free_page(page);             \
     }                                          \
   } while(0)                                   \
 
 
+#define V3_VAddr(addr) ({                              \
+      extern struct v3_os_hooks * os_hooks;            \
+      void * var = 0;                                  \
+      if ((os_hooks) && (os_hooks)->paddr_to_vaddr) {  \
+       var = (os_hooks)->paddr_to_vaddr(addr);         \
+      }                                                        \
+      var;                                             \
+    })
+
+
+#define V3_PAddr(addr) ({                              \
+      extern struct v3_os_hooks * os_hooks;            \
+      void * var = 0;                                  \
+      if ((os_hooks) && (os_hooks)->vaddr_to_paddr) {  \
+       var = (os_hooks)->vaddr_to_paddr(addr);         \
+      }                                                        \
+      var;                                             \
+    })
+
 
 
 #define V3_Malloc(size) ({                     \
-      extern struct vmm_os_hooks * os_hooks;   \
+      extern struct v3_os_hooks * os_hooks;    \
       void * var = 0;                          \
       if ((os_hooks) && (os_hooks)->malloc) {  \
        var = (os_hooks)->malloc(size);         \
 // We need to check the hook structure at runtime to ensure its SAFE
 #define V3_Free(addr)                                  \
   do {                                                 \
-    extern struct vmm_os_hooks * os_hooks;             \
+    extern struct v3_os_hooks * os_hooks;              \
     if ((os_hooks) && (os_hooks)->free) {              \
       (os_hooks)->free(addr);                          \
     }                                                  \
 #define V3_CPU_KHZ()                                   \
   ({                                                   \
     unsigned int khz = 0;                              \
-    extern struct vmm_os_hooks * os_hooks;             \
+    extern struct v3_os_hooks * os_hooks;              \
     if ((os_hooks) && (os_hooks)->get_cpu_khz) {       \
       khz = (os_hooks)->get_cpu_khz();                 \
     }                                                  \
 #define V3_Hook_Interrupt(irq, opaque)                         \
   ({                                                           \
     int ret = 0;                                               \
-    extern struct vmm_os_hooks * os_hooks;                     \
+    extern struct v3_os_hooks * os_hooks;                      \
     if ((os_hooks) && (os_hooks)->hook_interrupt) {            \
       ret = (os_hooks)->hook_interrupt(irq, opaque);           \
     }                                                          \
 
 #define V3_Yield(addr)                                 \
   do {                                                 \
-    extern struct vmm_os_hooks * os_hooks;             \
+    extern struct v3_os_hooks * os_hooks;              \
     if ((os_hooks) && (os_hooks)->yield_cpu) {         \
       (os_hooks)->yield_cpu();                         \
     }                                                  \
@@ -191,10 +210,13 @@ typedef enum v3_cpu_arch {V3_INVALID_CPU, V3_SVM_CPU, V3_SVM_REV3_CPU, V3_VMX_CP
 struct guest_info;
 
 /* This will contain function pointers that provide OS services */
-struct vmm_os_hooks {
+struct v3_os_hooks {
   void (*print_info)(const char * format, ...);
+  //   __attribute__ ((format (printf, 1, 2)));
   void (*print_debug)(const char * format, ...);
+  //   __attribute__ ((format (printf, 1, 2)));
   void (*print_trace)(const char * format, ...);
+  //   __attribute__ ((format (printf, 1, 2)));
   
   void *(*allocate_pages)(int numPages);
   void (*free_page)(void * page);
@@ -212,18 +234,23 @@ struct vmm_os_hooks {
   int (*ack_irq)(int irq);
 
 
-  unsigned int (*get_cpu_khz)();
+  unsigned int (*get_cpu_khz)(void);
 
 
-  void (*start_kernel_thread)(); // include pointer to function
+  void (*start_kernel_thread)(void); // include pointer to function
 
-  void (*yield_cpu)();
+  void (*yield_cpu)(void);
 
 };
 
 
 struct v3_vm_config {
-  void * vm_kernel;
+  void * rombios;
+  int rombios_size;
+
+  void * vgabios;
+  int vgabios_size;
+
   int use_ramdisk;
   void * ramdisk;
   int ramdisk_size;
@@ -232,15 +259,15 @@ struct v3_vm_config {
 
 
 /* This will contain Function pointers that control the VMs */
-struct vmm_ctrl_ops {
-  struct guest_info *(*allocate_guest)();
+struct v3_ctrl_ops {
+  struct guest_info *(*allocate_guest)(void);
 
   int (*config_guest)(struct guest_info * info, struct v3_vm_config * config_ptr);
   int (*init_guest)(struct guest_info * info);
   int (*start_guest)(struct guest_info * info);
   //  int (*stop_vm)(uint_t vm_id);
 
-  int (*has_nested_paging)();
+  int (*has_nested_paging)(void);
 
   //  v3_cpu_arch_t (*get_cpu_arch)();
 };
@@ -263,10 +290,10 @@ struct v3_interrupt {
 
 
 
-void Init_V3(struct vmm_os_hooks * hooks, struct vmm_ctrl_ops * vmm_ops);
+void Init_V3(struct v3_os_hooks * hooks, struct v3_ctrl_ops * vmm_ops);
 
 int v3_deliver_irq(struct guest_info * vm, struct v3_interrupt * intr);
-
+int v3_deliver_keyboard_evt(struct guest_info * vm);
 
 
 #endif
index 5e4ed96..328a221 100644 (file)
@@ -29,7 +29,7 @@
 
 
 
-int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr);
+int v3_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr);
 
 
 #endif // ! __V3VEE__
index c6eb1fe..1633217 100644 (file)
@@ -200,11 +200,11 @@ static const uchar_t mov_from_cr_byte = 0x20;
 */
 
 
-int handle_cr0_write(struct guest_info * info);
-int handle_cr0_read(struct guest_info * info);
+int v3_handle_cr0_write(struct guest_info * info);
+int v3_handle_cr0_read(struct guest_info * info);
 
-int handle_cr3_write(struct guest_info * info);
-int handle_cr3_read(struct guest_info * info);
+int v3_handle_cr3_write(struct guest_info * info);
+int v3_handle_cr3_read(struct guest_info * info);
 
 
 #endif // ! __V3VEE__
index ec52d09..6b8715e 100644 (file)
 #include <palacios/vmm.h>
 
 
-typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} operand_type_t;
+typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} v3_operand_type_t;
 
 struct x86_operand {
   addr_t operand;
   uint_t size;
-  operand_type_t type;
+  v3_operand_type_t type;
 };
 
 struct x86_prefixes {
@@ -87,7 +87,7 @@ struct basic_instr_info {
 /* 
  * Initializes a decoder
  */
-int init_decoder();
+int v3_init_decoder();
 
 /* 
  * Decodes an instruction 
@@ -118,7 +118,7 @@ int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic
 
 
 /* Removes a rep prefix in place */
-void strip_rep_prefix(uchar_t * instr, int length);
+void v3_strip_rep_prefix(uchar_t * instr, int length);
 
 
 
@@ -208,7 +208,7 @@ MAKE_INSTR(SMSW,   3, 0x0f, 0x01, 0x00);
 #define PREFIX_OP_SIZE      0x66
 #define PREFIX_ADDR_SIZE    0x67
 
-int opcode_cmp(const uchar_t * op1, const uchar_t * op2);
+int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2);
 
 
 static inline int is_prefix_byte(uchar_t byte) {
@@ -331,7 +331,7 @@ static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_s
 
 
 
-static inline operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output
+static inline v3_operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output
                                               char * modrm_instr,       // input
                                               int * offset,             // output
                                               addr_t * first_operand,   // output
@@ -341,7 +341,7 @@ static inline operand_type_t decode_operands16(struct v3_gprs * gprs, // input/o
   struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr;
   addr_t base_addr = 0;
   modrm_mode_t mod_mode = 0;
-  operand_type_t addr_type = INVALID_OPERAND;
+  v3_operand_type_t addr_type = INVALID_OPERAND;
   char * instr_cursor = modrm_instr;
 
   //  PrintDebug("ModRM mod=%d\n", modrm->mod);
@@ -420,7 +420,7 @@ static inline operand_type_t decode_operands16(struct v3_gprs * gprs, // input/o
 
 
 
-static inline operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output
+static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output
                                               uchar_t * modrm_instr,       // input
                                               int * offset,             // output
                                               addr_t * first_operand,   // output
@@ -432,7 +432,7 @@ static inline operand_type_t decode_operands32(struct v3_gprs * gprs, // input/o
   addr_t base_addr = 0;
   modrm_mode_t mod_mode = 0;
   uint_t has_sib_byte = 0;
-  operand_type_t addr_type = INVALID_OPERAND;
+  v3_operand_type_t addr_type = INVALID_OPERAND;
 
 
 
index b8d773e..11d64ec 100644 (file)
@@ -85,8 +85,8 @@ struct dev_mem_hook {
 };
 
 
-int dev_mgr_init(struct guest_info * info);
-int dev_mgr_deinit(struct guest_info * info);
+int v3_init_dev_mgr(struct guest_info * info);
+int v3_dev_mgr_deinit(struct guest_info * info);
 
 void PrintDebugDevMgr(struct guest_info * info);
 void PrintDebugDev(struct vm_device * dev);
index e396474..45cfa44 100644 (file)
@@ -73,7 +73,7 @@ struct emulation_state {
 };
 
 
-int init_emulator(struct guest_info * info);
+int v3_init_emulator(struct guest_info * info);
 
 
 int v3_emulation_exit_handler(struct guest_info * info);
diff --git a/palacios/include/palacios/vmm_host_events.h b/palacios/include/palacios/vmm_host_events.h
new file mode 100644 (file)
index 0000000..dfe4775
--- /dev/null
@@ -0,0 +1,89 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __VMM_HOST_EVENTS_H__
+#define __VMM_HOST_EVENTS_H__
+
+
+struct v3_keyboard_event {
+  unsigned char status;
+  unsigned char scan_code;
+};
+
+struct v3_mouse_event {
+  unsigned char data[3];
+};
+
+struct v3_timer_event {
+  unsigned int period_us;
+};
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_list.h>
+
+
+typedef enum {HOST_KEYBOARD_EVT, 
+             HOST_MOUSE_EVT, 
+             HOST_TIMER_EVT} v3_host_evt_type_t;
+
+
+union v3_host_event_handler {
+  int (*keyboard_handler)(struct guest_info * info, struct v3_keyboard_event * evt, void * priv_data);
+  int (*mouse_handler)(struct guest_info * info, struct v3_mouse_event * evt, void * priv_data);
+  int (*timer_handler)(struct guest_info * info, struct v3_timer_event * evt, void * priv_data);
+};
+
+
+struct v3_host_event_hook {
+  union v3_host_event_handler cb;
+  void * private_data;
+  struct list_head link;
+};
+
+
+
+struct v3_host_events {
+  struct list_head keyboard_events;
+  struct list_head mouse_events;
+  struct list_head timer_events;
+};
+
+
+
+int v3_init_host_events(struct guest_info * info);
+
+#define V3_HOST_EVENT_HANDLER(cb) ((union v3_host_event_handler)cb)
+
+int v3_hook_host_event(struct guest_info * info, 
+                      v3_host_evt_type_t event_type, 
+                      union v3_host_event_handler cb, 
+                      void * private_data);
+
+#endif // ! __V3VEE__
+
+
+
+int v3_deliver_keyboard_event(struct guest_info * info, struct v3_keyboard_event * evt);
+int v3_deliver_mouse_event(struct guest_info * info, struct v3_mouse_event * evt);
+int v3_deliver_timer_event(struct guest_info * info, struct v3_timer_event * evt);
+
+
+
+#endif
index d4543fd..fd83edb 100644 (file)
@@ -84,16 +84,13 @@ struct v3_intr_state {
 
 
 
-void init_interrupt_state(struct guest_info * info);
+void v3_init_interrupt_state(struct guest_info * info);
 
 
 int v3_raise_irq(struct guest_info * info, int irq);
-
-/*Zheng 07/30/2008*/
 int v3_lower_irq(struct guest_info * info, int irq);
 
 
-/*Zheng 07/30/2008*/
 
 struct intr_ctrl_ops {
   int (*intr_pending)(void * private_data);
@@ -106,16 +103,16 @@ struct intr_ctrl_ops {
 
 
 
-void set_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * state);
+void v3_set_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * state);
 
 int v3_raise_exception(struct guest_info * info, uint_t excp);
 int v3_raise_exception_with_error(struct guest_info * info, uint_t excp, uint_t error_code);
 
-int intr_pending(struct guest_info * info);
-uint_t get_intr_number(struct guest_info * info);
-intr_type_t get_intr_type(struct guest_info * info);
+int v3_intr_pending(struct guest_info * info);
+uint_t v3_get_intr_number(struct guest_info * info);
+intr_type_t v3_get_intr_type(struct guest_info * info);
 
-int injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type);
+int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type);
 
 /*
 int start_irq(struct vm_intr * intr);
index 242554b..9bfc197 100644 (file)
@@ -52,7 +52,7 @@ struct vmm_io_map {
 };
 
 
-void init_vmm_io_map(struct guest_info * info);
+void v3_init_vmm_io_map(struct guest_info * info);
 
 // FOREACH_IO_HOOK(vmm_io_map_t * io_map, vmm_io_hook_t * io_hook)
 #define FOREACH_IO_HOOK(io_map, io_hook) for (io_hook = (io_map).head; io_hook != NULL; io_hook = (io_hook)->next)
@@ -78,7 +78,7 @@ struct vmm_io_hook {
 struct vmm_io_hook * v3_get_io_hook(struct vmm_io_map * io_map, uint_t port);
 
 
-void PrintDebugIOMap(struct vmm_io_map * io_map);
+void v3_print_io_map(struct vmm_io_map * io_map);
 
 
 
index d66d4c7..0d8747e 100644 (file)
@@ -19,7 +19,7 @@
         (type *)( (char *)__mptr - offsetof(type,member) );})
 
 
-static inline void prefetch(const void *x) {;}
+static inline void prefetch(const void *x) {const void * foo; foo = x;}
 
 /*
  * These are non-NULL pointers that will result in page faults
diff --git a/palacios/include/palacios/vmm_lowlevel.h b/palacios/include/palacios/vmm_lowlevel.h
new file mode 100644 (file)
index 0000000..ea32b23
--- /dev/null
@@ -0,0 +1,83 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_types.h>
+
+
+#ifdef __V3_32BIT__
+
+void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) {
+  __asm__ __volatile__ (
+                       "pushl %%ebx\n\t"
+                       "cpuid\n\t"
+                       "movl %%ebx, %%esi\n\t"
+                       "popl %%ebx\n\t"
+                       : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
+                       : "a" (target)
+                       );
+  return;
+}
+
+#elif __V3_64BIT__
+
+void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) {
+  __asm__ __volatile__ (
+                       "pushq %%rbx\n\t"
+                       "cpuid\n\t"
+                       "movq %%rbx, %%rsi\n\t"
+                       "popq %%rbx\n\t"
+                       : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
+                       : "a" (target)
+                       );
+  return;
+}
+
+#endif
+
+
+void __inline__ v3_set_msr(uint_t msr, uint_t high_byte, uint_t low_byte) {
+  __asm__ __volatile__ (
+                       "wrmsr"
+                       : 
+                       : "c" (msr), "d" (high_byte), "a" (low_byte)
+                       );
+
+
+}
+
+
+
+void __inline__ v3_get_msr(uint_t msr, uint_t * high_byte, uint_t * low_byte) {
+  __asm__ __volatile__ (
+                       "rdmsr"
+                       : "=d" (*high_byte), "=a" (*low_byte) 
+                       : "c" (msr)
+                       );
+}
+
+
+
+void __inline__ v3_enable_ints() {
+  __asm__ __volatile__ ("sti");
+}
+
+void __inline__ v3_disable_ints() {
+  __asm__ __volatile__ ("cli");
+}
+
index 5351b36..313afc7 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 
-#ifndef __VMM_PAGING_H
-#define __VMM_PAGING_H
+#ifndef __VMM_PAGING_H__
+#define __VMM_PAGING_H__
 
 
 #ifdef __V3VEE__
@@ -110,6 +110,12 @@ the host state in the vmcs before entering the guest.
 #define PT32_BASE_ADDR(x) (((uint_t)x) >> 12)
 #define PD32_4MB_BASE_ADDR(x) (((uint_t)x) >> 22)
 
+
+#define PML4E64_BASE_ADDR(x) (((ullong_t)x) >> 12)
+#define PDPE64_BASE_ADDR(x) (((ullong_t)x) >> 12)
+#define PDE64_BASE_ADDR(x) (((ullong_t)x) >> 12)
+#define PTE64_BASE_ADDR(x) (((ullong_t)x) >> 12)
+
 #define PT32_PAGE_ADDR(x)   (((uint_t)x) & 0xfffff000)
 #define PT32_PAGE_OFFSET(x) (((uint_t)x) & 0xfff)
 #define PT32_PAGE_POWER 12
@@ -129,9 +135,9 @@ the host state in the vmcs before entering the guest.
 
 
 
-#define CR3_TO_PDE32(cr3) (((ulong_t)cr3) & 0xfffff000)
-#define CR3_TO_PDPTRE(cr3) (((ulong_t)cr3) & 0xffffffe0)
-#define CR3_TO_PML4E64(cr3)  (((ullong_t)cr3) & 0x000ffffffffff000LL)
+#define CR3_TO_PDE32(cr3) (V3_VAddr((void *)(((ulong_t)cr3) & 0xfffff000)))
+#define CR3_TO_PDPTRE(cr3) (V3_VAddr((void *)(((ulong_t)cr3) & 0xffffffe0)))
+#define CR3_TO_PML4E64(cr3)  (V3_VAddr((void *)(((ullong_t)cr3) & 0x000ffffffffff000LL)))
 
 
 
@@ -146,7 +152,7 @@ the host state in the vmcs before entering the guest.
 #define PT32_GUEST_PT 0x2
 
 
-#endif
+
 
 /* PDE 32 bit PAGE STRUCTURES */
 typedef enum {PDE32_ENTRY_NOT_PRESENT, PDE32_ENTRY_PTE32, PDE32_ENTRY_LARGE_PAGE} pde32_entry_type_t;
@@ -211,15 +217,14 @@ typedef struct pte32 {
 typedef struct pml4e64 {
   uint_t present        : 1;
   uint_t writable       : 1;
-  uint_t user           : 1;
-  uint_t pwt            : 1;
-  uint_t pcd            : 1;
+  uint_t user_page           : 1;
+  uint_t write_through  : 1;
+  uint_t cache_disable  : 1;
   uint_t accessed       : 1;
   uint_t reserved       : 1;
   uint_t zero           : 2;
   uint_t vmm_info       : 3;
-  uint_t pdp_base_addr_lo : 20;
-  uint_t pdp_base_addr_hi : 20;
+  ullong_t pdp_base_addr : 40;
   uint_t available      : 11;
   uint_t no_execute     : 1;
 } pml4e64_t;
@@ -228,16 +233,15 @@ typedef struct pml4e64 {
 typedef struct pdpe64 {
   uint_t present        : 1;
   uint_t writable       : 1;
-  uint_t user           : 1;
-  uint_t pwt            : 1;
-  uint_t pcd            : 1;
+  uint_t user_page           : 1;
+  uint_t write_through  : 1;
+  uint_t cache_disable  : 1;
   uint_t accessed       : 1;
   uint_t reserved       : 1;
-  uint_t large_pages    : 1;
+  uint_t large_page    : 1;
   uint_t zero           : 1;
   uint_t vmm_info       : 3;
-  uint_t pd_base_addr_lo : 20;
-  uint_t pd_base_addr_hi : 20;
+  ullong_t pd_base_addr : 40;
   uint_t available      : 11;
   uint_t no_execute     : 1;
 } pdpe64_t;
@@ -247,28 +251,32 @@ typedef struct pdpe64 {
 
 typedef struct pde64 {
   uint_t present         : 1;
-  uint_t flags           : 4;
+  uint_t writable        : 1;
+  uint_t user_page       : 1;
+  uint_t write_through   : 1;
+  uint_t cache_disable   : 1;
   uint_t accessed        : 1;
   uint_t reserved        : 1;
-  uint_t large_pages     : 1;
+  uint_t large_page     : 1;
   uint_t reserved2       : 1;
   uint_t vmm_info        : 3;
-  uint_t pt_base_addr_lo    : 20;
-  uint_t pt_base_addr_hi : 20;
+  ullong_t pt_base_addr  : 40;
   uint_t available       : 11;
   uint_t no_execute      : 1;
 } pde64_t;
 
 typedef struct pte64 {
   uint_t present         : 1;
-  uint_t flags           : 4;
+  uint_t writable        : 1;
+  uint_t user_page       : 1;
+  uint_t write_through   : 1;
+  uint_t cache_disable   : 1;
   uint_t accessed        : 1;
   uint_t dirty           : 1;
   uint_t pte_attr        : 1;
   uint_t global_page     : 1;
   uint_t vmm_info        : 3;
-  uint_t page_base_addr_lo  : 20;
-  uint_t page_base_addr_hi : 20;
+  ullong_t page_base_addr : 40;
   uint_t available       : 11;
   uint_t no_execute      : 1;
 } pte64_t;
@@ -284,8 +292,6 @@ typedef struct pf_error_code {
   uint_t rsvd              : 27;
 } pf_error_t;
 
-typedef enum { PDE32 } paging_mode_t;
-
 
 
 
@@ -310,8 +316,8 @@ pt_access_status_t can_access_pte32(pte32_t * pte, addr_t addr, pf_error_t acces
 
 struct guest_info;
 
-pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info);
-
+pde32_t * create_passthrough_pts_32(struct guest_info * guest_info);
+pml4e64_t * create_passthrough_pts_64(struct guest_info * info);
 
 
 
@@ -320,13 +326,13 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info);
 void PrintDebugPageTables(pde32_t * pde);
 
 
-#ifdef __V3VEE__
 
 
 void PrintPT32(addr_t starting_address, pte32_t * pte);
 void PrintPD32(pde32_t * pde);
 void PrintPTE32(addr_t virtual_address, pte32_t * pte);
 void PrintPDE32(addr_t virtual_address, pde32_t * pde);
+void PrintPTE64(addr_t virtual_address, pte64_t * pte);
 
 #endif // !__V3VEE__
 
index f7424e8..cb04d7d 100644 (file)
@@ -17,8 +17,8 @@
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __VMM_SHADOW_PAGING_H
-#define __VMM_SHADOW_PAGING_H
+#ifndef __VMM_SHADOW_PAGING_H__
+#define __VMM_SHADOW_PAGING_H__
 
 
 #ifdef __V3VEE__
 #include <palacios/vmm_paging.h>
 #include <palacios/vmm_hashtable.h>
 
+
 struct shadow_page_state {
 
   // these two reflect the top-level page directory
   // of the guest page table
-  paging_mode_t           guest_mode;
-  ullong_t                guest_cr3;         // points to guest's current page table
+  v3_reg_t                guest_cr3;         // points to guest's current page table
 
   // Should this be here??
-  ullong_t guest_cr0;
+  v3_reg_t guest_cr0;
 
   // these two reflect the top-level page directory 
   // of the shadow page table
-  paging_mode_t           shadow_mode;
-  ullong_t                shadow_cr3;
+  v3_reg_t                shadow_cr3;
 
 
   // Hash table that ties a CR3 value to a hash table pointer for the PT entries
@@ -57,19 +56,19 @@ struct guest_info;
 
 
 
-int cache_page_tables32(struct guest_info * info, addr_t  pde);
+int v3_cache_page_tables32(struct guest_info * info, addr_t  pde);
 
-int init_shadow_page_state(struct guest_info * info);
+int v3_init_shadow_page_state(struct guest_info * info);
 
-addr_t create_new_shadow_pt32();
+addr_t v3_create_new_shadow_pt32();
 
-int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
-int handle_shadow_invlpg(struct guest_info * info);
+int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
+int v3_handle_shadow_invlpg(struct guest_info * info);
 
 
 
 
-int v3_replace_shdw_page(struct guest_info * info, addr_t location, void * new_page, void* old_page);
+int v3_replace_shdw_page(struct guest_info * info, addr_t location, void * new_page, void * old_page);
 int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page); 
 
 #endif // ! __V3VEE__
index 11e4eb9..5e9a1f3 100644 (file)
@@ -68,11 +68,9 @@ int v3_remove_timer(struct guest_info * info, struct vm_timer * timer);
 
 void v3_update_time(struct guest_info * info, ullong_t cycles);
 
-#endif // !__V3VEE__
-
 
 void v3_init_time(struct guest_info * info);
 
-
+#endif // !__V3VEE__
 
 #endif
index 96e5642..ef9e498 100644 (file)
@@ -62,7 +62,7 @@ typedef unsigned char uint8_t;
 typedef char sint8_t;
 
 typedef ulong_t addr_t;
-
+typedef ullong_t v3_reg_t;
 #endif // ! __V3VEE__
 
 #endif
diff --git a/palacios/lib/xed/libxed32e.a b/palacios/lib/xed/libxed32e.a
new file mode 100644 (file)
index 0000000..9bced9e
Binary files /dev/null and b/palacios/lib/xed/libxed32e.a differ
index d55f7b8..5748d85 100644 (file)
@@ -43,13 +43,13 @@ static struct vm_device_ops dev_ops = {
   .stop = NULL,
 };
 
-struct vm_device * create_dma() {
+struct vm_device * v3_create_dma() {
   struct dma_state * dma = NULL;
 
   dma = (struct dma_state *)V3_Malloc(sizeof(struct dma_state));
   V3_ASSERT(dma != NULL);
 
-  struct vm_device * dev = create_device("DMA", &dev_ops, dma);
+  struct vm_device * dev = v3_create_device("DMA", &dev_ops, dma);
 
   return dma;
 }
index 7757691..7a81595 100644 (file)
@@ -566,10 +566,10 @@ static int pit_init(struct vm_device * dev) {
   uint_t cpu_khz = V3_CPU_KHZ();
   ullong_t reload_val = (ullong_t)cpu_khz * 1000;
 
-  dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
-  dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
-  dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
-  dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
+  v3_dev_hook_io(dev, CHANNEL0_PORT, &pit_read_channel, &pit_write_channel);
+  v3_dev_hook_io(dev, CHANNEL1_PORT, &pit_read_channel, &pit_write_channel);
+  v3_dev_hook_io(dev, CHANNEL2_PORT, &pit_read_channel, &pit_write_channel);
+  v3_dev_hook_io(dev, COMMAND_PORT, NULL, &pit_write_command);
 
 #ifdef DEBUG_PIT
   PrintDebug("8254 PIT: OSC_HZ=%d, reload_val=", OSC_HZ);
@@ -616,12 +616,12 @@ static struct vm_device_ops dev_ops = {
 };
 
 
-struct vm_device * create_pit() {
+struct vm_device * v3_create_pit() {
   struct pit * pit_state = NULL;
   pit_state = (struct pit *)V3_Malloc(sizeof(struct pit));
   V3_ASSERT(pit_state != NULL);
 
-  struct vm_device * dev = create_device("PIT", &dev_ops, pit_state);
+  struct vm_device * dev = v3_create_device("PIT", &dev_ops, pit_state);
   
   return dev;
 }
index b14bfe5..f13dc1d 100644 (file)
@@ -203,22 +203,20 @@ static int pic_raise_intr(void * private_data, int irq) {
 }
 
 
-/*Zheng 07/30/2008*/
-
-static int pic_lower_intr(void *private_data, int irq_no) {
+static int pic_lower_intr(void *private_data, int irq) {
 
   struct pic_internal *state = (struct pic_internal*)private_data;
 
-  PrintDebug("[pic_lower_intr] IRQ line %d now low\n", (unsigned) irq_no);
-  if (irq_no <= 7) {
+  PrintDebug("[pic_lower_intr] IRQ line %d now low\n", irq);
+  if (irq <= 7) {
 
-    state->master_irr &= ~(1 << irq_no);
+    state->master_irr &= ~(1 << irq);
     if ((state->master_irr & ~(state->master_imr)) == 0) {
       PrintDebug("\t\tFIXME: Master maybe should do sth\n");
     }
-  } else if ((irq_no > 7) && (irq_no <= 15)) {
+  } else if ((irq > 7) && (irq < 16)) {
 
-    state->slave_irr &= ~(1 << (irq_no - 8));
+    state->slave_irr &= ~(1 << (irq - 8));
     if ((state->slave_irr & (~(state->slave_imr))) == 0) {
       PrintDebug("\t\tFIXME: Slave maybe should do sth\n");
     }
@@ -316,20 +314,20 @@ static int pic_end_irq(void * private_data, int irq) {
 */
 
 
-/*Zheng 07/30/2008*/
+
 static struct intr_ctrl_ops intr_ops = {
   .intr_pending = pic_intr_pending,
   .get_intr_number = pic_get_intr_number,
   .raise_intr = pic_raise_intr,
   .begin_irq = pic_begin_irq,
-  .lower_intr = pic_lower_intr, //Zheng added
+  .lower_intr = pic_lower_intr, 
 
 };
 
 
 
 
-int read_master_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_master_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
 
   if (length != 1) {
@@ -348,7 +346,7 @@ int read_master_port1(ushort_t port, void * dst, uint_t length, struct vm_device
   return 1;
 }
 
-int read_master_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_master_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
 
   if (length != 1) {
@@ -362,7 +360,7 @@ int read_master_port2(ushort_t port, void * dst, uint_t length, struct vm_device
   
 }
 
-int read_slave_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_slave_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
 
   if (length != 1) {
@@ -381,7 +379,7 @@ int read_slave_port1(ushort_t port, void * dst, uint_t length, struct vm_device
   return 1;
 }
 
-int read_slave_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_slave_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
 
   if (length != 1) {
@@ -395,7 +393,7 @@ int read_slave_port2(ushort_t port, void * dst, uint_t length, struct vm_device
 }
 
 
-int write_master_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_master_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
   uchar_t cw = *(uchar_t *)src;
 
@@ -457,7 +455,7 @@ int write_master_port1(ushort_t port, void * src, uint_t length, struct vm_devic
   return 1;
 }
 
-int write_master_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_master_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
     struct pic_internal * state = (struct pic_internal*)dev->private_data;
     uchar_t cw = *(uchar_t *)src;    
 
@@ -511,7 +509,7 @@ int write_master_port2(ushort_t port, void * src, uint_t length, struct vm_devic
     return 1;
 }
 
-int write_slave_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_slave_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
   uchar_t cw = *(uchar_t *)src;
 
@@ -570,7 +568,7 @@ int write_slave_port1(ushort_t port, void * src, uint_t length, struct vm_device
   return 1;
 }
 
-int write_slave_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_slave_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
     struct pic_internal * state = (struct pic_internal*)dev->private_data;
     uchar_t cw = *(uchar_t *)src;    
 
@@ -631,10 +629,10 @@ int write_slave_port2(ushort_t port, void * src, uint_t length, struct vm_device
 
 
 
-int pic_init(struct vm_device * dev) {
+static int pic_init(struct vm_device * dev) {
   struct pic_internal * state = (struct pic_internal*)dev->private_data;
 
-  set_intr_controller(dev->vm, &intr_ops, state);
+  v3_set_intr_controller(dev->vm, &intr_ops, state);
 
   state->master_irr = 0;
   state->master_isr = 0;
@@ -660,20 +658,20 @@ int pic_init(struct vm_device * dev) {
   state->slave_state = ICW1;
 
 
-  dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
-  dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
-  dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
-  dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
+  v3_dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1);
+  v3_dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2);
+  v3_dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1);
+  v3_dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2);
 
   return 0;
 }
 
 
-int pic_deinit(struct vm_device * dev) {
-  dev_unhook_io(dev, MASTER_PORT1);
-  dev_unhook_io(dev, MASTER_PORT2);
-  dev_unhook_io(dev, SLAVE_PORT1);
-  dev_unhook_io(dev, SLAVE_PORT2);
+static int pic_deinit(struct vm_device * dev) {
+  v3_dev_unhook_io(dev, MASTER_PORT1);
+  v3_dev_unhook_io(dev, MASTER_PORT2);
+  v3_dev_unhook_io(dev, SLAVE_PORT1);
+  v3_dev_unhook_io(dev, SLAVE_PORT2);
 
   return 0;
 }
@@ -693,12 +691,12 @@ static struct vm_device_ops dev_ops = {
 };
 
 
-struct vm_device * create_pic() {
+struct vm_device * v3_create_pic() {
   struct pic_internal * state = NULL;
   state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
   V3_ASSERT(state != NULL);
 
-  struct vm_device *device = create_device("8259A", &dev_ops, state);
+  struct vm_device *device = v3_create_device("8259A", &dev_ops, state);
 
   return device;
 }
diff --git a/palacios/src/devices/bochs_debug.c b/palacios/src/devices/bochs_debug.c
new file mode 100644 (file)
index 0000000..45bc751
--- /dev/null
@@ -0,0 +1,144 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#include <devices/bochs_debug.h>
+#include <palacios/vmm.h>
+
+#define BUF_SIZE 1024
+
+#define BOCHS_PORT1 0x400
+#define BOCHS_PORT2 0x401
+#define BOCHS_INFO_PORT 0x402
+#define BOCHS_DEBUG_PORT 0x403
+
+
+
+struct debug_state {
+  char debug_buf[BUF_SIZE];
+  uint_t debug_offset;
+
+  char info_buf[BUF_SIZE];
+  uint_t info_offset;
+};
+
+static int handle_info_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+  struct debug_state * state = (struct debug_state *)dev->private_data;
+
+  state->info_buf[state->info_offset++] = *(char*)src;
+
+  if ((*(char*)src == 0xa) ||  (state->info_offset == (BUF_SIZE - 1))) {
+    PrintDebug("BOCHSINFO>%s", state->info_buf);
+    memset(state->info_buf, 0, BUF_SIZE);
+    state->info_offset = 0;
+  }
+
+  return length;
+}
+
+
+static int handle_debug_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+  struct debug_state * state = (struct debug_state *)dev->private_data;
+
+  state->debug_buf[state->debug_offset++] = *(char*)src;
+
+  if ((*(char*)src == 0xa) ||  (state->debug_offset == (BUF_SIZE - 1))) {
+    PrintDebug("BOCHSDEBUG>%s", state->debug_buf);
+    memset(state->debug_buf, 0, BUF_SIZE);
+    state->debug_offset = 0;
+  }
+
+  return length;
+}
+
+
+static int handle_gen_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+
+  switch (length) {
+  case 1:
+    PrintDebug(">0x%.2x\n", *(uchar_t*)src);
+    break;
+  case 2:
+    PrintDebug(">0x%.4x\n", *(ushort_t*)src);
+    break;
+  case 4:
+    PrintDebug(">0x%.8x\n", *(uint_t*)src);
+    break;
+  default:
+    PrintError("Invalid length in handle_gen_write\n");
+    return -1;
+    break;
+  }
+
+  return length;
+}
+
+
+static int debug_init(struct vm_device * dev) {
+  struct debug_state * state = (struct debug_state *)dev->private_data;
+
+  state->debug_offset = 0;
+  state->info_offset = 0;
+  memset(state->debug_buf, 0, BUF_SIZE);
+  memset(state->info_buf, 0, BUF_SIZE);
+
+
+  v3_dev_hook_io(dev, BOCHS_PORT1,  NULL, &handle_gen_write);
+  v3_dev_hook_io(dev, BOCHS_PORT2, NULL, &handle_gen_write);
+  v3_dev_hook_io(dev, BOCHS_INFO_PORT, NULL, &handle_info_write);
+  v3_dev_hook_io(dev, BOCHS_DEBUG_PORT, NULL, &handle_debug_write);
+  
+  return 0;
+}
+
+static int debug_deinit(struct vm_device * dev) {
+  v3_dev_unhook_io(dev, BOCHS_PORT1);
+  v3_dev_unhook_io(dev, BOCHS_PORT2);
+  v3_dev_unhook_io(dev, BOCHS_INFO_PORT);
+  v3_dev_unhook_io(dev, BOCHS_DEBUG_PORT);
+
+  return 0;
+};
+
+
+
+
+static struct vm_device_ops dev_ops = {
+  .init = debug_init,
+  .deinit = debug_deinit,
+  .reset = NULL,
+  .start = NULL,
+  .stop = NULL,
+};
+
+
+struct vm_device * v3_create_bochs_debug() {
+  struct debug_state * state = NULL;
+
+  state = (struct debug_state *)V3_Malloc(sizeof(struct debug_state));
+
+  V3_ASSERT(state != NULL);
+
+  PrintDebug("Creating Bochs Debug Device\n");
+  struct vm_device * device = v3_create_device("BOCHS Debug", &dev_ops, state);
+
+
+
+  return device;
+}
index 40ed98c..ff1c55c 100644 (file)
@@ -168,13 +168,13 @@ struct vm_device *  v3_create_cdrom(struct vm_device * ramdisk_dev, void * ramdi
 
   memset(cd, 0, sizeof(struct cdrom_state));
 
-  cd->image_addr = (uchar_t *)ramdisk;
+  cd->image_addr = (uchar_t *)V3_VAddr(ramdisk);
   cd->capacity_in_bytes = ramdisk_size;
   cd->ide_dev = ramdisk_dev;
   
   PrintDebug("Creating RamDISK CDROM\n");
 
-  struct vm_device * cd_dev = create_device("Ram Based CD", &dev_ops, cd);
+  struct vm_device * cd_dev = v3_create_device("Ram Based CD", &dev_ops, cd);
 
   return cd_dev;
 }
index 3cdc298..130c708 100644 (file)
@@ -70,27 +70,22 @@ struct irq_range {
 
 
 
-int generic_reset_device(struct vm_device * dev)
-{
+static int generic_reset_device(struct vm_device * dev) {
   PrintDebug("generic: reset device\n");
   return 0;
-
 }
 
 
 
 
 
-int generic_start_device(struct vm_device * dev)
-{
+static int generic_start_device(struct vm_device * dev) {
   PrintDebug("generic: start device\n");
   return 0;
 }
 
 
-int generic_stop_device(struct vm_device * dev)
-{
+static int generic_stop_device(struct vm_device * dev) {
   PrintDebug("generic: stop device\n");
   return 0;
 }
@@ -98,11 +93,10 @@ int generic_stop_device(struct vm_device * dev)
 
 
 
-int generic_write_port_passthrough(ushort_t port,
-                                  void * src, 
-                                  uint_t length,
-                                  struct vm_device * dev)
-{
+static int generic_write_port_passthrough(ushort_t port,
+                                         void * src, 
+                                         uint_t length,
+                                         struct vm_device * dev) {
   uint_t i;
 
   PrintDebug("generic: writing 0x");
@@ -136,11 +130,10 @@ int generic_write_port_passthrough(ushort_t port,
   return length;
 }
 
-int generic_read_port_passthrough(ushort_t port,
-                                 void * src, 
-                                 uint_t length,
-                                 struct vm_device * dev)
-{
+static int generic_read_port_passthrough(ushort_t port,
+                                        void * src, 
+                                        uint_t length,
+                                        struct vm_device * dev) {
   uint_t i;
 
   PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
@@ -173,11 +166,10 @@ int generic_read_port_passthrough(ushort_t port,
   return length;
 }
 
-int generic_write_port_ignore(ushort_t port,
-                             void * src, 
-                             uint_t length,
-                             struct vm_device * dev)
-{
+static int generic_write_port_ignore(ushort_t port,
+                                    void * src, 
+                                    uint_t length,
+                                    struct vm_device * dev) {
   uint_t i;
 
   PrintDebug("generic: writing 0x");
@@ -191,11 +183,10 @@ int generic_write_port_ignore(ushort_t port,
   return length;
 }
 
-int generic_read_port_ignore(ushort_t port,
-                            void * src, 
-                            uint_t length,
-                            struct vm_device * dev)
-{
+static int generic_read_port_ignore(ushort_t port,
+                                   void * src, 
+                                   uint_t length,
+                                   struct vm_device * dev) {
 
   PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
 
@@ -207,16 +198,16 @@ int generic_read_port_ignore(ushort_t port,
 
 
 
-int generic_interrupt(uint_t irq, struct vm_device * dev) {
+static int generic_interrupt(uint_t irq, struct vm_device * dev) {
   PrintDebug("generic: interrupt 0x%x - injecting into VM\n", irq);
 
-  dev->vm->vm_ops.raise_irq(dev->vm, irq);
+  v3_raise_irq(dev->vm, irq);
 
   return 0;
 }
 
 
-int generic_init_device(struct vm_device * dev) {
+static int generic_init_device(struct vm_device * dev) {
   struct generic_internal * state = (struct generic_internal *)(dev->private_data);
 
   PrintDebug("generic: init_device\n");
@@ -236,13 +227,13 @@ int generic_init_device(struct vm_device * dev) {
       for (i = tmp->start; i <= tmp->end; i++) { 
        if (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) { 
          
-         if (dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough)) { 
+         if (v3_dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough)) { 
            PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
          }
          
        } else if (tmp->type == GENERIC_PRINT_AND_IGNORE) { 
          
-         if (dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore)) { 
+         if (v3_dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore)) { 
            PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
          }
        } 
@@ -264,7 +255,7 @@ int generic_init_device(struct vm_device * dev) {
                 tmp->start, tmp->end); 
       
       
-      if (dev_hook_mem(dev, tmp->start, tmp->end)) {
+      if (v3_dev_hook_mem(dev, tmp->start, tmp->end)) {
        PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
                   tmp->start, tmp->end); 
       }
@@ -286,7 +277,7 @@ int generic_init_device(struct vm_device * dev) {
                 tmp->start, tmp->end);
       
       for (i = tmp->start; i <= tmp->end; i++) { 
-       if (dev_hook_irq(dev, i, &generic_interrupt)) { 
+       if (v3_dev_hook_irq(dev, i, &generic_interrupt)) { 
          PrintDebug("generic: can't hook irq  0x%x (already hooked?)\n", i);
        }
       }
@@ -301,7 +292,7 @@ int generic_init_device(struct vm_device * dev) {
   return 0;
 }
 
-int generic_deinit_device(struct vm_device * dev) {
+static int generic_deinit_device(struct vm_device * dev) {
   struct generic_internal * state = (struct generic_internal *)(dev->private_data);
 
 
@@ -320,7 +311,7 @@ int generic_deinit_device(struct vm_device * dev) {
       
 
       for (i = cur->start; i <= cur->end; i++) { 
-       if (dev_unhook_irq(dev, i)) {
+       if (v3_dev_unhook_irq(dev, i)) {
          PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n", i);
        }
       }
@@ -343,7 +334,7 @@ int generic_deinit_device(struct vm_device * dev) {
       PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
                 cur->start, cur->end); 
 
-      if (dev_unhook_mem(dev, cur->start, cur->end)) {
+      if (v3_dev_unhook_mem(dev, cur->start, cur->end)) {
        PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
                   cur->start, cur->end); 
       }
@@ -368,7 +359,7 @@ int generic_deinit_device(struct vm_device * dev) {
                   cur->start, cur->end);
                
       for (i = cur->start; i <= cur->end; i++) {
-       if (dev_unhook_io(dev, i)) {
+       if (v3_dev_unhook_io(dev, i)) {
          PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
        }
       }
@@ -470,7 +461,7 @@ int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, u
 
 
 
-struct vm_device * create_generic() {
+struct vm_device * v3_create_generic() {
   struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
   
   generic_state->num_port_ranges = 0;
@@ -481,7 +472,7 @@ struct vm_device * create_generic() {
   INIT_LIST_HEAD(&(generic_state->mem_list));
   INIT_LIST_HEAD(&(generic_state->irq_list));
     
-  struct vm_device * device = create_device("GENERIC", &dev_ops, generic_state);
+  struct vm_device * device = v3_create_device("GENERIC", &dev_ops, generic_state);
 
   return device;
 }
index 29485be..8f25c0c 100644 (file)
@@ -98,8 +98,6 @@
 #define MOUSE               1
 
 
-// The currently targetted keyboard
-static struct vm_device * thekeyboard = NULL;
 
 //#define QUEUE_SIZE          32
 
@@ -325,49 +323,52 @@ static int PullFromInputQueue(struct vm_device *dev, uchar_t *value)
 
 #endif
 
-static struct vm_device *demultiplex_injected_key(uchar_t status, uchar_t scancode)
-{
-  // this currently does nothing
-  return thekeyboard;
-}
 
-static struct vm_device *demultiplex_injected_mouse(uchar_t mouse_packet[3])
-{
-  // this currently does nothing
-  return thekeyboard;
+
+
+static int keyboard_interrupt(struct vm_device * dev, uint_t irq) {
+  PrintDebug("keyboard: interrupt 0x%x\n", irq);
+
+  v3_raise_irq(dev->vm, irq);
+
+  return 0;
+
 }
 
-int keyboard_interrupt(uint_t irq, struct vm_device * dev);
 
-void deliver_key_to_vmm(uchar_t status, uchar_t scancode)
-{
-  struct vm_device *dev = demultiplex_injected_key(status, scancode);
+
+static int key_event_handler(struct guest_info * info, 
+                            struct v3_keyboard_event * evt, 
+                            void * private_data) {
+  struct vm_device * dev = (struct vm_device *)private_data;
   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
-  PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", status, scancode);
+  PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
   
   if ( (state->status_byte & STATUS_ENABLED)      // onboard is enabled
        && (!(state->cmd_byte & CMD_DISABLE)) )  {   // keyboard is enabled
-
-    PushToOutputQueue(dev, scancode, OVERWRITE, DATA, KEYBOARD);
-
+    
+    PushToOutputQueue(dev, evt->scan_code, OVERWRITE, DATA, KEYBOARD);
+    
     if (state->cmd_byte & CMD_INTR) { 
-      keyboard_interrupt(KEYBOARD_IRQ, dev);
+      keyboard_interrupt(dev, KEYBOARD_IRQ);
     }
-       
   }
+  
+  return 0;
 }
 
 
-void deliver_mouse_to_vmm(uchar_t data[3])
-{
-  struct vm_device * dev = demultiplex_injected_mouse(data);
+static int mouse_event_handler(struct guest_info * info, 
+                              struct v3_mouse_event * evt, 
+                              void * private_data) {
+  struct vm_device * dev = (struct vm_device *)private_data;
   struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
 
   PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
-            data[0], data[1], data[2]);
+            evt->data[0], evt->data[1], evt->data[2]);
   
-  memcpy(state->mouse_packet, data, 3);
+  memcpy(state->mouse_packet, evt->data, 3);
   
   state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
   
@@ -377,17 +378,19 @@ void deliver_mouse_to_vmm(uchar_t data[3])
   case STREAM2:
   case STREAM3:
     if (!(state->cmd_byte & CMD_MOUSE_DISABLE)) { 
-      keyboard_interrupt(MOUSE_IRQ, dev);
+      keyboard_interrupt(dev, MOUSE_IRQ);
     }
     break;
   default:
+    return -1;
     break;
   }
 
+  return 0;
 }
 
 
-int keyboard_reset_device(struct vm_device * dev)
+static int keyboard_reset_device(struct vm_device * dev)
 {
   struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
   
@@ -422,21 +425,21 @@ int keyboard_reset_device(struct vm_device * dev)
 
 
 
-int keyboard_start_device(struct vm_device *dev)
+static int keyboard_start_device(struct vm_device *dev)
 {
   PrintDebug("keyboard: start device\n");
   return 0;
 }
 
 
-int keyboard_stop_device(struct vm_device *dev)
+static int keyboard_stop_device(struct vm_device *dev)
 {
   PrintDebug("keyboard: stop device\n");
   return 0;
 }
 
 
-int mouse_read_input(struct vm_device *dev)
+static int mouse_read_input(struct vm_device *dev)
 {
   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
@@ -556,7 +559,7 @@ int mouse_read_input(struct vm_device *dev)
   }
 }
 
-int mouse_write_output(struct vm_device * dev, uchar_t data)
+static int mouse_write_output(struct vm_device * dev, uchar_t data)
 {
   struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
 
@@ -742,7 +745,7 @@ int mouse_write_output(struct vm_device * dev, uchar_t data)
 
 
 #if KEYBOARD_DEBUG_80H
-int keyboard_write_delay(ushort_t port,
+static int keyboard_write_delay(ushort_t port,
                         void * src, 
                         uint_t length,
                         struct vm_device * dev)
@@ -759,7 +762,7 @@ int keyboard_write_delay(ushort_t port,
   }
 }
 
-int keyboard_read_delay(ushort_t port,
+static int keyboard_read_delay(ushort_t port,
                        void * dest, 
                        uint_t length,
                        struct vm_device * dev)
@@ -783,10 +786,10 @@ int keyboard_read_delay(ushort_t port,
 
 
 
-int keyboard_write_command(ushort_t port,
-                          void * src, 
-                          uint_t length,
-                          struct vm_device * dev)
+static int keyboard_write_command(ushort_t port,
+                                 void * src, 
+                                 uint_t length,
+                                 struct vm_device * dev)
 {
   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
   uchar_t cmd;
@@ -981,10 +984,10 @@ int keyboard_write_command(ushort_t port,
 
 }
 
-int keyboard_read_status(ushort_t port,
-                        void * dest, 
-                        uint_t length,
-                        struct vm_device * dev)
+static int keyboard_read_status(ushort_t port,
+                               void * dest, 
+                               uint_t length,
+                               struct vm_device * dev)
 {
   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
@@ -1003,10 +1006,10 @@ int keyboard_read_status(ushort_t port,
   }
 }
 
-int keyboard_write_output(ushort_t port,
-                         void * src, 
-                         uint_t length,
-                         struct vm_device * dev)
+static int keyboard_write_output(ushort_t port,
+                                void * src, 
+                                uint_t length,
+                                struct vm_device * dev)
 {
   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
@@ -1099,10 +1102,10 @@ int keyboard_write_output(ushort_t port,
   return 1;
 }
 
-int keyboard_read_input(ushort_t port,
-                       void * dest, 
-                       uint_t length,
-                       struct vm_device * dev)
+static int keyboard_read_input(ushort_t port,
+                              void * dest, 
+                              uint_t length,
+                              struct vm_device * dev)
 {
   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
 
@@ -1141,18 +1144,10 @@ int keyboard_read_input(ushort_t port,
 }
 
 
-int keyboard_interrupt(uint_t irq, struct vm_device * dev) 
-{
-  PrintDebug("keyboard: interrupt 0x%x\n", irq);
-
-  dev->vm->vm_ops.raise_irq(dev->vm, irq);
-
-  return 0;
 
-}
 
 
-int keyboard_init_device(struct vm_device * dev) 
+static int keyboard_init_device(struct vm_device * dev) 
 {
  
   //  struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
@@ -1164,11 +1159,15 @@ int keyboard_init_device(struct vm_device * dev)
   keyboard_reset_device(dev);
 
   // hook ports
-  dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
-  dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
+  v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
+  v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
+
+  v3_hook_host_event(dev->vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
+  v3_hook_host_event(dev->vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
+
 
 #if KEYBOARD_DEBUG_80H
-  dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
+  v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
 #endif
 
   
@@ -1180,13 +1179,13 @@ int keyboard_init_device(struct vm_device * dev)
   return 0;
 }
 
-int keyboard_deinit_device(struct vm_device *dev)
+static int keyboard_deinit_device(struct vm_device *dev)
 {
 
-  dev_unhook_io(dev, KEYBOARD_60H);
-  dev_unhook_io(dev, KEYBOARD_64H);
+  v3_dev_unhook_io(dev, KEYBOARD_60H);
+  v3_dev_unhook_io(dev, KEYBOARD_64H);
 #if KEYBOARD_DEBUG_80H
-  dev_unhook_io(dev, KEYBOARD_DELAY_80H);
+  v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
 #endif
   keyboard_reset_device(dev);
   return 0;
@@ -1207,17 +1206,13 @@ static struct vm_device_ops dev_ops = {
 
 
 
-struct vm_device *create_keyboard() {
-  
-  if (thekeyboard != NULL) { 
-    PrintDebug("keyboard: creating >1 keyboard device.  This will probably fail!\n");
-  }
-  
-  struct keyboard_internal * keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
+struct vm_device * v3_create_keyboard() {
+  struct keyboard_internal * keyboard_state = NULL;
+
+  keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
+
+  struct vm_device *device = v3_create_device("KEYBOARD", &dev_ops, keyboard_state);
 
-  struct vm_device *device = create_device("KEYBOARD", &dev_ops, keyboard_state);
 
-  thekeyboard = device;
-  
   return device;
 }
index 6326487..15c8dfa 100644 (file)
@@ -132,23 +132,14 @@ struct rtc_statd {
 
 
 
-struct vm_device * thedev = NULL;
-
-/*JRL: A hack and a fatal bug 
-static struct vm_device * demultiplex_timer_interrupt(uint_t period_us)
-{
-  // hack
-  return thedev;
-}
-*/
-/* JRL: Doesn't work
 struct bcd_num {
   uchar_t bot : 4;
   uchar_t top : 4;
-} ;
+};
+
+
 
-static uchar_t add_to(uchar_t * left, uchar_t * right, uchar_t bcd)
-{
+static uchar_t add_to(uchar_t * left, uchar_t * right, uchar_t bcd) {
   uchar_t temp;
 
   if (bcd) { 
@@ -175,12 +166,10 @@ static uchar_t add_to(uchar_t * left, uchar_t * right, uchar_t bcd)
       return 0;
     }
   }
-  
 }
 
 
-static uchar_t days_in_month(struct vm_device *dev, uchar_t month, uchar_t bcd)
-{
+static uchar_t days_in_month(struct vm_device * dev, uchar_t month, uchar_t bcd) {
   // This completely ignores Julian / Gregorian stuff right now
 
   if (bcd) { 
@@ -238,8 +227,7 @@ static uchar_t days_in_month(struct vm_device *dev, uchar_t month, uchar_t bcd)
 }
 
 
-static void update_time(struct vm_device *dev, uint_t period_us)
-{
+static void update_time(struct vm_device * dev, uint_t period_us) {
   struct nvram_internal * data = (struct nvram_internal *) (dev->private_data);
   struct rtc_stata * stata = (struct rtc_stata *) &((data->mem_state[NVRAM_REG_STAT_A]));
   struct rtc_statb * statb = (struct rtc_statb *) &((data->mem_state[NVRAM_REG_STAT_B]));
@@ -421,29 +409,27 @@ static void update_time(struct vm_device *dev, uint_t period_us)
   // Interrupt associated VM, if needed
   if (statc->irq) { 
     PrintDebug("nvram: injecting interrupt\n");
-    dev->vm->vm_ops.raise_irq(dev->vm, NVRAM_RTC_IRQ);
+    v3_raise_irq(dev->vm, NVRAM_RTC_IRQ);
   }
 }
 
-*/
 
-/* JRL: This is completely broken...
-void deliver_timer_interrupt_to_vmm(uint_t period_us)
-{
-  struct vm_device * dev = demultiplex_timer_interrupt(period_us);
+static int handle_timer_event(struct guest_info * info, 
+                       struct v3_timer_event * evt, 
+                       void * priv_data) {
+
+  struct vm_device * dev = (struct vm_device *)priv_data;
 
   if (dev) {
-    update_time(dev, period_us);
+    update_time(dev, evt->period_us);
   }
   
+  return 0;
 }
-*/
 
-static int set_nvram_defaults(struct vm_device * dev)
-{
+static int set_nvram_defaults(struct vm_device * dev) {
   struct nvram_internal * nvram_state = (struct nvram_internal *)dev->private_data;
 
-
   //
   // 2 1.44 MB floppy drives
   //
@@ -527,16 +513,13 @@ static int set_nvram_defaults(struct vm_device * dev)
   nvram_state->pus = 0;
 
   return 0;
-
 }
 
 
-int nvram_reset_device(struct vm_device * dev)
-{
+static int nvram_reset_device(struct vm_device * dev) {
   struct nvram_internal * data = (struct nvram_internal *) dev->private_data;
   
   PrintDebug("nvram: reset device\n");
-
  
   data->dev_state = NVRAM_READY;
   data->thereg = 0;
@@ -548,15 +531,13 @@ int nvram_reset_device(struct vm_device * dev)
 
 
 
-int nvram_start_device(struct vm_device *dev)
-{
+static int nvram_start_device(struct vm_device * dev) {
   PrintDebug("nvram: start device\n");
   return 0;
 }
 
 
-int nvram_stop_device(struct vm_device *dev)
-{
+static int nvram_stop_device(struct vm_device * dev) {
   PrintDebug("nvram: stop device\n");
   return 0;
 }
@@ -564,11 +545,10 @@ int nvram_stop_device(struct vm_device *dev)
 
 
 
-int nvram_write_reg_port(ushort_t port,
-                        void * src, 
-                        uint_t length,
-                        struct vm_device * dev)
-{
+static int nvram_write_reg_port(ushort_t port,
+                               void * src, 
+                               uint_t length,
+                               struct vm_device * dev) {
   struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
 
   memcpy(&(data->thereg), src, 1);
@@ -578,14 +558,11 @@ int nvram_write_reg_port(ushort_t port,
   return 1;
 }
 
-int nvram_read_data_port(ushort_t port,
-                        void * dst, 
-                        uint_t length,
-                        struct vm_device * dev)
-{
-  struct nvram_internal * data = (struct nvram_internal *) dev->private_data;
-
-
+static int nvram_read_data_port(ushort_t port,
+                               void * dst, 
+                               uint_t length,
+                               struct vm_device * dev) {
+  struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
 
   memcpy(dst, &(data->mem_state[data->thereg]), 1);
 
@@ -600,11 +577,10 @@ int nvram_read_data_port(ushort_t port,
   return 1;
 }
 
-int nvram_write_data_port(ushort_t port,
-                         void * src, 
-                         uint_t length,
-                         struct vm_device * dev)
-{
+static int nvram_write_data_port(ushort_t port,
+                                void * src, 
+                                uint_t length,
+                                struct vm_device * dev) {
   struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
 
   memcpy(&(data->mem_state[data->thereg]), src, 1);
@@ -616,9 +592,9 @@ int nvram_write_data_port(ushort_t port,
 
 
 
-int nvram_init_device(struct vm_device * dev) {
+static int nvram_init_device(struct vm_device * dev) {
  
-  struct nvram_internal * data = (struct nvram_internal *) dev->private_data;
+  struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
 
   PrintDebug("nvram: init_device\n");
 
@@ -630,18 +606,17 @@ int nvram_init_device(struct vm_device * dev) {
   nvram_reset_device(dev);
 
   // hook ports
-  dev_hook_io(dev, NVRAM_REG_PORT, NULL, &nvram_write_reg_port);
-  dev_hook_io(dev, NVRAM_DATA_PORT, &nvram_read_data_port, &nvram_write_data_port);
+  v3_dev_hook_io(dev, NVRAM_REG_PORT, NULL, &nvram_write_reg_port);
+  v3_dev_hook_io(dev, NVRAM_DATA_PORT, &nvram_read_data_port, &nvram_write_data_port);
   
+  v3_hook_host_event(dev->vm, HOST_TIMER_EVT, V3_HOST_EVENT_HANDLER(handle_timer_event), dev);
+
   return 0;
 }
 
-int nvram_deinit_device(struct vm_device *dev)
-{
-
-
-  dev_unhook_io(dev, NVRAM_REG_PORT);
-  dev_unhook_io(dev, NVRAM_DATA_PORT);
+static int nvram_deinit_device(struct vm_device * dev) {
+  v3_dev_unhook_io(dev, NVRAM_REG_PORT);
+  v3_dev_unhook_io(dev, NVRAM_DATA_PORT);
 
   nvram_reset_device(dev);
   return 0;
@@ -662,18 +637,14 @@ static struct vm_device_ops dev_ops = {
 
 
 
-struct vm_device * create_nvram() {
-  struct nvram_internal * nvram_state = (struct nvram_internal *)V3_Malloc(sizeof(struct nvram_internal) + 1000);
+struct vm_device * v3_create_nvram() {
+  struct nvram_internal * nvram_state = NULL;
 
-  PrintDebug("nvram: internal at %x\n",nvram_state);
+  nvram_state = (struct nvram_internal *)V3_Malloc(sizeof(struct nvram_internal) + 1000);
 
-  struct vm_device * device = create_device("NVRAM", &dev_ops, nvram_state);
-
-  if (thedev != NULL) {
-    PrintDebug("nvram: warning! overwriting thedev\n");
-  }
+  PrintDebug("nvram: internal at %x\n", nvram_state);
 
-  thedev = device;
+  struct vm_device * device = v3_create_device("NVRAM", &dev_ops, nvram_state);
 
   return device;
 }
index 495ffe8..5879875 100644 (file)
 #include <devices/ide.h>
 
 
+#ifndef TRACE_RAMDISK
+#undef PrintTrace
+#define PrintTrace(fmt, args...)
+#endif
+
+
 #ifndef DEBUG_RAMDISK
 #undef PrintDebug
-#define PrintDebug(_f, _a...)
+#define PrintDebug(fmt, args...)
 #endif
 
 
@@ -301,7 +307,7 @@ static void rd_identify_ATAPI_drive(struct vm_device * dev, struct channel_t * c
  * Interrupt handling
  */
 static void rd_raise_interrupt(struct vm_device * dev, struct channel_t * channel);
-static void rd_lower_irq(struct vm_device *dev, Bit32u irq);
+static void rd_lower_irq(struct vm_device *dev, struct channel_t * channel);
 
 
 
@@ -315,6 +321,8 @@ static void rd_lower_irq(struct vm_device *dev, Bit32u irq);
 static void rd_print_state(struct ramdisk_t *ramdisk);
 static int check_bit_fields(struct controller_t * controller);
 #endif
+
+
 ////////////////////////////////////////////////////////////////////
 
 
@@ -354,9 +362,10 @@ int v3_ramdisk_register_cdrom(struct vm_device * dev, uint_t busID, uint_t drive
   
   drive->private_data = private_data;
 
+
 #ifdef DEBUG_RAMDISK
   if (check_bit_fields(controller) == INTR_REASON_BIT_ERR) {
-    PrintDebug("interrupt reason: bit field error\n");
+    PrintError("interrupt reason: bit field error\n");
     return INTR_REASON_BIT_ERR;
   }
 #endif
@@ -488,7 +497,7 @@ static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_de
   controller = &(drive->controller);
 
 
-  PrintDebug("[read_data_handler] IO Read at 0x%x, on drive %d/%d (current_cmd = 0x%02x)\n", 
+  PrintTrace("[read_data_handler] IO Read at 0x%x, on drive %d/%d current cmd=0x%x\n", 
             port, 
             get_channel_no(ramdisk, channel),
             get_drive_no(channel, drive), 
@@ -539,7 +548,7 @@ static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_de
       uint_t index = controller->buffer_index;
 
       
-      PrintDebug("\t\tatapi.command(%02x), index(%d), cdrom.remaining_blocks(%d)\n", 
+      PrintTrace("\t\tatapi.command(%02x), index(%d), cdrom.remaining_blocks(%d)\n", 
                    drive->atapi.command, 
                    index, 
                    drive->cdrom.remaining_blocks);
@@ -657,7 +666,7 @@ static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_de
     }
 
   default:
-    PrintDebug("\t\tread need support more command: %02x\n", controller->current_command);
+    PrintError("\t\tunsupported command: %02x\n", controller->current_command);
     break;
   }
 
@@ -700,6 +709,7 @@ static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_d
   case 0xa0: // PACKET
     
     if (handle_atapi_packet_command(dev, channel, *(ushort_t *)src) == -1) {
+      PrintError("Error sending atapi packet command in PACKET write to data port\n");
       return -1;
     }
 
@@ -750,6 +760,7 @@ static int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_
 
 
   if (num_drives_on_channel(channel) == 0) {
+    PrintDebug("Setting value to zero because 0 devices on channel\n");
     // (mch) Just return zero for these registers
     memset(dst, 0, length);
 
@@ -777,7 +788,7 @@ static int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_
   }
   
   if ((port == SEC_CMD_PORT) || (port == PRI_CMD_PORT)) {
-    rd_lower_irq(dev, channel->irq);
+    rd_lower_irq(dev, channel);
   }
   
   PrintDebug("\t\tRead STATUS = 0x%x\n", *(uchar_t *)dst);
@@ -814,10 +825,52 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
 
   PrintDebug("[write_command_handler] IO write at 0x%x, on drive %d/%d (val = 0x%x)\n", 
             port, get_channel_no(ramdisk, channel), 
-            channel->drive_select, 
+            get_drive_no(channel, drive), 
             value);
 
   switch (value) {
+#if 0
+  case 0xec: // IDENTIFY DEVICE
+    {
+
+      if (drive->device_type == IDE_NONE) {
+       PrintError("\t\tError: disk ata%d-%d not present, aborting\n", 
+                  get_channel_no(ramdisk, channel), 
+                  get_drive_no(channel, drive));
+       rd_command_aborted(dev, channel, value);
+       break;
+      } else if (drive->device_type == IDE_CDROM) {
+       PrintDebug("Identifying CDROM...Going to abort????\n");
+       controller->head_no        = 0;
+       controller->sector_count   = 1;
+       controller->sector_no      = 1;
+       controller->cylinder_no    = 0xeb14;
+       rd_command_aborted(dev, channel, 0xec);
+      } else {
+       PrintError("\t\tError: Want to identify HDD!!\n");
+       /*
+         SELECTED_CONTROLLER(channel).current_command = value;
+         SELECTED_CONTROLLER(channel).error_register = 0;
+         
+         // See ATA/ATAPI-4, 8.12
+         SELECTED_CONTROLLER(channel).status.busy  = 0;
+         SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+         SELECTED_CONTROLLER(channel).status.write_fault = 0;
+         SELECTED_CONTROLLER(channel).status.drq   = 1;
+         SELECTED_CONTROLLER(channel).status.err   = 0;
+         
+         SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+         SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+         
+         SELECTED_CONTROLLER(channel).buffer_index = 0;
+         raise_interrupt(channel);
+         identify_drive(channel);
+       */
+      }
+
+    break;
+    }
+#endif
     // ATAPI commands
   case 0xa1: // IDENTIFY PACKET DEVICE
     {
@@ -838,6 +891,9 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
        rd_raise_interrupt(dev, channel);
        rd_identify_ATAPI_drive(dev, channel);
       } else {
+       PrintError("Identifying non cdrom device not supported - ata %d/%d\n", 
+                  get_channel_no(ramdisk, channel),
+                  get_drive_no(channel, drive));
        rd_command_aborted(dev, channel, 0xa1);
       }
       break;
@@ -870,12 +926,15 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
        controller->current_command = value;
        controller->buffer_index = 0;
       } else {
+       PrintError("Sending packet to non cdrom device not supported\n");
        rd_command_aborted (dev, channel, 0xa0);
       }
       break;
     }
   default:
-    PrintError("\t\tneed translate command %2x\n", value);
+    PrintError("\t\tneed translate command %2x - ata %d\%d\n", value, 
+              get_channel_no(ramdisk, channel), 
+              get_drive_no(channel, drive));
     //return -1;
     /* JRL THIS NEEDS TO CHANGE */
     return length;
@@ -978,7 +1037,7 @@ static int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_d
       ctrl->control.disable_irq = 0;
     }
 
-    rd_lower_irq(dev, channel->irq);
+    rd_lower_irq(dev, channel);
 
   } else if ((controller->reset_in_progress) &&
             (!controller->control.reset)) {
@@ -1268,7 +1327,7 @@ static int write_general_port(ushort_t port, void * src, uint_t length, struct v
       drive = get_selected_drive(channel);
 
       if (drive->device_type == IDE_NONE) {
-       PrintDebug("\t\tError: device set to %d which does not exist! channel = 0x%x\n",
+       PrintError("\t\tError: device set to %d which does not exist! channel = 0x%x\n",
                   channel->drive_select, get_channel_no(ramdisk, channel));
 
        controller->error_register = 0x04; // aborted
@@ -1290,30 +1349,27 @@ static int write_general_port(ushort_t port, void * src, uint_t length, struct v
 
 
 static void rd_raise_interrupt(struct vm_device * dev, struct channel_t * channel) {
-  Bit32u irq;
   //  struct ramdisk_t * ramdisk = (struct ramdisk_t *)(dev->private_data);
   struct drive_t * drive = get_selected_drive(channel);
   struct controller_t * controller = &(drive->controller);
 
-  PrintDebug("[raise_interrupt] disable_irq = %02x\n", controller->control.disable_irq);
+  PrintDebug("[raise_interrupt] disable_irq = 0x%02x\n", controller->control.disable_irq);
 
   if (!(controller->control.disable_irq)) {
-    irq = channel->irq; 
  
-    PrintDebug("\t\tRaising interrupt %d {%s}\n\n", irq, device_type_to_str(drive->device_type));
+    PrintDebug("\t\tRaising interrupt %d {%s}\n\n", channel->irq, device_type_to_str(drive->device_type));
 
-    dev->vm->vm_ops.raise_irq(dev->vm, irq);
+    v3_raise_irq(dev->vm, channel->irq);
   } else {
-    PrintDebug("\t\tirq is disabled\n");
+    PrintDebug("\t\tRaising irq but irq is disabled\n");
   }
   
   return;
 }
 
-static void rd_lower_irq(struct vm_device *dev, Bit32u irq)  // __attribute__(regparm(1))
-{
-  PrintDebug("[lower_irq] irq = %d\n", irq);
-  dev->vm->vm_ops.lower_irq(dev->vm, irq);
+static void rd_lower_irq(struct vm_device *dev, struct channel_t * channel) {
+  PrintDebug("[lower_irq] irq = %d\n", channel->irq);
+  v3_lower_irq(dev->vm, channel->irq);
 }
 
 
@@ -1356,9 +1412,11 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
     switch (atapi_command) {
     case 0x00: // test unit ready
       {
+       PrintDebug("Testing unit ready\n");
        if (drive->cdrom.ready) {
          rd_atapi_cmd_nop(dev, channel);
        } else {
+         PrintError("CDROM not ready in test unit ready\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
        }
        
@@ -1371,6 +1429,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
        int alloc_length = controller->buffer[4];
 
        if (rd_init_send_atapi_command(dev, channel, atapi_command, 18, alloc_length, false) == -1) {
+         PrintError("Error sending atapi command in Request Sense\n");
          return -1;
        }
        
@@ -1409,6 +1468,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
 
          rd_atapi_cmd_nop(dev, channel);
          rd_raise_interrupt(dev, channel);
+
        } else if (!LoEj && Start) { // start (spin up) the disc
          
          drive->cdrom.cd->start_cdrom(drive->private_data);
@@ -1416,9 +1476,10 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
          PrintError("FIXME: ATAPI start disc not reading TOC\n");
          rd_atapi_cmd_nop(dev, channel);
          rd_raise_interrupt(dev, channel);
+
        } else if (LoEj && !Start) { // Eject the disc
          rd_atapi_cmd_nop(dev, channel);
-         
+         PrintDebug("Ejecting Disk\n");
          if (drive->cdrom.ready) {
            
            drive->cdrom.cd->eject_cdrom(drive->private_data);
@@ -1428,6 +1489,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
            //bx_gui->update_drive_status_buttons();
          }
          rd_raise_interrupt(dev, channel);
+
        } else { // Load the disc
          // My guess is that this command only closes the tray, that's a no-op for us
          rd_atapi_cmd_nop(dev, channel);
@@ -1445,6 +1507,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
        }
        
        if (rd_init_send_atapi_command(dev, channel, atapi_command, 8, alloc_length, false) == -1) {
+         PrintError("Error sending atapi command in mechanism status\n");
          return -1;
        }
        
@@ -1478,6 +1541,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
              {
                
                if (rd_init_send_atapi_command(dev, channel, atapi_command, sizeof(struct error_recovery_t) + 8, alloc_length, false) == -1) {
+                 PrintError("Error sending atapi command in mode sense error recovery\n");
                  return -1;
                }
                
@@ -1490,6 +1554,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
              {
 
                if (rd_init_send_atapi_command(dev, channel, atapi_command, 28, alloc_length, false) == -1) {
+                 PrintError("Error sending atapi command in CDROM caps/mech mode-sense\n");
                  return -1;
                }
 
@@ -1536,7 +1601,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
            default:
              {
                // not implemeted by this device
-               PrintDebug("\t\tcdrom: MODE SENSE PC=%x, PageCode=%x, not implemented by device\n",
+               PrintError("\t\tcdrom: MODE SENSE PC=%x, PageCode=%x, not implemented by device\n",
                              PC, PageCode);
                rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST,
                                   ASC_INV_FIELD_IN_CMD_PACKET);
@@ -1565,6 +1630,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
            default:
              {
                // not implemeted by this device
+               PrintError("Changeable values of mode sense not supported by cdrom\n");
                PrintDebug("\t\tcdrom: MODE SENSE PC=%x, PageCode=%x, not implemented by device\n",
                           PC, PageCode);
                rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST,
@@ -1583,15 +1649,17 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
            case 0x0e: // CD-ROM audio control
            case 0x2a: // CD-ROM capabilities & mech. status
            case 0x3f: // all
-             PrintError("cdrom: MODE SENSE (dflt), code=%x\n",
+             PrintError("Default values of mode sense not supported by cdrom\n");
+             PrintDebug("cdrom: MODE SENSE (dflt), code=%x\n",
                       PageCode);
              return -1;
              
            default:
              {
+               PrintError("Default values of mode sense not implemented in cdrom\n");
                // not implemeted by this device
-               PrintDebug("\t\tcdrom: MODE SENSE PC=%x, PageCode=%x, not implemented by device\n",
-                             PC, PageCode);
+               PrintDebug("cdrom: MODE SENSE PC=%x, PageCode=%x, not implemented by device\n",
+                          PC, PageCode);
                rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST,
                                   ASC_INV_FIELD_IN_CMD_PACKET);
                rd_raise_interrupt(dev, channel);
@@ -1602,13 +1670,14 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
          }
        case 0x3: // saved values not implemented
          {
+           PrintError("\t\tSaved values not implemented in mode sense\n");
            rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
            rd_raise_interrupt(dev, channel);
            break;
          }
        default:
          {
-           PrintError("Should not get here!\n");
+           PrintError("Unsupported Mode sense value\n");
            return -1;
            break;
          }
@@ -1620,6 +1689,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
        uint8_t alloc_length = controller->buffer[4];
        
        if (rd_init_send_atapi_command(dev, channel, atapi_command, 36, alloc_length, false) == -1) {
+         PrintError("Error sending atapi command in inquiry\n");
          return -1;
        }
        
@@ -1658,6 +1728,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
       {
        // no allocation length???
        if (rd_init_send_atapi_command(dev, channel, atapi_command, 8, 8, false) == -1) {
+         PrintError("Error sending atapi command in read cdrom capacity\n");
          return -1;
        }
        
@@ -1677,6 +1748,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
 
          rd_ready_to_send_atapi(dev, channel);
        } else {
+         PrintError("CDROM not ready in read cdrom capacity\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
          rd_raise_interrupt(dev, channel);
        }
@@ -1691,6 +1763,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
          rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
          rd_raise_interrupt(dev, channel);
        } else {
+         PrintError("Drive not ready in read cd with CD present\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
          rd_raise_interrupt(dev, channel);
        }
@@ -1723,7 +1796,9 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
                break;
              }
 
+
              if (rd_init_send_atapi_command(dev, channel, atapi_command, toc_length, alloc_length, false) == -1) {
+               PrintError("Failed to init send atapi command in read toc (fmt=%d)\n", format);
                return -1;
              }
 
@@ -1735,6 +1810,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
            // multi session stuff. we ignore this and emulate a single session only
 
            if (rd_init_send_atapi_command(dev, channel, atapi_command, 12, alloc_length, false) == -1) {
+             PrintError("Failed to init send atapi command in read toc (fmt=%d)\n", format);
              return -1;
            }
            
@@ -1756,6 +1832,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
            return -1;
          }
        } else {
+         PrintError("CDROM not ready in read toc\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
          rd_raise_interrupt(dev, channel);
        }
@@ -1783,10 +1860,10 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
        }
        
        if (transfer_length == 0) {
-         rd_atapi_cmd_nop(dev, channel);
-         rd_raise_interrupt(dev, channel);
          PrintError("READ(%d) with transfer length 0, ok\n", 
                     (atapi_command == 0x28) ? 10 : 12);
+         rd_atapi_cmd_nop(dev, channel);
+         rd_raise_interrupt(dev, channel);
          break;
        }
        
@@ -1820,18 +1897,20 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
        uint32_t lba = rd_read_32bit(controller->buffer + 2);
 
        if (!(drive->cdrom.ready)) {
+         PrintError("CDROM not ready in seek\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
          rd_raise_interrupt(dev, channel);
          break;
        }
        
        if (lba > drive->cdrom.capacity) {
+         PrintError("LBA is greater than CDROM capacity in seek\n");
          rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
          rd_raise_interrupt(dev, channel);
          break;
        }
        
-       PrintDebug("\t\tcdrom: SEEK (ignored)\n");
+       PrintError("\t\tcdrom: SEEK (ignored)\n");
 
        rd_atapi_cmd_nop(dev, channel);
        rd_raise_interrupt(dev, channel);
@@ -1845,6 +1924,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
          drive->cdrom.locked = controller->buffer[4] & 1;
          rd_atapi_cmd_nop(dev, channel);
        } else {
+         PrintError("CD not ready in prevent/allow medium removal\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
        }
 
@@ -1867,6 +1947,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
          UNUSED(track_number);
        */
        if (!(drive->cdrom.ready)) {
+         PrintError("CDROM not ready in read sub-channel\n");
          rd_atapi_cmd_error(dev, channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
          rd_raise_interrupt(dev, channel);
        } else {
@@ -1885,6 +1966,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
          }
          
          if (rd_init_send_atapi_command(dev, channel, atapi_command, ret_len, alloc_length, false) == -1) {
+           PrintError("Error sending atapi command in read sub-channel\n");
            return -1;
          }
          rd_ready_to_send_atapi(dev, channel);
@@ -1894,6 +1976,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
     case 0x51:  // read disc info
       {
        // no-op to keep the Linux CD-ROM driver happy
+       PrintError("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
        rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
        rd_raise_interrupt(dev, channel);
        break;
@@ -1912,7 +1995,7 @@ int handle_atapi_packet_command(struct vm_device * dev, struct channel_t * chann
     case 0x46: // ???
     case 0x4a: // ???
       PrintError("ATAPI command 0x%x not implemented yet\n",
-              atapi_command);
+                atapi_command);
       rd_atapi_cmd_error(dev, channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
       rd_raise_interrupt(dev, channel);
       break;
@@ -2025,14 +2108,12 @@ void rd_atapi_cmd_error(struct vm_device * dev, struct channel_t * channel, sens
   struct drive_t * drive = &(channel->drives[channel->drive_select]);
   struct controller_t * controller = &(drive->controller);
 
-#ifdef DEBUG_RAMDISK
-  {
-    struct ramdisk_t *ramdisk = (struct ramdisk_t *)(dev->private_data);
-    PrintDebug("[rd_atapi_cmd_error]\n");
-    PrintDebug("Error: atapi_cmd_error channel=%02x key=%02x asc=%02x\n", 
-              get_channel_no(ramdisk, channel), sense_key, asc);
-  }
-#endif
+
+  struct ramdisk_t *ramdisk = (struct ramdisk_t *)(dev->private_data);
+  PrintError("[rd_atapi_cmd_error]\n");
+  PrintError("Error: atapi_cmd_error channel=%02x key=%02x asc=%02x\n", 
+            get_channel_no(ramdisk, channel), sense_key, asc);
+  
 
   controller->error_register = sense_key << 4;
   controller->interrupt_reason.i_o = 1;
@@ -2215,8 +2296,8 @@ static void rd_command_aborted(struct vm_device * dev,
   struct drive_t * drive = &(channel->drives[channel->drive_select]);
   struct controller_t * controller = &(drive->controller);
 
-  PrintDebug("[rd_command_aborted]\n");
-  PrintDebug("\t\taborting on command 0x%02x {%s}\n", value, device_type_to_str(drive->device_type));
+  PrintError("[rd_command_aborted]\n");
+  PrintError("\t\taborting on command 0x%02x {%s}\n", value, device_type_to_str(drive->device_type));
 
   controller->current_command = 0;
   controller->status.busy = 0;
@@ -2241,54 +2322,54 @@ static int ramdisk_init_device(struct vm_device *dev) {
   rd_init_hardware(ramdisk);
 
 
-  dev_hook_io(dev, PRI_CTRL_PORT, 
-             &read_status_port, &write_ctrl_port);
-
-  dev_hook_io(dev, PRI_DATA_PORT, 
-             &read_data_port, &write_data_port);
-  dev_hook_io(dev, PRI_FEATURES_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, PRI_SECT_CNT_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, PRI_SECT_ADDR1_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, PRI_SECT_ADDR2_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, PRI_SECT_ADDR3_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, PRI_DRV_SEL_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, PRI_CMD_PORT, 
-             &read_status_port, &write_cmd_port);
-
-
-  dev_hook_io(dev, SEC_CTRL_PORT, 
-             &read_status_port, &write_ctrl_port);
-
-  dev_hook_io(dev, SEC_DATA_PORT, 
-             &read_data_port, &write_data_port);
-  dev_hook_io(dev, SEC_FEATURES_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, SEC_SECT_CNT_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, SEC_SECT_ADDR1_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, SEC_SECT_ADDR2_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, SEC_SECT_ADDR3_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, SEC_DRV_SEL_PORT, 
-             &read_general_port, &write_general_port);
-  dev_hook_io(dev, SEC_CMD_PORT, 
-             &read_status_port, &write_cmd_port);
-
+  v3_dev_hook_io(dev, PRI_CTRL_PORT, 
+                &read_status_port, &write_ctrl_port);
+
+  v3_dev_hook_io(dev, PRI_DATA_PORT, 
+                &read_data_port, &write_data_port);
+  v3_dev_hook_io(dev, PRI_FEATURES_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_SECT_CNT_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_SECT_ADDR1_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_SECT_ADDR2_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_SECT_ADDR3_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_DRV_SEL_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_CMD_PORT, 
+                &read_status_port, &write_cmd_port);
+
+
+  v3_dev_hook_io(dev, SEC_CTRL_PORT, 
+                &read_status_port, &write_ctrl_port);
+
+  v3_dev_hook_io(dev, SEC_DATA_PORT, 
+                &read_data_port, &write_data_port);
+  v3_dev_hook_io(dev, SEC_FEATURES_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_SECT_CNT_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_SECT_ADDR1_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_SECT_ADDR2_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_SECT_ADDR3_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_DRV_SEL_PORT, 
+                &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_CMD_PORT, 
+                &read_status_port, &write_cmd_port);
+  
   
 
-  dev_hook_io(dev, SEC_ADDR_REG_PORT, 
-             &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, SEC_ADDR_REG_PORT, 
+                &read_general_port, &write_general_port);
 
-  dev_hook_io(dev, PRI_ADDR_REG_PORT, 
-             &read_general_port, &write_general_port);
+  v3_dev_hook_io(dev, PRI_ADDR_REG_PORT, 
+                &read_general_port, &write_general_port);
 
 
 
@@ -2314,7 +2395,7 @@ static struct vm_device_ops dev_ops = {
 
 
 
-struct vm_device *create_ramdisk()
+struct vm_device * v3_create_ramdisk()
 {
 
   struct ramdisk_t *ramdisk;
@@ -2323,7 +2404,7 @@ struct vm_device *create_ramdisk()
 
   PrintDebug("[create_ramdisk]\n");
 
-  struct vm_device *device = create_device("RAMDISK", &dev_ops, ramdisk);
+  struct vm_device * device = v3_create_device("RAMDISK", &dev_ops, ramdisk);
 
   return device;
 }
@@ -2523,4 +2604,5 @@ static int check_bit_fields(struct controller_t * controller) {
   
   return 0;
 }
+
 #endif
index 55d7541..7468493 100644 (file)
@@ -161,8 +161,8 @@ struct serial_buffer {
   char buffer[SERIAL_BUF_LEN];
 };
 
-int queue_data(struct serial_buffer * buf, char data) {
-  int next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
+static int queue_data(struct serial_buffer * buf, char data) {
+  uint_t next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
 
   if (next_loc == buf->tail) {
     return -1;
@@ -174,8 +174,8 @@ int queue_data(struct serial_buffer * buf, char data) {
   return 0;
 }
 
-int dequeue_data(struct serial_buffer * buf, char * data) {
-  int next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
+static int dequeue_data(struct serial_buffer * buf, char * data) {
+  uint_t next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
 
   if (buf->head == buf->tail) {
     return -1;
@@ -210,7 +210,7 @@ struct serial_state {
 };
 
 
-int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
   struct serial_state * state = (struct serial_state *)dev->private_data;
   char * val = (char *)src;
   PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *(char*)src);
@@ -243,7 +243,7 @@ int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device *
 
 
 
-int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct serial_state * state = (struct serial_state *)dev->private_data;
   char * val = (char *)dst;
   PrintDebug("Read from Data Port 0x%x\n", port);
@@ -276,20 +276,20 @@ int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device *
 
 
 
-int handle_ier_write(struct serial_port * com, struct irq_enable_reg * ier) {
+static int handle_ier_write(struct serial_port * com, struct irq_enable_reg * ier) {
   
 
   return -1;
 }
 
 
-int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
   struct serial_state * state = (struct serial_state *)dev->private_data;
   char * val = (char *)src;
   PrintDebug("Write to Control Port (val=%x)\n", *(char *)src);
 
   if (length != 1) {
-    PrintDebug("Invalid Write length to control port\n", port, port);
+    PrintDebug("Invalid Write length to control port %d\n", port);
     return -1;
   }
 
@@ -343,7 +343,7 @@ int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device *
 
 
 
-int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct serial_state * state = (struct serial_state *)dev->private_data;
   char * val = (char *)dst;
   PrintDebug("Read from Control Port\n");
@@ -414,13 +414,13 @@ int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device *
 }
 
 
-int write_status_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+static int write_status_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
   PrintDebug("Write to Status Port 0x%x (val=%x)\n", port, *(char *)src);
 
   return -1;
 }
 
-int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
   struct serial_state * state = (struct serial_state *)dev->private_data;
   char * val = (char *)dst;
   PrintDebug("Read from Status Port 0x%x\n", port);
@@ -490,7 +490,7 @@ static int init_serial_port(struct serial_port * com) {
   return 0;
 }
 
-int serial_init(struct vm_device * dev) {
+static int serial_init(struct vm_device * dev) {
   struct serial_state * state = (struct serial_state *)dev->private_data;
 
 
@@ -499,84 +499,84 @@ int serial_init(struct vm_device * dev) {
   init_serial_port(&(state->com3));
   init_serial_port(&(state->com4));
 
-  dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
-  dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-  dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
-  dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-  dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
-  dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
-
-  dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
-  dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
-  dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
-  dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
+  v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+  v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
+  v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+  v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
+  v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+
+  v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
+  v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
+  v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
+  v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
 
   return 0;
 }
 
 
-int serial_deinit(struct vm_device * dev) {
-
-
-  dev_unhook_io(dev, COM1_DATA_PORT);
-  dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
-  dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
-  dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
-  dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
-  dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
-  dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
-  dev_unhook_io(dev, COM1_SCRATCH_PORT);
-
-  dev_unhook_io(dev, COM2_DATA_PORT);
-  dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
-  dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
-  dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
-  dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
-  dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
-  dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
-  dev_unhook_io(dev, COM2_SCRATCH_PORT);
-
-  dev_unhook_io(dev, COM3_DATA_PORT);
-  dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
-  dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
-  dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
-  dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
-  dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
-  dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
-  dev_unhook_io(dev, COM3_SCRATCH_PORT);
-
-  dev_unhook_io(dev, COM4_DATA_PORT);
-  dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
-  dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
-  dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
-  dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
-  dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
-  dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
-  dev_unhook_io(dev, COM4_SCRATCH_PORT);
+static int serial_deinit(struct vm_device * dev) {
+
+
+  v3_dev_unhook_io(dev, COM1_DATA_PORT);
+  v3_dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
+  v3_dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM1_SCRATCH_PORT);
+
+  v3_dev_unhook_io(dev, COM2_DATA_PORT);
+  v3_dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
+  v3_dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM2_SCRATCH_PORT);
+
+  v3_dev_unhook_io(dev, COM3_DATA_PORT);
+  v3_dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
+  v3_dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM3_SCRATCH_PORT);
+
+  v3_dev_unhook_io(dev, COM4_DATA_PORT);
+  v3_dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
+  v3_dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
+  v3_dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
+  v3_dev_unhook_io(dev, COM4_SCRATCH_PORT);
 
   return 0;
 }
@@ -592,12 +592,12 @@ static struct vm_device_ops dev_ops = {
 };
 
 
-struct vm_device * create_serial(int num_ports) {
+struct vm_device * v3_create_serial(int num_ports) {
   struct serial_state * state = NULL;
   state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
   V3_ASSERT(state != NULL);
 
-  struct vm_device * device = create_device("Serial UART", &dev_ops, state);
+  struct vm_device * device = v3_create_device("Serial UART", &dev_ops, state);
 
   return device;
 }
index c0903eb..7003111 100644 (file)
@@ -60,16 +60,16 @@ static struct intr_ctrl_ops intr_ops = {
 
 
 
-int pic_init_device(struct vm_device * dev) {
+static int pic_init_device(struct vm_device * dev) {
   struct pic_internal * data = (struct pic_internal *)dev->private_data;
-  set_intr_controller(dev->vm, &intr_ops, data);
+  v3_set_intr_controller(dev->vm, &intr_ops, data);
   data->pending_irq = 0;
 
   return 0;
 }
 
 
-int pic_deinit_device(struct vm_device * dev) {
+static int pic_deinit_device(struct vm_device * dev) {
   return 0;
 }
 
@@ -86,12 +86,12 @@ static struct vm_device_ops dev_ops = {
 };
 
 
-struct vm_device * create_simple_pic() {
+struct vm_device * v3_create_simple_pic() {
   struct pic_internal * state = NULL;
   state = (struct pic_internal *)V3_Malloc(sizeof(struct pic_internal));
   V3_ASSERT(state != NULL);
 
-  struct vm_device * pic_dev = create_device("Simple Pic", &dev_ops, state);
+  struct vm_device * pic_dev = v3_create_device("Simple Pic", &dev_ops, state);
 
 
   return pic_dev;
index 87dcdfa..5ed434b 100644 (file)
@@ -28,20 +28,21 @@ struct timer_state {
 };
 
 
-
-int irq_handler(uint_t irq, struct vm_device * dev) {
+/*
+static int irq_handler(uint_t irq, struct vm_device * dev) {
   PrintDebug("Timer interrupt\n");
   return 0;
 
 }
+*/
 
-int timer_init(struct vm_device * dev) {
+static int timer_init(struct vm_device * dev) {
   //dev_hook_irq(dev, TIMER_IRQ, &irq_handler);
 
   return 0;
 }
 
-int timer_deinit(struct vm_device * dev) {
+static int timer_deinit(struct vm_device * dev) {
 
   return 0;
 }
@@ -57,12 +58,12 @@ static struct vm_device_ops dev_ops = {
 };
 
 
-struct vm_device * create_timer() {
+struct vm_device * v3_create_timer() {
   struct timer_state * timer = NULL;
   timer = (struct timer_state *)V3_Malloc( sizeof(struct timer_state));
   V3_ASSERT(timer != NULL);
 
-  struct vm_device * dev = create_device("Timer", &dev_ops, timer);
+  struct vm_device * dev = v3_create_device("Timer", &dev_ops, timer);
   
   return dev;
 
index 015e396..d533c92 100644 (file)
 
 #include <palacios/vmm_decoder.h>
 #include <palacios/vmm_string.h>
+#include <palacios/vmm_lowlevel.h>
 
 
 
-
-extern uint_t cpuid_ecx(uint_t op);
-extern uint_t cpuid_edx(uint_t op);
-extern void Get_MSR(uint_t MSR, uint_t * high_byte, uint_t * low_byte); 
-extern void Set_MSR(uint_t MSR, uint_t high_byte, uint_t low_byte);
-extern uint_t launch_svm(vmcb_t * vmcb_addr);
-extern void safe_svm_launch(vmcb_t * vmcb_addr, struct v3_gprs * gprs);
-
-extern void STGI();
-extern void CLGI();
-
-extern uint_t Get_CR3();
-
-
-extern void DisableInts();
-extern void EnableInts();
-
-
-
+extern void v3_stgi();
+extern void v3_clgi();
+extern int v3_svm_launch(vmcb_t * vmcb, struct v3_gprs * vm_regs);
 
 
 
 
 static vmcb_t * Allocate_VMCB() {
-  vmcb_t * vmcb_page = (vmcb_t *)V3_AllocPages(1);
-
+  vmcb_t * vmcb_page = (vmcb_t *)V3_VAddr(V3_AllocPages(1));
 
   memset(vmcb_page, 0, 4096);
 
@@ -71,7 +55,7 @@ static vmcb_t * Allocate_VMCB() {
 
 
 
-
+#include <palacios/vmm_ctrl_regs.h>
 
 static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
@@ -89,7 +73,23 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
   ctrl_area->cr_reads.cr0 = 1;
   ctrl_area->cr_writes.cr0 = 1;
 
+
+  /* Set up the efer to enable 64 bit page tables */
+  /*
+  {
+    struct efer_64 * efer = (struct efer_64 *)&(guest_state->efer);
+    struct cr4_32 * cr4 = (struct cr4_32 *)&(guest_state->cr4);
+    efer->lma = 1;
+    efer->lme = 1;
+
+    cr4->pae = 1;
+  }
+  */
+
   guest_state->efer |= EFER_MSR_svm_enable;
+
+
+
   guest_state->rflags = 0x00000002; // The reserved bit is always 1
   ctrl_area->svm_instrs.VMRUN = 1;
   ctrl_area->svm_instrs.VMMCALL = 1;
@@ -145,6 +145,10 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
   guest_state->cs.attrib.raw = 0xf3;
 
   
+  /* DEBUG FOR RETURN CODE */
+  ctrl_area->exit_code = 1;
+
+
   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
   for ( i = 0; segregs[i] != NULL; i++) {
     struct vmcb_selector * seg = segregs[i];
@@ -176,10 +180,10 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
     struct vmm_io_hook * iter;
     addr_t io_port_bitmap;
     
-    io_port_bitmap = (addr_t)V3_AllocPages(3);
+    io_port_bitmap = (addr_t)V3_VAddr(V3_AllocPages(3));
     memset((uchar_t*)io_port_bitmap, 0, PAGE_SIZE * 3);
     
-    ctrl_area->IOPM_BASE_PA = io_port_bitmap;
+    ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr((void *)io_port_bitmap);
 
     //PrintDebug("Setting up IO Map at 0x%x\n", io_port_bitmap);
 
@@ -188,7 +192,7 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
       uchar_t * bitmap = (uchar_t *)io_port_bitmap;
 
       bitmap += (port / 8);
-      PrintDebug("Setting Bit for port 0x%x\n", port);
+      //      PrintDebug("Setting Bit for port 0x%x\n", port);
       *bitmap |= 1 << (port % 8);
     }
 
@@ -207,12 +211,23 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
 
   if (vm_info->shdw_pg_mode == SHADOW_PAGING) {
     PrintDebug("Creating initial shadow page table\n");
-    vm_info->direct_map_pt = (addr_t)create_passthrough_pde32_pts(vm_info);
-    vm_info->shdw_pg_state.shadow_cr3 |= (vm_info->direct_map_pt & ~0xfff);
+
+
+
+    /* Testing 64 bit page tables for long paged real mode guests */
+    //    vm_info->direct_map_pt = (addr_t)V3_PAddr(create_passthrough_pts_64(vm_info));
+    vm_info->direct_map_pt = (addr_t)V3_PAddr(create_passthrough_pts_32(vm_info));
+    /* End Test */
+
+    //vm_info->shdw_pg_state.shadow_cr3 |= (vm_info->direct_map_pt & ~0xfff);
+    vm_info->shdw_pg_state.shadow_cr3 = 0;
     vm_info->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
     PrintDebug("Created\n");
 
-    guest_state->cr3 = vm_info->shdw_pg_state.shadow_cr3;
+    //guest_state->cr3 = vm_info->shdw_pg_state.shadow_cr3;
+
+    guest_state->cr3 = vm_info->direct_map_pt;
+
 
     //PrintDebugPageTables((pde32_t*)(vm_info->shdw_pg_state.shadow_cr3.e_reg.low));
 
@@ -242,10 +257,10 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) {
     // Enable Nested Paging
     ctrl_area->NP_ENABLE = 1;
 
-    PrintDebug("NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
+    PrintDebug("NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE));
 
     // Set the Nested Page Table pointer
-    vm_info->direct_map_pt = ((addr_t)create_passthrough_pde32_pts(vm_info) & ~0xfff);
+    vm_info->direct_map_pt = ((addr_t)create_passthrough_pts_32(vm_info) & ~0xfff);
     ctrl_area->N_CR3 = vm_info->direct_map_pt;
 
     //   ctrl_area->N_CR3 = Get_CR3();
@@ -272,7 +287,7 @@ static int init_svm_guest(struct guest_info *info) {
   //  PrintDebugPageTables(info->page_tables);
 
 
-  PrintDebug("Initializing VMCB (addr=%x)\n", info->vmm_data);
+  PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
   Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
   
 
@@ -295,47 +310,62 @@ static int init_svm_guest(struct guest_info *info) {
 
 
 // can we start a kernel thread here...
- int start_svm_guest(struct guest_info *info) {
+static int start_svm_guest(struct guest_info *info) {
   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
   vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
   uint_t num_exits = 0;
 
 
 
-  PrintDebug("Launching SVM VM (vmcb=%x)\n", info->vmm_data);
+  PrintDebug("Launching SVM VM (vmcb=%p)\n", (void *)info->vmm_data);
   //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
 
   info->run_state = VM_RUNNING;
 
   while (1) {
     ullong_t tmp_tsc;
+    uint_t vm_cr_low = 0, vm_cr_high = 0;
+
+
+    v3_enable_ints();
+    v3_clgi();
 
 
-    EnableInts();
-    CLGI();
+    //PrintDebug("SVM Entry to rip=%p...\n", (void *)info->rip);
 
-    //    PrintDebug("SVM Entry to rip=%x...\n", info->rip);
+    v3_get_msr(0xc0000101, &vm_cr_high, &vm_cr_low);
 
     rdtscll(info->time_state.cached_host_tsc);
-    guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
 
-    safe_svm_launch((vmcb_t*)(info->vmm_data), &(info->vm_regs));
+    guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
 
+    v3_svm_launch((vmcb_t*)V3_PAddr(info->vmm_data), &(info->vm_regs));
     rdtscll(tmp_tsc);
+
+    v3_set_msr(0xc0000101, vm_cr_high, vm_cr_low);
     //PrintDebug("SVM Returned\n");
 
 
+#if PrintDebug
+    {
+      uint_t x = 0;
+      PrintDebug("RSP=%p\n", (void *)&x);
+    }
+#endif
+
+
     v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
     num_exits++;
 
-    STGI();
+    //PrintDebug("Turning on global interrupts\n");
+    v3_stgi();
+
+
+    //PrintDebug("SVM Exit number %d\n", num_exits);
 
-    if ((num_exits % 25) == 0) {
-      PrintDebug("SVM Exit number %d\n", num_exits);
-    }
 
      
-    if (handle_svm_exit(info) != 0) {
+    if (v3_handle_svm_exit(info) != 0) {
 
       addr_t host_addr;
       addr_t linear_addr = 0;
@@ -344,27 +374,27 @@ static int init_svm_guest(struct guest_info *info) {
 
       PrintDebug("SVM ERROR!!\n"); 
       
-      PrintDebug("RIP: %x\n", guest_state->rip);
+      PrintDebug("RIP: %p\n", (void *)(addr_t)(guest_state->rip));
 
 
       linear_addr = get_addr_linear(info, guest_state->rip, &(info->segments.cs));
 
 
-      PrintDebug("RIP Linear: %x\n", linear_addr);
-      PrintV3Segments(info);
-      PrintV3CtrlRegs(info);
-      PrintV3GPRs(info);
+      PrintDebug("RIP Linear: %p\n", (void *)linear_addr);
+      v3_print_segments(info);
+      v3_print_ctrl_regs(info);
+      v3_print_GPRs(info);
       
       if (info->mem_mode == PHYSICAL_MEM) {
-       guest_pa_to_host_pa(info, linear_addr, &host_addr);
+       guest_pa_to_host_va(info, linear_addr, &host_addr);
       } else if (info->mem_mode == VIRTUAL_MEM) {
-       guest_va_to_host_pa(info, linear_addr, &host_addr);
+       guest_va_to_host_va(info, linear_addr, &host_addr);
       }
 
 
-      PrintDebug("Host Address of rip = 0x%x\n", host_addr);
+      PrintDebug("Host Address of rip = 0x%p\n", (void *)host_addr);
 
-      PrintDebug("Instr (15 bytes) at %x:\n", host_addr);
+      PrintDebug("Instr (15 bytes) at %p:\n", (void *)host_addr);
       PrintTraceMemDump((uchar_t *)host_addr, 15);
 
       break;
@@ -379,35 +409,33 @@ static int init_svm_guest(struct guest_info *info) {
 
 /* Checks machine SVM capability */
 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
-int is_svm_capable() {
+int v3_is_svm_capable() {
 
 #if 1
   // Dinda
-
-  uint_t ret;
   uint_t vm_cr_low = 0, vm_cr_high = 0;
+  addr_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
-
-  ret =  cpuid_ecx(CPUID_FEATURE_IDS);
+  v3_cpuid(CPUID_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
   
-  PrintDebug("CPUID_FEATURE_IDS_ecx=0x%x\n",ret);
+  PrintDebug("CPUID_FEATURE_IDS_ecx=0x%p\n", (void *)ecx);
 
-  if ((ret & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) {
+  if ((ecx & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) {
     PrintDebug("SVM Not Available\n");
     return 0;
   }  else {
-    Get_MSR(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
+    v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
     
-    PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n",vm_cr_high,vm_cr_low);
+    PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
     
     if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
       PrintDebug("SVM is available but is disabled.\n");
 
-      ret = cpuid_edx(CPUID_SVM_REV_AND_FEATURE_IDS);
+      v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
       
-      PrintDebug("CPUID_FEATURE_IDS_edx=0x%x\n",ret);
+      PrintDebug("CPUID_FEATURE_IDS_edx=0x%p\n", (void *)edx);
       
-      if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
+      if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
        PrintDebug("SVM BIOS Disabled, not unlockable\n");
       } else {
        PrintDebug("SVM is locked with a key\n");
@@ -417,11 +445,11 @@ int is_svm_capable() {
     } else {
       PrintDebug("SVM is available and  enabled.\n");
 
-      ret = cpuid_edx(CPUID_SVM_REV_AND_FEATURE_IDS);
+      v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
       
-      PrintDebug("CPUID_FEATURE_IDS_edx=0x%x\n",ret);
+      PrintDebug("CPUID_FEATURE_IDS_edx=0x%p\n", (void *)edx);
 
-      if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
+      if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
        PrintDebug("SVM Nested Paging not supported\n");
       } else {
        PrintDebug("SVM Nested Paging supported\n");
@@ -433,24 +461,24 @@ int is_svm_capable() {
   }
 
 #else
+  uint_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+  addr_t vm_cr_low = 0, vm_cr_high = 0;
 
-  uint_t ret =  cpuid_ecx(CPUID_FEATURE_IDS);
-  uint_t vm_cr_low = 0, vm_cr_high = 0;
-
+  v3_cpuid(CPUID_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
 
-  if ((ret & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) {
+  if ((ecx & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) {
     PrintDebug("SVM Not Available\n");
     return 0;
   } 
 
-  Get_MSR(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
+  v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
 
-  PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n",vm_cr_high,vm_cr_low);
+  PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
 
 
   // this part is clearly wrong, since the np bit is in 
   // edx, not ecx
-  if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 1) {
+  if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 1) {
     PrintDebug("Nested Paging not supported\n");
   } else {
     PrintDebug("Nested Paging supported\n");
@@ -461,9 +489,9 @@ int is_svm_capable() {
     return 1;
   }
 
-  ret = cpuid_edx(CPUID_SVM_REV_AND_FEATURE_IDS);
+  v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
 
-  if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
+  if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
     PrintDebug("SVM BIOS Disabled, not unlockable\n");
   } else {
     PrintDebug("SVM is locked with a key\n");
@@ -475,14 +503,14 @@ int is_svm_capable() {
 
 }
 
-int has_svm_nested_paging() {
-  uint32_t ret;
+static int has_svm_nested_paging() {
+  addr_t eax = 0, ebx = 0, ecx = 0, edx = 0;
 
-  ret = cpuid_edx(CPUID_SVM_REV_AND_FEATURE_IDS);
+  v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
       
-  //PrintDebug("CPUID_FEATURE_IDS_edx=0x%x\n",ret);
+  //PrintDebug("CPUID_FEATURE_IDS_edx=0x%x\n", edx);
   
-  if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
+  if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
     PrintDebug("SVM Nested Paging not supported\n");
     return 0;
   } else {
@@ -494,15 +522,15 @@ int has_svm_nested_paging() {
 
 
 
-void Init_SVM(struct vmm_ctrl_ops * vmm_ops) {
+void v3_init_SVM(struct v3_ctrl_ops * vmm_ops) {
   reg_ex_t msr;
   void * host_state;
 
 
   // Enable SVM on the CPU
-  Get_MSR(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
+  v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
   msr.e_reg.low |= EFER_MSR_svm_enable;
-  Set_MSR(EFER_MSR, 0, msr.e_reg.low);
+  v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
   
   PrintDebug("SVM Enabled\n");
 
@@ -516,8 +544,8 @@ void Init_SVM(struct vmm_ctrl_ops * vmm_ops) {
   //msr.e_reg.low = (uint_t)host_state;
   msr.r_reg = (addr_t)host_state;
 
-  PrintDebug("Host State being saved at %x\n", (addr_t)host_state);
-  Set_MSR(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
+  PrintDebug("Host State being saved at %p\n", (void *)(addr_t)host_state);
+  v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
 
 
 
@@ -662,7 +690,7 @@ void Init_SVM(struct vmm_ctrl_ops * vmm_ops) {
 
   if (vm_info.page_mode == SHADOW_PAGING) {
     PrintDebug("Creating initial shadow page table\n");
-    vm_info.shdw_pg_state.shadow_cr3 |= ((addr_t)create_passthrough_pde32_pts(&vm_info) & ~0xfff);
+    vm_info.shdw_pg_state.shadow_cr3 |= ((addr_t)create_passthrough_pts_32(&vm_info) & ~0xfff);
     PrintDebug("Created\n");
 
     guest_state->cr3 = vm_info.shdw_pg_state.shadow_cr3;
index 68261c3..5316edc 100644 (file)
 #include <palacios/vmm_intr.h>
 
 
+#ifndef DEBUG_HALT
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+
 
 //
 // This should trigger a #GP if cpl!=0, otherwise, yield to host
 //
 
-int handle_svm_halt(struct guest_info * info)
+int v3_handle_svm_halt(struct guest_info * info)
 {
   if (info->cpl!=0) { 
     v3_raise_exception(info, GPF_EXCEPTION);
index 159cb53..23546e2 100644 (file)
 #include <palacios/vmm_intr.h>
 #include <palacios/vmm_emulator.h>
 
-int handle_svm_exit(struct guest_info * info) {
+
+
+
+static const uchar_t * vmexit_code_to_str(uint_t exit_code);
+
+
+int v3_handle_svm_exit(struct guest_info * info) {
   vmcb_ctrl_t * guest_ctrl = 0;
   vmcb_saved_state_t * guest_state = 0;
   ulong_t exit_code = 0;
@@ -58,8 +64,8 @@ int handle_svm_exit(struct guest_info * info) {
   info->ctrl_regs.efer = guest_state->efer;
 
   get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
-  info->cpu_mode = get_cpu_mode(info);
-  info->mem_mode = get_mem_mode(info);
+  info->cpu_mode = v3_get_cpu_mode(info);
+  info->mem_mode = v3_get_mem_mode(info);
 
 
   exit_code = guest_ctrl->exit_code;
@@ -77,7 +83,7 @@ int handle_svm_exit(struct guest_info * info) {
     // Dump out the instr stream
 
     //PrintDebug("RIP: %x\n", guest_state->rip);
-    PrintDebug("RIP Linear: %x\n", get_addr_linear(info, info->rip, &(info->segments.cs)));
+    PrintDebug("RIP Linear: %p\n", (void *)get_addr_linear(info, info->rip, &(info->segments.cs)));
 
     // OK, now we will read the instruction
     // The only difference between PROTECTED and PROTECTED_PG is whether we read
@@ -117,21 +123,21 @@ int handle_svm_exit(struct guest_info * info) {
     
     if (io_info->type == 0) {
       if (io_info->str) {
-       if (handle_svm_io_outs(info) == -1 ) {
+       if (v3_handle_svm_io_outs(info) == -1 ) {
          return -1;
        }
       } else {
-       if (handle_svm_io_out(info) == -1) {
+       if (v3_handle_svm_io_out(info) == -1) {
          return -1;
        }
       }
     } else {
       if (io_info->str) {
-       if (handle_svm_io_ins(info) == -1) {
+       if (v3_handle_svm_io_ins(info) == -1) {
          return -1;
        }
       } else {
-       if (handle_svm_io_in(info) == -1) {
+       if (v3_handle_svm_io_in(info) == -1) {
          return -1;
        }
       }
@@ -144,7 +150,7 @@ int handle_svm_exit(struct guest_info * info) {
 #ifdef DEBUG_CTRL_REGS
     PrintDebug("CR0 Write\n");
 #endif
-    if (handle_cr0_write(info) == -1) {
+    if (v3_handle_cr0_write(info) == -1) {
       return -1;
     }
   } 
@@ -154,7 +160,7 @@ int handle_svm_exit(struct guest_info * info) {
 #ifdef DEBUG_CTRL_REGS
     PrintDebug("CR0 Read\n");
 #endif
-    if (handle_cr0_read(info) == -1) {
+    if (v3_handle_cr0_read(info) == -1) {
       return -1;
     }
   } 
@@ -164,7 +170,7 @@ int handle_svm_exit(struct guest_info * info) {
 #ifdef DEBUG_CTRL_REGS
     PrintDebug("CR3 Write\n");
 #endif
-    if (handle_cr3_write(info) == -1) {
+    if (v3_handle_cr3_write(info) == -1) {
       return -1;
     }    
   } 
@@ -174,7 +180,7 @@ int handle_svm_exit(struct guest_info * info) {
 #ifdef DEBUG_CTRL_REGS
     PrintDebug("CR3 Read\n");
 #endif
-    if (handle_cr3_read(info) == -1) {
+    if (v3_handle_cr3_read(info) == -1) {
       return -1;
     }
   }
@@ -184,10 +190,11 @@ int handle_svm_exit(struct guest_info * info) {
     addr_t fault_addr = guest_ctrl->exit_info2;
     pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
 #ifdef DEBUG_SHADOW_PAGING
-    PrintDebug("PageFault at %x (error=%d)\n", fault_addr, *error_code);
+    PrintDebug("PageFault at %p (error=%d)\n", 
+              (void *)fault_addr, *(uint_t *)error_code);
 #endif
     if (info->shdw_pg_mode == SHADOW_PAGING) {
-      if (handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
+      if (v3_handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
        return -1;
       }
     } else {
@@ -209,7 +216,7 @@ int handle_svm_exit(struct guest_info * info) {
 #ifdef DEBUG_SHADOW_PAGING
       PrintDebug("Invlpg\n");
 #endif
-      if (handle_shadow_invlpg(info) == -1) {
+      if (v3_handle_shadow_invlpg(info) == -1) {
        return -1;
       }
     }
@@ -223,7 +230,7 @@ int handle_svm_exit(struct guest_info * info) {
 
   case VMEXIT_INTR: { 
     
-    //    handle_svm_intr(info); // handled by interrupt dispatch earlier
+    // handled by interrupt dispatch earlier
 
   } 
     break;
@@ -236,16 +243,18 @@ int handle_svm_exit(struct guest_info * info) {
     break;
 
   case VMEXIT_HLT: {
+#ifdef DEBUG_HALT
     PrintDebug("Guest halted\n");
-    if (handle_svm_halt(info) == -1) {
+#endif
+    if (v3_handle_svm_halt(info) == -1) {
       return -1;
     }
   } 
     break;
 
   case VMEXIT_PAUSE: {
-    PrintDebug("Guest paused\n");
-    if (handle_svm_pause(info) == -1) { 
+    //PrintDebug("Guest paused\n");
+    if (v3_handle_svm_pause(info) == -1) { 
       return -1;
     }
   } 
@@ -306,7 +315,7 @@ int handle_svm_exit(struct guest_info * info) {
 #ifdef DEBUG_EMULATOR
       PrintDebug("WBINVD\n");
 #endif
-      if (!handle_svm_wbinvd(info)) { 
+      if (!v3_handle_svm_wbinvd(info)) { 
        return -1;
       }
       break;
@@ -329,11 +338,11 @@ int handle_svm_exit(struct guest_info * info) {
     rip_addr = get_addr_linear(info, guest_state->rip, &(info->segments.cs));
 
 
-    PrintError("SVM Returned:(VMCB=%x)\n", info->vmm_data); 
-    PrintError("RIP: %x\n", guest_state->rip);
-    PrintError("RIP Linear: %x\n", rip_addr);
+    PrintError("SVM Returned:(VMCB=%p)\n", (void *)(info->vmm_data)); 
+    PrintError("RIP: %p\n", (void *)(addr_t)(guest_state->rip));
+    PrintError("RIP Linear: %p\n", (void *)(addr_t)(rip_addr));
     
-    PrintError("SVM Returned: Exit Code: %x\n", exit_code); 
+    PrintError("SVM Returned: Exit Code: %p\n", (void *)(addr_t)exit_code); 
     
     PrintError("io_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
     PrintError("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
@@ -344,12 +353,12 @@ int handle_svm_exit(struct guest_info * info) {
     
 
     if (info->mem_mode == PHYSICAL_MEM) {
-      if (guest_pa_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
+      if (guest_pa_to_host_va(info, guest_state->rip, &host_addr) == -1) {
        PrintError("Could not translate guest_state->rip to host address\n");
        return -1;
       }
     } else if (info->mem_mode == VIRTUAL_MEM) {
-      if (guest_va_to_host_pa(info, guest_state->rip, &host_addr) == -1) {
+      if (guest_va_to_host_va(info, guest_state->rip, &host_addr) == -1) {
        PrintError("Could not translate guest_state->rip to host address\n");
        return -1;
       }
@@ -358,16 +367,16 @@ int handle_svm_exit(struct guest_info * info) {
       return -1;
     }
     
-    PrintError("Host Address of rip = 0x%x\n", host_addr);
+    PrintError("Host Address of rip = 0x%p\n", (void *)host_addr);
     
     memset(buf, 0, 32);
     
-    PrintError("Reading instruction stream in guest\n", rip_addr);
+    PrintError("Reading instruction stream in guest (addr=%p)\n", (void *)rip_addr);
     
     if (info->mem_mode == PHYSICAL_MEM) {
-      read_guest_pa_memory(info, rip_addr-16, 32, buf);
+      read_guest_pa_memory(info, rip_addr - 16, 32, buf);
     } else {
-      read_guest_va_memory(info, rip_addr-16, 32, buf);
+      read_guest_va_memory(info, rip_addr - 16, 32, buf);
     }
     
     PrintDebug("16 bytes before Rip\n");
@@ -386,12 +395,12 @@ int handle_svm_exit(struct guest_info * info) {
 
   // Update the low level state
 
-  if (intr_pending(info)) {
+  if (v3_intr_pending(info)) {
 
-    switch (get_intr_type(info)) {
+    switch (v3_get_intr_type(info)) {
     case EXTERNAL_IRQ: 
       {
-       uint_t irq = get_intr_number(info);
+       uint_t irq = v3_get_intr_number(info);
 
         // check to see if ==-1 (non exists)
 
@@ -406,9 +415,11 @@ int handle_svm_exit(struct guest_info * info) {
        guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
        guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
 #ifdef DEBUG_INTERRUPTS
-       PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->guest_ctrl.V_INTR_VECTOR, info->rip);
+       PrintDebug("Injecting Interrupt %d (EIP=%p)\n", 
+                  guest_ctrl->guest_ctrl.V_INTR_VECTOR, 
+                  (void *)info->rip);
 #endif
-       injecting_intr(info, irq, EXTERNAL_IRQ);
+       v3_injecting_intr(info, irq, EXTERNAL_IRQ);
        
        break;
       }
@@ -417,7 +428,7 @@ int handle_svm_exit(struct guest_info * info) {
       break;
     case EXCEPTION:
       {
-       uint_t excp = get_intr_number(info);
+       uint_t excp = v3_get_intr_number(info);
 
        guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
        
@@ -433,9 +444,11 @@ int handle_svm_exit(struct guest_info * info) {
        
        guest_ctrl->EVENTINJ.valid = 1;
 #ifdef DEBUG_INTERRUPTS
-       PrintDebug("Injecting Interrupt %d (EIP=%x)\n", guest_ctrl->EVENTINJ.vector, info->rip);
+       PrintDebug("Injecting Interrupt %d (EIP=%p)\n", 
+                  guest_ctrl->EVENTINJ.vector, 
+                  (void *)info->rip);
 #endif
-       injecting_intr(info, excp, EXCEPTION);
+       v3_injecting_intr(info, excp, EXCEPTION);
        break;
       }
     case SOFTWARE_INTR:
@@ -484,6 +497,150 @@ int handle_svm_exit(struct guest_info * info) {
 }
 
 
+static const uchar_t VMEXIT_CR0_READ_STR[] = "VMEXIT_CR0_READ";
+static const uchar_t VMEXIT_CR1_READ_STR[] = "VMEXIT_CR1_READ";
+static const uchar_t VMEXIT_CR2_READ_STR[] = "VMEXIT_CR2_READ";
+static const uchar_t VMEXIT_CR3_READ_STR[] = "VMEXIT_CR3_READ";
+static const uchar_t VMEXIT_CR4_READ_STR[] = "VMEXIT_CR4_READ";
+static const uchar_t VMEXIT_CR5_READ_STR[] = "VMEXIT_CR5_READ";
+static const uchar_t VMEXIT_CR6_READ_STR[] = "VMEXIT_CR6_READ";
+static const uchar_t VMEXIT_CR7_READ_STR[] = "VMEXIT_CR7_READ";
+static const uchar_t VMEXIT_CR8_READ_STR[] = "VMEXIT_CR8_READ";
+static const uchar_t VMEXIT_CR9_READ_STR[] = "VMEXIT_CR9_READ";
+static const uchar_t VMEXIT_CR10_READ_STR[] = "VMEXIT_CR10_READ";
+static const uchar_t VMEXIT_CR11_READ_STR[] = "VMEXIT_CR11_READ";
+static const uchar_t VMEXIT_CR12_READ_STR[] = "VMEXIT_CR12_READ";
+static const uchar_t VMEXIT_CR13_READ_STR[] = "VMEXIT_CR13_READ";
+static const uchar_t VMEXIT_CR14_READ_STR[] = "VMEXIT_CR14_READ";
+static const uchar_t VMEXIT_CR15_READ_STR[] = "VMEXIT_CR15_READ";
+static const uchar_t VMEXIT_CR0_WRITE_STR[] = "VMEXIT_CR0_WRITE";
+static const uchar_t VMEXIT_CR1_WRITE_STR[] = "VMEXIT_CR1_WRITE";
+static const uchar_t VMEXIT_CR2_WRITE_STR[] = "VMEXIT_CR2_WRITE";
+static const uchar_t VMEXIT_CR3_WRITE_STR[] = "VMEXIT_CR3_WRITE";
+static const uchar_t VMEXIT_CR4_WRITE_STR[] = "VMEXIT_CR4_WRITE";
+static const uchar_t VMEXIT_CR5_WRITE_STR[] = "VMEXIT_CR5_WRITE";
+static const uchar_t VMEXIT_CR6_WRITE_STR[] = "VMEXIT_CR6_WRITE";
+static const uchar_t VMEXIT_CR7_WRITE_STR[] = "VMEXIT_CR7_WRITE";
+static const uchar_t VMEXIT_CR8_WRITE_STR[] = "VMEXIT_CR8_WRITE";
+static const uchar_t VMEXIT_CR9_WRITE_STR[] = "VMEXIT_CR9_WRITE";
+static const uchar_t VMEXIT_CR10_WRITE_STR[] = "VMEXIT_CR10_WRITE";
+static const uchar_t VMEXIT_CR11_WRITE_STR[] = "VMEXIT_CR11_WRITE";
+static const uchar_t VMEXIT_CR12_WRITE_STR[] = "VMEXIT_CR12_WRITE";
+static const uchar_t VMEXIT_CR13_WRITE_STR[] = "VMEXIT_CR13_WRITE";
+static const uchar_t VMEXIT_CR14_WRITE_STR[] = "VMEXIT_CR14_WRITE";
+static const uchar_t VMEXIT_CR15_WRITE_STR[] = "VMEXIT_CR15_WRITE";
+static const uchar_t VMEXIT_DR0_READ_STR[] = "VMEXIT_DR0_READ";
+static const uchar_t VMEXIT_DR1_READ_STR[] = "VMEXIT_DR1_READ";
+static const uchar_t VMEXIT_DR2_READ_STR[] = "VMEXIT_DR2_READ";
+static const uchar_t VMEXIT_DR3_READ_STR[] = "VMEXIT_DR3_READ";
+static const uchar_t VMEXIT_DR4_READ_STR[] = "VMEXIT_DR4_READ";
+static const uchar_t VMEXIT_DR5_READ_STR[] = "VMEXIT_DR5_READ";
+static const uchar_t VMEXIT_DR6_READ_STR[] = "VMEXIT_DR6_READ";
+static const uchar_t VMEXIT_DR7_READ_STR[] = "VMEXIT_DR7_READ";
+static const uchar_t VMEXIT_DR8_READ_STR[] = "VMEXIT_DR8_READ";
+static const uchar_t VMEXIT_DR9_READ_STR[] = "VMEXIT_DR9_READ";
+static const uchar_t VMEXIT_DR10_READ_STR[] = "VMEXIT_DR10_READ";
+static const uchar_t VMEXIT_DR11_READ_STR[] = "VMEXIT_DR11_READ";
+static const uchar_t VMEXIT_DR12_READ_STR[] = "VMEXIT_DR12_READ";
+static const uchar_t VMEXIT_DR13_READ_STR[] = "VMEXIT_DR13_READ";
+static const uchar_t VMEXIT_DR14_READ_STR[] = "VMEXIT_DR14_READ";
+static const uchar_t VMEXIT_DR15_READ_STR[] = "VMEXIT_DR15_READ";
+static const uchar_t VMEXIT_DR0_WRITE_STR[] = "VMEXIT_DR0_WRITE";
+static const uchar_t VMEXIT_DR1_WRITE_STR[] = "VMEXIT_DR1_WRITE";
+static const uchar_t VMEXIT_DR2_WRITE_STR[] = "VMEXIT_DR2_WRITE";
+static const uchar_t VMEXIT_DR3_WRITE_STR[] = "VMEXIT_DR3_WRITE";
+static const uchar_t VMEXIT_DR4_WRITE_STR[] = "VMEXIT_DR4_WRITE";
+static const uchar_t VMEXIT_DR5_WRITE_STR[] = "VMEXIT_DR5_WRITE";
+static const uchar_t VMEXIT_DR6_WRITE_STR[] = "VMEXIT_DR6_WRITE";
+static const uchar_t VMEXIT_DR7_WRITE_STR[] = "VMEXIT_DR7_WRITE";
+static const uchar_t VMEXIT_DR8_WRITE_STR[] = "VMEXIT_DR8_WRITE";
+static const uchar_t VMEXIT_DR9_WRITE_STR[] = "VMEXIT_DR9_WRITE";
+static const uchar_t VMEXIT_DR10_WRITE_STR[] = "VMEXIT_DR10_WRITE";
+static const uchar_t VMEXIT_DR11_WRITE_STR[] = "VMEXIT_DR11_WRITE";
+static const uchar_t VMEXIT_DR12_WRITE_STR[] = "VMEXIT_DR12_WRITE";
+static const uchar_t VMEXIT_DR13_WRITE_STR[] = "VMEXIT_DR13_WRITE";
+static const uchar_t VMEXIT_DR14_WRITE_STR[] = "VMEXIT_DR14_WRITE";
+static const uchar_t VMEXIT_DR15_WRITE_STR[] = "VMEXIT_DR15_WRITE";
+static const uchar_t VMEXIT_EXCP0_STR[] = "VMEXIT_EXCP0";
+static const uchar_t VMEXIT_EXCP1_STR[] = "VMEXIT_EXCP1";
+static const uchar_t VMEXIT_EXCP2_STR[] = "VMEXIT_EXCP2";
+static const uchar_t VMEXIT_EXCP3_STR[] = "VMEXIT_EXCP3";
+static const uchar_t VMEXIT_EXCP4_STR[] = "VMEXIT_EXCP4";
+static const uchar_t VMEXIT_EXCP5_STR[] = "VMEXIT_EXCP5";
+static const uchar_t VMEXIT_EXCP6_STR[] = "VMEXIT_EXCP6";
+static const uchar_t VMEXIT_EXCP7_STR[] = "VMEXIT_EXCP7";
+static const uchar_t VMEXIT_EXCP8_STR[] = "VMEXIT_EXCP8";
+static const uchar_t VMEXIT_EXCP9_STR[] = "VMEXIT_EXCP9";
+static const uchar_t VMEXIT_EXCP10_STR[] = "VMEXIT_EXCP10";
+static const uchar_t VMEXIT_EXCP11_STR[] = "VMEXIT_EXCP11";
+static const uchar_t VMEXIT_EXCP12_STR[] = "VMEXIT_EXCP12";
+static const uchar_t VMEXIT_EXCP13_STR[] = "VMEXIT_EXCP13";
+static const uchar_t VMEXIT_EXCP14_STR[] = "VMEXIT_EXCP14";
+static const uchar_t VMEXIT_EXCP15_STR[] = "VMEXIT_EXCP15";
+static const uchar_t VMEXIT_EXCP16_STR[] = "VMEXIT_EXCP16";
+static const uchar_t VMEXIT_EXCP17_STR[] = "VMEXIT_EXCP17";
+static const uchar_t VMEXIT_EXCP18_STR[] = "VMEXIT_EXCP18";
+static const uchar_t VMEXIT_EXCP19_STR[] = "VMEXIT_EXCP19";
+static const uchar_t VMEXIT_EXCP20_STR[] = "VMEXIT_EXCP20";
+static const uchar_t VMEXIT_EXCP21_STR[] = "VMEXIT_EXCP21";
+static const uchar_t VMEXIT_EXCP22_STR[] = "VMEXIT_EXCP22";
+static const uchar_t VMEXIT_EXCP23_STR[] = "VMEXIT_EXCP23";
+static const uchar_t VMEXIT_EXCP24_STR[] = "VMEXIT_EXCP24";
+static const uchar_t VMEXIT_EXCP25_STR[] = "VMEXIT_EXCP25";
+static const uchar_t VMEXIT_EXCP26_STR[] = "VMEXIT_EXCP26";
+static const uchar_t VMEXIT_EXCP27_STR[] = "VMEXIT_EXCP27";
+static const uchar_t VMEXIT_EXCP28_STR[] = "VMEXIT_EXCP28";
+static const uchar_t VMEXIT_EXCP29_STR[] = "VMEXIT_EXCP29";
+static const uchar_t VMEXIT_EXCP30_STR[] = "VMEXIT_EXCP30";
+static const uchar_t VMEXIT_EXCP31_STR[] = "VMEXIT_EXCP31";
+static const uchar_t VMEXIT_INTR_STR[] = "VMEXIT_INTR";
+static const uchar_t VMEXIT_NMI_STR[] = "VMEXIT_NMI";
+static const uchar_t VMEXIT_SMI_STR[] = "VMEXIT_SMI";
+static const uchar_t VMEXIT_INIT_STR[] = "VMEXIT_INIT";
+static const uchar_t VMEXIT_VINITR_STR[] = "VMEXIT_VINITR";
+static const uchar_t VMEXIT_CR0_SEL_WRITE_STR[] = "VMEXIT_CR0_SEL_WRITE";
+static const uchar_t VMEXIT_IDTR_READ_STR[] = "VMEXIT_IDTR_READ";
+static const uchar_t VMEXIT_GDTR_READ_STR[] = "VMEXIT_GDTR_READ";
+static const uchar_t VMEXIT_LDTR_READ_STR[] = "VMEXIT_LDTR_READ";
+static const uchar_t VMEXIT_TR_READ_STR[] = "VMEXIT_TR_READ";
+static const uchar_t VMEXIT_IDTR_WRITE_STR[] = "VMEXIT_IDTR_WRITE";
+static const uchar_t VMEXIT_GDTR_WRITE_STR[] = "VMEXIT_GDTR_WRITE";
+static const uchar_t VMEXIT_LDTR_WRITE_STR[] = "VMEXIT_LDTR_WRITE";
+static const uchar_t VMEXIT_TR_WRITE_STR[] = "VMEXIT_TR_WRITE";
+static const uchar_t VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
+static const uchar_t VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
+static const uchar_t VMEXIT_PUSHF_STR[] = "VMEXIT_PUSHF";
+static const uchar_t VMEXIT_POPF_STR[] = "VMEXIT_POPF";
+static const uchar_t VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
+static const uchar_t VMEXIT_RSM_STR[] = "VMEXIT_RSM";
+static const uchar_t VMEXIT_IRET_STR[] = "VMEXIT_IRET";
+static const uchar_t VMEXIT_SWINT_STR[] = "VMEXIT_SWINT";
+static const uchar_t VMEXIT_INVD_STR[] = "VMEXIT_INVD";
+static const uchar_t VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
+static const uchar_t VMEXIT_HLT_STR[] = "VMEXIT_HLT";
+static const uchar_t VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
+static const uchar_t VMEXIT_INVLPGA_STR[] = "VMEXIT_INVLPGA";
+static const uchar_t VMEXIT_IOIO_STR[] = "VMEXIT_IOIO";
+static const uchar_t VMEXIT_MSR_STR[] = "VMEXIT_MSR";
+static const uchar_t VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
+static const uchar_t VMEXIT_FERR_FREEZE_STR[] = "VMEXIT_FERR_FREEZE";
+static const uchar_t VMEXIT_SHUTDOWN_STR[] = "VMEXIT_SHUTDOWN";
+static const uchar_t VMEXIT_VMRUN_STR[] = "VMEXIT_VMRUN";
+static const uchar_t VMEXIT_VMMCALL_STR[] = "VMEXIT_VMMCALL";
+static const uchar_t VMEXIT_VMLOAD_STR[] = "VMEXIT_VMLOAD";
+static const uchar_t VMEXIT_VMSAVE_STR[] = "VMEXIT_VMSAVE";
+static const uchar_t VMEXIT_STGI_STR[] = "VMEXIT_STGI";
+static const uchar_t VMEXIT_CLGI_STR[] = "VMEXIT_CLGI";
+static const uchar_t VMEXIT_SKINIT_STR[] = "VMEXIT_SKINIT";
+static const uchar_t VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
+static const uchar_t VMEXIT_ICEBP_STR[] = "VMEXIT_ICEBP";
+static const uchar_t VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
+static const uchar_t VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
+static const uchar_t VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
+static const uchar_t VMEXIT_MWAIT_CONDITIONAL_STR[] = "VMEXIT_MWAIT_CONDITIONAL";
+static const uchar_t VMEXIT_NPF_STR[] = "VMEXIT_NPF";
+static const uchar_t VMEXIT_INVALID_VMCB_STR[] = "VMEXIT_INVALID_VMCB";
+
 
 
 const uchar_t * vmexit_code_to_str(uint_t exit_code) {
index 63a5603..d4af89f 100644 (file)
 #endif
 
 
+
+
+
 // This should package up an IO request and call vmm_handle_io
-int handle_svm_io_in(struct guest_info * info) {
+int v3_handle_svm_io_in(struct guest_info * info) {
   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
 
   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
-  uint_t read_size = 0;
+  int read_size = 0;
 
   if (hook == NULL) {
     PrintError("Hook Not present for in on port %x\n", io_info->port);
@@ -76,14 +79,14 @@ int handle_svm_io_in(struct guest_info * info) {
 /* We might not handle wrap around of the RDI register correctly...
  * In that if we do wrap around the effect will manifest in the higher bits of the register
  */
-int handle_svm_io_ins(struct guest_info * info) {
+int v3_handle_svm_io_ins(struct guest_info * info) {
   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
   
   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
   
   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
-  uint_t read_size = 0;
+  int read_size = 0;
 
   addr_t dst_addr = 0;
   uint_t rep_num = 1;
@@ -111,7 +114,7 @@ int handle_svm_io_ins(struct guest_info * info) {
   
   addr_t inst_ptr;
 
-  if (guest_va_to_host_pa(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
+  if (guest_va_to_host_va(info, get_addr_linear(info, info->rip, &(info->segments.cs)), &inst_ptr) == -1) {
     PrintError("Can't access instruction\n");
     return -1;
   }
@@ -167,7 +170,8 @@ int handle_svm_io_ins(struct guest_info * info) {
     // This value should be set depending on the host register size...
     mask = get_gpr_mask(info);
 
-    PrintDebug("INS io_info invalid address size, mask=0x%x, io_info=0x%x\n",mask,*((uint_t*)(io_info)));
+    PrintDebug("INS io_info invalid address size, mask=0x%p, io_info=0x%p\n",
+              (void *)mask, (void *)(io_info));
     // PrintDebug("INS Aborted... Check implementation\n");
     //return -1;
   }
@@ -184,7 +188,7 @@ int handle_svm_io_ins(struct guest_info * info) {
     addr_t host_addr;
     dst_addr = get_addr_linear(info, info->vm_regs.rdi & mask, theseg);
     
-    PrintDebug("Writing 0x%x\n", dst_addr);
+    PrintDebug("Writing 0x%p\n", (void *)dst_addr);
 
     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
       // either page fault or gpf...
@@ -212,13 +216,13 @@ int handle_svm_io_ins(struct guest_info * info) {
   return 0;
 }
 
-int handle_svm_io_out(struct guest_info * info) {
+int v3_handle_svm_io_out(struct guest_info * info) {
   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
 
   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
-  uint_t write_size = 0;
+  int write_size = 0;
 
   if (hook == NULL) {
     PrintError("Hook Not present for out on port %x\n", io_info->port);
@@ -253,7 +257,7 @@ int handle_svm_io_out(struct guest_info * info) {
  * In that if we do wrap around the effect will manifest in the higher bits of the register
  */
 
-int handle_svm_io_outs(struct guest_info * info) {
+int v3_handle_svm_io_outs(struct guest_info * info) {
   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
 
@@ -261,7 +265,7 @@ int handle_svm_io_outs(struct guest_info * info) {
   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
   
   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
-  uint_t write_size = 0;
+  int write_size = 0;
 
   addr_t dst_addr = 0;
   uint_t rep_num = 1;
@@ -306,7 +310,8 @@ int handle_svm_io_outs(struct guest_info * info) {
     // This value should be set depending on the host register size...
     mask = get_gpr_mask(info);
 
-    PrintDebug("OUTS io_info invalid address size, mask=0x%, io_info=0x%x\n",mask,*((uint_t*)(io_info)));
+    PrintDebug("OUTS io_info invalid address size, mask=0%p, io_info=0x%p\n",
+              (void *)mask, (void *)io_info);
     // PrintDebug("INS Aborted... Check implementation\n");
     //return -1;
     // should never happen
@@ -322,7 +327,7 @@ int handle_svm_io_outs(struct guest_info * info) {
   
   addr_t inst_ptr;
 
-  if (guest_va_to_host_pa(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
+  if (guest_va_to_host_va(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
     PrintError("Can't access instruction\n");
     return -1;
   }
diff --git a/palacios/src/palacios/svm_lowlevel.S b/palacios/src/palacios/svm_lowlevel.S
new file mode 100644 (file)
index 0000000..1e36bc9
--- /dev/null
@@ -0,0 +1,185 @@
+#;  -*- fundamental -*-
+
+
+.text
+.align 4
+
+.globl v3_svm_launch
+.globl v3_stgi
+.globl v3_clgi
+
+#define SVM_ERROR .dword 0xffffffff
+#define SVM_SUCCESS .dword 0x00000000
+
+#define vmrun .byte 0x0f,0x01,0xd8
+#define vmload .byte 0x0F,0x01,0xDA
+#define vmsave .byte 0x0F,0x01,0xDB
+#define stgi   .byte 0x0F,0x01,0xDC
+#define clgi   .byte 0x0F,0x01,0xDD
+
+
+#ifdef __V3_32BIT__
+
+#define Save_SVM_Registers(location)   \
+       pushl   %eax;                   \
+       movl    location, %eax;         \
+       movl    %edi, (%eax);           \
+       movl    %esi, 8(%eax);          \
+       movl    %ebp, 16(%eax);         \
+       movl    $0, 24(%eax);           \
+       movl    %ebx, 32(%eax);         \
+       movl    %edx, 40(%eax);         \
+       movl    %ecx, 48(%eax);         \
+       pushl   %ebx;                   \
+       movl    8(%esp), %ebx;          \
+       movl    %ebx, 56(%eax);         \
+       popl    %ebx;                   \
+       popl    %eax;                   
+       
+
+#define Restore_SVM_Registers(location) \
+       pushl   %eax;                   \
+       movl    location, %eax;         \
+       movl    (%eax), %edi;           \
+       movl    8(%eax), %esi;          \
+       movl    16(%eax), %ebp;         \
+       movl    32(%eax), %ebx;         \
+       movl    40(%eax), %edx;         \
+       movl    48(%eax), %ecx;         \
+       popl    %eax;
+
+
+v3_svm_launch:
+       push    %ebp;
+       movl    %esp, %ebp;
+       pushf;
+       push    %fs;
+       push    %gs;
+       pusha;
+
+       pushl   12(%ebp);
+       pushl   8(%ebp);
+
+       Restore_SVM_Registers(8(%esp));
+       popl    %eax;
+
+       vmload;
+       vmrun;
+       vmsave;
+
+       Save_SVM_Registers(4(%esp));
+
+       addl    $4, %esp;
+
+       popa;
+       pop     %gs;
+       pop     %fs;
+       popf;
+       pop     %ebp;
+       ret
+
+
+
+#elif __V3_64BIT__
+
+#define Save_SVM_Registers(location)   \
+       push    %rax;                   \
+       mov     location, %rax;         \
+       mov     %rdi, (%rax);           \
+       mov     %rsi, 8(%rax);          \
+       mov     %rbp, 16(%rax);         \
+       movq    $0, 24(%rax);           \
+       mov     %rbx, 32(%rax);         \
+       mov     %rdx, 40(%rax);         \
+       mov     %rcx, 48(%rax);         \
+       push    %rbx;                   \
+       mov     16(%rsp), %rbx;         \
+       mov     %rbx, 56(%rax);         \
+       pop     %rbx;                   \
+       pop     %rax;                   
+       
+
+#define Restore_SVM_Registers(location) \
+       push    %rax;                   \
+       mov     location, %rax;         \
+       mov     (%rax), %rdi;           \
+       mov     8(%rax), %rsi;          \
+       mov     16(%rax), %rbp;         \
+       mov     32(%rax), %rbx;         \
+       mov     40(%rax), %rdx;         \
+       mov     48(%rax), %rcx;         \
+       pop     %rax;
+
+
+
+
+#define PUSHA                          \
+       pushq %rbp;                     \
+       pushq %rbx;                     \
+       pushq %r12;                     \
+       pushq %r13;                     \
+       pushq %r14;                     \
+       pushq %r15;                     
+
+
+#define POPA                           \
+       popq %r15;                      \
+       popq %r14;                      \
+       popq %r13;                      \
+       popq %r12;                      \
+       popq %rbx;                      \
+       popq %rbp;                      
+
+// VMCB => RDI
+// vm_regs => RSI
+
+v3_svm_launch:
+       pushf;
+       push    %fs;
+       push    %gs;
+       PUSHA
+
+       
+       
+
+
+       pushq %rsi
+
+       movq    %rdi, %rax
+       Restore_SVM_Registers(%rsi);
+
+
+       
+
+       vmload;
+       vmrun;
+       vmsave;
+
+
+       Save_SVM_Registers(8(%rsp));
+
+       addq $8, %rsp
+
+
+
+
+
+       POPA
+       pop     %gs;
+       pop     %fs;
+       popf;
+       ret
+
+
+#endif
+
+
+v3_stgi:
+       stgi;
+       ret;
+
+v3_clgi:
+       clgi;
+       ret;
+       
+       
diff --git a/palacios/src/palacios/svm_lowlevel.asm b/palacios/src/palacios/svm_lowlevel.asm
deleted file mode 100644 (file)
index ac646b2..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-;  -*- fundamental -*-
-;; 
-;; This file is part of the Palacios Virtual Machine Monitor developed
-;; by the V3VEE Project with funding from the United States National 
-;; Science Foundation and the Department of Energy.  
-;;
-;; The V3VEE Project is a joint project between Northwestern University
-;; and the University of New Mexico.  You can find out more at 
-;; http://www.v3vee.org
-;;
-;; Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
-;; Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
-;; All rights reserved.
-;;
-;; Author: Jack Lange <jarusl@cs.northwestern.edu>
-;;
-;; This is free software.  You are permitted to use,
-;; redistribute, and modify it as specified in the file "V3VEE_LICENSE".
-;;
-
-
-
-%ifndef SVM_ASM
-%define SVM_ASM
-
-;%include "defs.asm"
-%include "vmm_symbol.asm"
-
-SVM_ERROR equ 0xFFFFFFFF
-SVM_SUCCESS equ 0x00000000
-
-
-
-EXPORT exit_test
-
-EXTERN handle_svm_exit
-
-EXPORT launch_svm
-EXPORT safe_svm_launch
-
-EXPORT STGI
-EXPORT CLGI
-
-
-
-;; These need to be kept similar with the svm return values in svm.h
-SVM_HANDLER_SUCCESS  equ 0x00
-SVM_HANDLER_ERROR equ  0x1
-SVM_HANDLER_HALT equ 0x2
-
-[BITS 32]
-
-
-; Save and restore registers needed by SVM
-%macro Save_SVM_Registers 1
-       push    eax
-       mov     eax, dword %1
-       mov     [eax], edi
-       mov     [eax + 8], esi
-       mov     [eax + 16], ebp
-       mov     [eax + 24], dword 0             ;; esp
-       mov     [eax + 32], ebx
-       mov     [eax + 40], edx
-       mov     [eax + 48], ecx
-
-       push    ebx
-       mov     ebx, [esp + 4]
-       mov     [eax + 56], ebx         ;; eax
-       pop     ebx
-
-       pop     eax
-%endmacro
-
-
-%macro Restore_SVM_Registers 1
-       push    eax
-       mov     eax, dword %1
-       mov     edi, [eax]
-       mov     esi, [eax + 8]
-       mov     ebp, [eax + 16]
-;;     mov     esp, [eax + 24]
-       mov     ebx, [eax + 32]
-       mov     edx, [eax + 40]
-       mov     ecx, [eax + 48]
-;;     mov     eax, [eax + 56]
-       pop     eax
-%endmacro
-
-%macro vmrun 0
-       db      00fh, 001h, 0d8h
-%endmacro
-
-%macro vmsave 0
-       db      00fh, 001h, 0dbh
-%endmacro
-
-%macro vmload 0
-       db      00fh, 001h, 0dah
-%endmacro
-
-%macro stgi 0
-       db      00fh, 001h, 0dch
-%endmacro
-
-%macro clgi 0
-       db      00fh, 001h, 0ddh
-%endmacro
-
-;VMRUN  equ db 0Fh, 01h, D8h
-;VMLOAD equ db 0x0F,0x01,0xDA
-;VMSAVE equ db 0x0F,0x01,0xDB
-;STGI   equ db 0x0F,0x01,0xDC
-;CLGI   equ db 0x0F,0x01,0xDD
-
-
-
-align 8
-CLGI:
-       clgi
-       ret
-
-align 8
-STGI:
-       stgi
-       ret
-
-
-
-; I think its safe to say that there are some pretty serious register issues...
-align 8
-launch_svm:
-       push    ebp
-       mov     ebp, esp
-       pusha
-       
-       mov     eax, [ebp + 8]
-       vmrun
-;      db      00fh, 001h, 0d8h
-       popa
-       pop     ebp
-       ret
-
-
-
-
-exit_test: 
-       mov     cr4, eax
-       ret
-
-
-;; Need to check this..
-;; save_svm_launch(rax, struct guest_gprs * regs)
-align 8
-safe_svm_launch:
-       push    ebp
-       mov     ebp, esp
-       pushf
-       push    fs
-       push    gs
-       pusha                                   ;; Save Host state
-
-
-       push    dword [ebp + 12]                ;; pointer to the guest GPR save area
-       push    dword [ebp + 8]                 ;; pointer to the VMCB pointer
-
-;;     mov     eax, [esp + 4]                  ;; mov guest GPR pointer to eax
-
-       ;; this is plus 8 because we push eax in the macro
-       Restore_SVM_Registers [esp + 8]         ;; Restore Guest GPR state
-       pop     eax                             ;; pop VMCB pointer into eax
-
-       vmload
-       vmrun
-       vmsave
-
-;;     pop     eax                             ;; pop Guest GPR pointer into eax
-       ;; this is plus 4 because we push eax in the macro NEED TO CHANGE
-       Save_SVM_Registers  [esp+4]             ;; save guest GPRs
-       
-       add     esp, 4                          ;; skip past the gpr ptr
-       
-       popa                                    ;; Restore Host state
-       pop     gs
-       pop     fs
-       popf
-       pop     ebp
-       ret
-
-
-
-%endif
-
-
index 0018a60..c922ee3 100644 (file)
@@ -24,7 +24,7 @@
 #include <palacios/vmm_intr.h>
 
 
-int handle_svm_pause(struct guest_info * info)
+int v3_handle_svm_pause(struct guest_info * info)
 {
   // handled as a nop
 
index 921039e..85632d8 100644 (file)
@@ -28,7 +28,7 @@
 // should raise #GP if CPL is not zero
 // Otherwise execute
 
-int handle_svm_wbinvd(struct guest_info * info)
+int v3_handle_svm_wbinvd(struct guest_info * info)
 {
   if (info->cpl!=0) { 
     PrintDebug("WBINVD: cpl!=0, injecting GPF\n");
index 17cc8be..6257a98 100644 (file)
@@ -23,7 +23,7 @@
 
 
 
-struct vm_device * allocate_device() {
+static struct vm_device * v3_allocate_device() {
 
   struct vm_device * dev = NULL;
   dev = (struct vm_device*)V3_Malloc(sizeof(struct vm_device));
@@ -48,8 +48,8 @@ struct vm_device * allocate_device() {
   return dev;
 }
 
-struct vm_device * create_device(char * name, struct vm_device_ops * ops, void * private_data) {
-  struct vm_device * dev = allocate_device();
+struct vm_device * v3_create_device(char * name, struct vm_device_ops * ops, void * private_data) {
+  struct vm_device * dev = v3_allocate_device();
 
   strncpy(dev->name, name, 32);
   dev->ops = ops;
@@ -58,7 +58,7 @@ struct vm_device * create_device(char * name, struct vm_device_ops * ops, void *
   return dev;
 }
 
-void free_device(struct vm_device * dev) {
+void v3_free_device(struct vm_device * dev) {
   V3_Free(dev);
 }
 
index 64241aa..e47c1fb 100644 (file)
 #include <palacios/vm_guest.h>
 #include <palacios/vmm_ctrl_regs.h>
 #include <palacios/vmm.h>
+#include <palacios/vmcb.h>
 
 
-vm_cpu_mode_t get_cpu_mode(struct guest_info * info) {
+v3_vm_cpu_mode_t v3_get_cpu_mode(struct guest_info * info) {
   struct cr0_32 * cr0;
   struct cr4_32 * cr4 = (struct cr4_32 *)&(info->ctrl_regs.cr4);
   struct efer_64 * efer = (struct efer_64 *)&(info->ctrl_regs.efer);
@@ -54,7 +55,7 @@ vm_cpu_mode_t get_cpu_mode(struct guest_info * info) {
   }
 }
 
-vm_mem_mode_t get_mem_mode(struct guest_info * info) {
+v3_vm_mem_mode_t v3_get_mem_mode(struct guest_info * info) {
   struct cr0_32 * cr0;
 
   if (info->shdw_pg_mode == SHADOW_PAGING) {
@@ -77,7 +78,7 @@ vm_mem_mode_t get_mem_mode(struct guest_info * info) {
 }
 
 
-void PrintV3Segments(struct guest_info * info) {
+void v3_print_segments(struct guest_info * info) {
   struct v3_segments * segs = &(info->segments);
   int i = 0;
   struct v3_segment * seg_ptr;
@@ -89,30 +90,35 @@ void PrintV3Segments(struct guest_info * info) {
 
   for (i = 0; seg_names[i] != NULL; i++) {
 
-    PrintDebug("\t%s: Sel=%x, base=%x, limit=%x\n", seg_names[i], seg_ptr[i].selector, seg_ptr[i].base, seg_ptr[i].limit);
+    PrintDebug("\t%s: Sel=%x, base=%p, limit=%x\n", seg_names[i], seg_ptr[i].selector, 
+              (void *)(addr_t)seg_ptr[i].base, seg_ptr[i].limit);
 
   }
 
 }
 
 
-void PrintV3CtrlRegs(struct guest_info * info) {
+void v3_print_ctrl_regs(struct guest_info * info) {
   struct v3_ctrl_regs * regs = &(info->ctrl_regs);
   int i = 0;
   v3_reg_t * reg_ptr;
   char * reg_names[] = {"CR0", "CR2", "CR3", "CR4", "CR8", "FLAGS", NULL};
+  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(info->vmm_data);
 
   reg_ptr= (v3_reg_t *)regs;
 
   PrintDebug("32 bit Ctrl Regs:\n");
 
   for (i = 0; reg_names[i] != NULL; i++) {
-    PrintDebug("\t%s=0x%x\n", reg_names[i], reg_ptr[i]);  
+    PrintDebug("\t%s=0x%p\n", reg_names[i], (void *)(addr_t)reg_ptr[i]);  
   }
+
+  PrintDebug("\tEFER=0x%p\n", (void*)(addr_t)(guest_state->efer));
+
 }
 
 
-void PrintV3GPRs(struct guest_info * info) {
+void v3_print_GPRs(struct guest_info * info) {
   struct v3_gprs * regs = &(info->vm_regs);
   int i = 0;
   v3_reg_t * reg_ptr;
@@ -123,6 +129,6 @@ void PrintV3GPRs(struct guest_info * info) {
   PrintDebug("32 bit GPRs:\n");
 
   for (i = 0; reg_names[i] != NULL; i++) {
-    PrintDebug("\t%s=0x%x\n", reg_names[i], reg_ptr[i]);  
+    PrintDebug("\t%s=0x%p\n", reg_names[i], (void *)(addr_t)reg_ptr[i]);  
   }
 }
index 17e9901..920c8bb 100644 (file)
@@ -21,7 +21,7 @@
 #include <palacios/vmm.h>
 #include <palacios/vmm_paging.h>
 
-extern struct vmm_os_hooks * os_hooks;
+extern struct v3_os_hooks * os_hooks;
 
 
 /**********************************/
@@ -34,7 +34,8 @@ int host_va_to_host_pa(addr_t host_va, addr_t * host_pa) {
     *host_pa = (addr_t)(os_hooks)->vaddr_to_paddr((void *)host_va);
   
     if (*host_pa == 0) {
-      PrintError("In HVA->HPA: Invalid HVA(%x)->HPA lookup\n", host_va);
+      PrintError("In HVA->HPA: Invalid HVA(%p)->HPA lookup\n",  
+                (void *)host_va);
       return -1;
     }
   } else {
@@ -51,7 +52,8 @@ int host_pa_to_host_va(addr_t host_pa, addr_t * host_va) {
     *host_va = (addr_t)(os_hooks)->paddr_to_vaddr((void *)host_pa);
     
     if (*host_va == 0) {
-      PrintError("In HPA->HVA: Invalid HPA(%x)->HVA lookup\n", host_pa);
+      PrintError("In HPA->HVA: Invalid HPA(%p)->HVA lookup\n",  
+                (void *)host_pa);
       return -1;
     }
   } else {
@@ -65,8 +67,11 @@ int host_pa_to_host_va(addr_t host_pa, addr_t * host_va) {
 
 int guest_pa_to_host_pa(struct guest_info * guest_info, addr_t guest_pa, addr_t * host_pa) {
   // we use the shadow map here...
-  if (lookup_shadow_map_addr(&(guest_info->mem_map), guest_pa, host_pa) != HOST_REGION_PHYSICAL_MEMORY) {
-    PrintError("In GPA->HPA: Could not find address in shadow map (addr=%x)\n", guest_pa);
+  host_region_type_t reg_type = lookup_shadow_map_addr(&(guest_info->mem_map), guest_pa, host_pa);
+
+  if (reg_type != HOST_REGION_PHYSICAL_MEMORY) {
+    PrintError("In GPA->HPA: Could not find address in shadow map (addr=%p) (reg_type=%d)\n", 
+               (void *)guest_pa, reg_type);
     return -1;
   }
 
@@ -99,12 +104,14 @@ int host_va_to_guest_pa(struct guest_info * guest_info, addr_t host_va, addr_t *
   *guest_pa = 0;
 
   if (host_va_to_host_pa(host_va, &host_pa) != 0) {
-    PrintError("In HVA->GPA: Invalid HVA(%x)->HPA lookup\n", host_va);
+    PrintError("In HVA->GPA: Invalid HVA(%p)->HPA lookup\n", 
+              (void *)host_va);
     return -1;
   }
 
   if (host_pa_to_guest_pa(guest_info, host_pa, guest_pa) != 0) {
-    PrintError("In HVA->GPA: Invalid HPA(%x)->GPA lookup\n", host_pa);
+    PrintError("In HVA->GPA: Invalid HPA(%p)->GPA lookup\n", 
+              (void *)host_pa);
     return -1;
   }
 
@@ -120,12 +127,14 @@ int guest_pa_to_host_va(struct guest_info * guest_info, addr_t guest_pa, addr_t
   *host_va = 0;
 
   if (guest_pa_to_host_pa(guest_info, guest_pa, &host_pa) != 0) {
-    PrintError("In GPA->HVA: Invalid GPA(%x)->HPA lookup\n", guest_pa);
+    PrintError("In GPA->HVA: Invalid GPA(%p)->HPA lookup\n", 
+               (void *)guest_pa);
     return -1;
   }
   
   if (host_pa_to_host_va(host_pa, host_va) != 0) {
-    PrintError("In GPA->HVA: Invalid HPA(%x)->HVA lookup\n", host_pa);
+    PrintError("In GPA->HVA: Invalid HPA(%p)->HVA lookup\n", 
+              (void *)host_pa);
     return -1;
   }
 
@@ -151,13 +160,14 @@ int guest_va_to_guest_pa(struct guest_info * guest_info, addr_t guest_va, addr_t
       addr_t guest_pde = 0;
       
       if (guest_info->shdw_pg_mode == SHADOW_PAGING) {
-       guest_pde = CR3_TO_PDE32(guest_info->shdw_pg_state.guest_cr3);
+       guest_pde = (addr_t)V3_PAddr((void *)(addr_t)CR3_TO_PDE32((void *)(addr_t)(guest_info->shdw_pg_state.guest_cr3)));
       } else if (guest_info->shdw_pg_mode == NESTED_PAGING) {
-       guest_pde = CR3_TO_PDE32(guest_info->ctrl_regs.cr3);
+       guest_pde = (addr_t)V3_PAddr((void *)(addr_t)CR3_TO_PDE32((void *)(addr_t)(guest_info->ctrl_regs.cr3)));
       }
       
       if (guest_pa_to_host_va(guest_info, guest_pde, (addr_t *)&pde) == -1) {
-       PrintError("In GVA->GPA: Invalid GPA(%x)->HVA PDE32 lookup\n", guest_pde);
+       PrintError("In GVA->GPA: Invalid GPA(%p)->HVA PDE32 lookup\n", 
+                   (void *)guest_pde);
        return -1;
       }
       
@@ -175,14 +185,16 @@ int guest_va_to_guest_pa(struct guest_info * guest_info, addr_t guest_va, addr_t
          
          
          if (guest_pa_to_host_va(guest_info, tmp_pa, (addr_t*)&pte) == -1) {
-           PrintError("In GVA->GPA: Invalid GPA(%x)->HVA PTE32 lookup\n", guest_pa);
+           PrintError("In GVA->GPA: Invalid GPA(%p)->HVA PTE32 lookup\n", 
+                       (void *)guest_pa);
            return -1;
          }
          
          //PrintDebug("PTE host addr=%x, GVA=%x, GPA=%x(should be 0)\n", pte, guest_va, *guest_pa);
         
          if (pte32_lookup(pte, guest_va, guest_pa) != 0) {
-           PrintError("In GVA->GPA: PTE32 Lookup failure GVA=%x; PTE=%x\n", guest_va, pte);
+           PrintError("In GVA->GPA: PTE32 Lookup failure GVA=%p; PTE=%p\n", 
+                       (void *)guest_va,  (void *)pte);
            //        PrintPT32(PDE32_INDEX(guest_va) << 22, pte);
            return -1;
          }
@@ -235,12 +247,14 @@ int guest_va_to_host_pa(struct guest_info * guest_info, addr_t guest_va, addr_t
   *host_pa = 0;
 
   if (guest_va_to_guest_pa(guest_info, guest_va, &guest_pa) != 0) {
-    PrintError("In GVA->HPA: Invalid GVA(%x)->GPA lookup\n", guest_va);
+    PrintError("In GVA->HPA: Invalid GVA(%p)->GPA lookup\n", 
+               (void *)guest_va);
     return -1;
   }
   
   if (guest_pa_to_host_pa(guest_info, guest_pa, host_pa) != 0) {
-    PrintError("In GVA->HPA: Invalid GPA(%x)->HPA lookup\n", guest_pa);
+    PrintError("In GVA->HPA: Invalid GPA(%p)->HPA lookup\n", 
+              (void *)guest_pa);
     return -1;
   }
 
@@ -254,12 +268,14 @@ int host_pa_to_guest_va(struct guest_info * guest_info, addr_t host_pa, addr_t *
   *guest_va = 0;
 
   if (host_pa_to_guest_pa(guest_info, host_pa, &guest_pa) != 0) {
-    PrintError("In HPA->GVA: Invalid HPA(%x)->GPA lookup\n", host_pa);
+    PrintError("In HPA->GVA: Invalid HPA(%p)->GPA lookup\n", 
+               (void *)host_pa);
     return -1;
   }
 
   if (guest_pa_to_guest_va(guest_info, guest_pa, guest_va) != 0) {
-    PrintError("In HPA->GVA: Invalid GPA(%x)->GVA lookup\n", guest_pa);
+    PrintError("In HPA->GVA: Invalid GPA(%p)->GVA lookup\n", 
+               (void *)guest_pa);
     return -1;
   }
 
@@ -276,17 +292,20 @@ int guest_va_to_host_va(struct guest_info * guest_info, addr_t guest_va, addr_t
   *host_va = 0;
 
   if (guest_va_to_guest_pa(guest_info, guest_va, &guest_pa) != 0) {
-    PrintError("In GVA->HVA: Invalid GVA(%x)->GPA lookup\n", guest_va);
+    PrintError("In GVA->HVA: Invalid GVA(%p)->GPA lookup\n", 
+               (void *)guest_va);
     return -1;
   }
 
   if (guest_pa_to_host_pa(guest_info, guest_pa, &host_pa) != 0) {
-    PrintError("In GVA->HVA: Invalid GPA(%x)->HPA lookup\n", guest_pa);
+    PrintError("In GVA->HVA: Invalid GPA(%p)->HPA lookup\n", 
+               (void *)guest_pa);
     return -1;
   }
 
   if (host_pa_to_host_va(host_pa, host_va) != 0) {
-    PrintError("In GVA->HVA: Invalid HPA(%x)->HVA lookup\n", host_pa);
+    PrintError("In GVA->HVA: Invalid HPA(%p)->HVA lookup\n", 
+               (void *)host_pa);
     return -1;
   }
 
@@ -302,17 +321,20 @@ int host_va_to_guest_va(struct guest_info * guest_info, addr_t host_va, addr_t *
   *guest_va = 0;
 
   if (host_va_to_host_pa(host_va, &host_pa) != 0) {
-    PrintError("In HVA->GVA: Invalid HVA(%x)->HPA lookup\n", host_va);
+    PrintError("In HVA->GVA: Invalid HVA(%p)->HPA lookup\n", 
+               (void *)host_va);
     return -1;
   }
 
   if (host_pa_to_guest_pa(guest_info, host_pa, &guest_pa) != 0) {
-    PrintError("In HVA->GVA: Invalid HPA(%x)->GPA lookup\n", host_va);
+    PrintError("In HVA->GVA: Invalid HPA(%p)->GPA lookup\n", 
+               (void *)host_va);
     return -1;
   }
 
   if (guest_pa_to_guest_va(guest_info, guest_pa, guest_va) != 0) {
-    PrintError("In HVA->GVA: Invalid GPA(%x)->GVA lookup\n", guest_pa);
+    PrintError("In HVA->GVA: Invalid GPA(%p)->GVA lookup\n", 
+              (void *)guest_pa);
     return -1;
   }
 
@@ -340,7 +362,7 @@ int read_guest_va_memory(struct guest_info * guest_info, addr_t guest_va, int co
 
     
     if (guest_va_to_host_va(guest_info, cursor, &host_addr) != 0) {
-      PrintDebug("Invalid GVA(%x)->HVA lookup\n", cursor);
+      PrintDebug("Invalid GVA(%p)->HVA lookup\n", (void *)cursor);
       return bytes_read;
     }
     
index a2eae49..7e3317f 100644 (file)
@@ -91,7 +91,7 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
   vmcb_saved_state_t * guest_area = GET_VMCB_SAVE_STATE_AREA(vmcb);
 
-  PrintDebug("VMCB (0x%.8x)\n", vmcb);
+  PrintDebug("VMCB (0x%p)\n", (void *)vmcb);
 
   PrintDebug("--Control Area--\n");
   PrintDebug("CR Reads: %x\n", *(ushort_t*)&(ctrl_area->cr_reads));
@@ -99,7 +99,7 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
   PrintDebug("DR Reads: %x\n", *(ushort_t*)&(ctrl_area->dr_reads));
   PrintDebug("DR Writes: %x\n", *(ushort_t*)&(ctrl_area->dr_writes));
   
-  PrintDebug("Exception Bitmap: %x (at 0x%.8x)\n", *(uint_t*)&(ctrl_area->exceptions), &(ctrl_area->exceptions));
+  PrintDebug("Exception Bitmap: %x (at 0x%p)\n", *(uint_t*)&(ctrl_area->exceptions), (void *)&(ctrl_area->exceptions));
   PrintDebug("\tDivide-by-Zero: %d\n", ctrl_area->exceptions.de);
   PrintDebug("\tDebug: %d\n", ctrl_area->exceptions.db);
   PrintDebug("\tNon-maskable interrupts: %d\n", ctrl_area->exceptions.nmi);
@@ -120,7 +120,7 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
   PrintDebug("\tSIMD floating point: %d\n", ctrl_area->exceptions.xf);
   PrintDebug("\tSecurity: %d\n", ctrl_area->exceptions.sx);
 
-  PrintDebug("Instructions bitmap: %.8x (at 0x%.8x)\n", *(uint_t*)&(ctrl_area->instrs), &(ctrl_area->instrs));
+  PrintDebug("Instructions bitmap: %.8x (at 0x%p)\n", *(uint_t*)&(ctrl_area->instrs), &(ctrl_area->instrs));
   PrintDebug("\tINTR: %d\n", ctrl_area->instrs.INTR);
   PrintDebug("\tNMI: %d\n", ctrl_area->instrs.NMI);
   PrintDebug("\tSMI: %d\n", ctrl_area->instrs.SMI);
@@ -154,7 +154,7 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
   PrintDebug("\tFERR_FREEZE: %d\n", ctrl_area->instrs.FERR_FREEZE);
   PrintDebug("\tshutdown_evts: %d\n", ctrl_area->instrs.shutdown_evts);
 
-  PrintDebug("SVM Instruction Bitmap: %.8x (at 0x%.8x)\n", *(uint_t*)&(ctrl_area->svm_instrs), &(ctrl_area->svm_instrs));
+  PrintDebug("SVM Instruction Bitmap: %x (at 0x%p)\n", *(uint_t*)&(ctrl_area->svm_instrs), &(ctrl_area->svm_instrs));
   PrintDebug("\tVMRUN: %d\n", ctrl_area->svm_instrs.VMRUN);
   PrintDebug("\tVMMCALL: %d\n", ctrl_area->svm_instrs.VMMCALL);
   PrintDebug("\tVMLOAD: %d\n", ctrl_area->svm_instrs.VMLOAD);
@@ -172,17 +172,17 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
 
 
   tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
-  PrintDebug("IOPM_BASE_PA: lo: 0x%.8x, hi: 0x%.8x\n", tmp_reg.e_reg.low, tmp_reg.e_reg.high);
+  PrintDebug("IOPM_BASE_PA: lo: 0x%x, hi: 0x%x\n", tmp_reg.e_reg.low, tmp_reg.e_reg.high);
   tmp_reg.r_reg = ctrl_area->MSRPM_BASE_PA;
-  PrintDebug("MSRPM_BASE_PA: lo: 0x%.8x, hi: 0x%.8x\n", tmp_reg.e_reg.low, tmp_reg.e_reg.high);
+  PrintDebug("MSRPM_BASE_PA: lo: 0x%x, hi: 0x%x\n", tmp_reg.e_reg.low, tmp_reg.e_reg.high);
   tmp_reg.r_reg = ctrl_area->TSC_OFFSET;
-  PrintDebug("TSC_OFFSET: lo: 0x%.8x, hi: 0x%.8x\n", tmp_reg.e_reg.low, tmp_reg.e_reg.high);
+  PrintDebug("TSC_OFFSET: lo: 0x%x, hi: 0x%x\n", tmp_reg.e_reg.low, tmp_reg.e_reg.high);
 
   PrintDebug("guest_ASID: %d\n", ctrl_area->guest_ASID);
   PrintDebug("TLB_CONTROL: %d\n", ctrl_area->TLB_CONTROL);
 
 
-  PrintDebug("Guest Control Bitmap: %x (at 0x%.8x)\n", *(uint_t*)&(ctrl_area->guest_ctrl), &(ctrl_area->guest_ctrl));
+  PrintDebug("Guest Control Bitmap: %x (at 0x%p)\n", *(uint_t*)&(ctrl_area->guest_ctrl), &(ctrl_area->guest_ctrl));
   PrintDebug("\tV_TPR: %d\n", ctrl_area->guest_ctrl.V_TPR);
   PrintDebug("\tV_IRQ: %d\n", ctrl_area->guest_ctrl.V_IRQ);
   PrintDebug("\tV_INTR_PRIO: %d\n", ctrl_area->guest_ctrl.V_INTR_PRIO);
@@ -194,14 +194,14 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
 
 
   tmp_reg.r_reg = ctrl_area->exit_code;
-  PrintDebug("exit_code: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("exit_code: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = ctrl_area->exit_info1;
-  PrintDebug("exit_info1: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("exit_info1: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = ctrl_area->exit_info2;
-  PrintDebug("exit_info2: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("exit_info2: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("Exit Int Info: (at 0x%.8x)\n", &(ctrl_area->exit_int_info));
+  PrintDebug("Exit Int Info: (at 0x%p)\n", &(ctrl_area->exit_int_info));
   PrintDebug("Vector: %d\n", ctrl_area->exit_int_info.vector);
   PrintDebug("(type=%d) (ev=%d) (valid=%d)\n", ctrl_area->exit_int_info.type, 
             ctrl_area->exit_int_info.ev, ctrl_area->exit_int_info.valid);
@@ -209,9 +209,9 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
 
 
   tmp_reg.r_reg = ctrl_area->NP_ENABLE;
-  PrintDebug("NP_ENABLE: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("NP_ENABLE: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
-  PrintDebug("Event Injection: (at 0x%.8x)\n", &(ctrl_area->EVENTINJ));
+  PrintDebug("Event Injection: (at 0x%p)\n", &(ctrl_area->EVENTINJ));
   PrintDebug("Vector: %d\n", ctrl_area->EVENTINJ.vector);
   PrintDebug("(type=%d) (ev=%d) (valid=%d)\n", ctrl_area->EVENTINJ.type, 
             ctrl_area->EVENTINJ.ev, ctrl_area->EVENTINJ.valid);
@@ -219,192 +219,192 @@ void PrintDebugVMCB(vmcb_t * vmcb) {
 
 
   tmp_reg.r_reg = ctrl_area->N_CR3;
-  PrintDebug("N_CR3: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("N_CR3: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
   PrintDebug("LBR_VIRTUALIZATION_ENABLE: %d\n", ctrl_area->LBR_VIRTUALIZATION_ENABLE);
 
 
   PrintDebug("\n--Guest Saved State--\n");
 
-  PrintDebug("es Selector (at 0x%.8x): \n", &(guest_area->es));
+  PrintDebug("es Selector (at 0x%p): \n", &(guest_area->es));
   PrintDebug("\tSelector: %d\n", guest_area->es.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->es.attrib.fields.type, guest_area->es.attrib.fields.S, 
             guest_area->es.attrib.fields.dpl, guest_area->es.attrib.fields.P,
             guest_area->es.attrib.fields.avl, guest_area->es.attrib.fields.L,
             guest_area->es.attrib.fields.db, guest_area->es.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->es.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->es.limit);
   tmp_reg.r_reg = guest_area->es.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("cs Selector (at 0x%.8x): \n", &(guest_area->cs));
+  PrintDebug("cs Selector (at 0x%p): \n", &(guest_area->cs));
   PrintDebug("\tSelector: %d\n", guest_area->cs.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->cs.attrib.fields.type, guest_area->cs.attrib.fields.S, 
             guest_area->cs.attrib.fields.dpl, guest_area->cs.attrib.fields.P,
             guest_area->cs.attrib.fields.avl, guest_area->cs.attrib.fields.L,
             guest_area->cs.attrib.fields.db, guest_area->cs.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->cs.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->cs.limit);
   tmp_reg.r_reg = guest_area->cs.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("ss Selector (at 0x%.8x): \n", &(guest_area->ss));
+  PrintDebug("ss Selector (at 0x%p): \n", &(guest_area->ss));
   PrintDebug("\tSelector: %d\n", guest_area->ss.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->ss.attrib.fields.type, guest_area->ss.attrib.fields.S, 
             guest_area->ss.attrib.fields.dpl, guest_area->ss.attrib.fields.P,
             guest_area->ss.attrib.fields.avl, guest_area->ss.attrib.fields.L,
             guest_area->ss.attrib.fields.db, guest_area->ss.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->ss.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->ss.limit);
   tmp_reg.r_reg = guest_area->ss.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("ds Selector (at 0x%.8x): \n", &(guest_area->ds));
+  PrintDebug("ds Selector (at 0x%p): \n", &(guest_area->ds));
   PrintDebug("\tSelector: %d\n", guest_area->ds.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->ds.attrib.fields.type, guest_area->ds.attrib.fields.S, 
             guest_area->ds.attrib.fields.dpl, guest_area->ds.attrib.fields.P,
             guest_area->ds.attrib.fields.avl, guest_area->ds.attrib.fields.L,
             guest_area->ds.attrib.fields.db, guest_area->ds.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->ds.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->ds.limit);
   tmp_reg.r_reg = guest_area->ds.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("fs Selector (at 0x%.8x): \n", &(guest_area->fs));
+  PrintDebug("fs Selector (at 0x%p): \n", &(guest_area->fs));
   PrintDebug("\tSelector: %d\n", guest_area->fs.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->fs.attrib.fields.type, guest_area->fs.attrib.fields.S, 
             guest_area->fs.attrib.fields.dpl, guest_area->fs.attrib.fields.P,
             guest_area->fs.attrib.fields.avl, guest_area->fs.attrib.fields.L,
             guest_area->fs.attrib.fields.db, guest_area->fs.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->fs.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->fs.limit);
   tmp_reg.r_reg = guest_area->fs.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("gs Selector (at 0x%.8x): \n", &(guest_area->gs));
+  PrintDebug("gs Selector (at 0x%p): \n", &(guest_area->gs));
   PrintDebug("\tSelector: %d\n", guest_area->gs.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->gs.attrib.fields.type, guest_area->gs.attrib.fields.S, 
             guest_area->gs.attrib.fields.dpl, guest_area->gs.attrib.fields.P,
             guest_area->gs.attrib.fields.avl, guest_area->gs.attrib.fields.L,
             guest_area->gs.attrib.fields.db, guest_area->gs.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->gs.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->gs.limit);
   tmp_reg.r_reg = guest_area->gs.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("gdtr Selector (at 0x%.8x): \n", &(guest_area->gdtr));
+  PrintDebug("gdtr Selector (at 0x%p): \n", &(guest_area->gdtr));
   PrintDebug("\tSelector: %d\n", guest_area->gdtr.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->gdtr.attrib.fields.type, guest_area->gdtr.attrib.fields.S, 
             guest_area->gdtr.attrib.fields.dpl, guest_area->gdtr.attrib.fields.P,
             guest_area->gdtr.attrib.fields.avl, guest_area->gdtr.attrib.fields.L,
             guest_area->gdtr.attrib.fields.db, guest_area->gdtr.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->gdtr.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->gdtr.limit);
   tmp_reg.r_reg = guest_area->gdtr.base;
   PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("ldtr Selector (at 0x%.8x): \n", &(guest_area->ldtr));
+  PrintDebug("ldtr Selector (at 0x%p): \n", &(guest_area->ldtr));
   PrintDebug("\tSelector: %d\n", guest_area->ldtr.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->ldtr.attrib.fields.type, guest_area->ldtr.attrib.fields.S, 
             guest_area->ldtr.attrib.fields.dpl, guest_area->ldtr.attrib.fields.P,
             guest_area->ldtr.attrib.fields.avl, guest_area->ldtr.attrib.fields.L,
             guest_area->ldtr.attrib.fields.db, guest_area->ldtr.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->ldtr.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->ldtr.limit);
   tmp_reg.r_reg = guest_area->ldtr.base;
   PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("idtr Selector (at 0x%.8x): \n", &(guest_area->idtr));
+  PrintDebug("idtr Selector (at 0x%p): \n", &(guest_area->idtr));
   PrintDebug("\tSelector: %d\n", guest_area->idtr.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->idtr.attrib.fields.type, guest_area->idtr.attrib.fields.S, 
             guest_area->idtr.attrib.fields.dpl, guest_area->idtr.attrib.fields.P,
             guest_area->idtr.attrib.fields.avl, guest_area->idtr.attrib.fields.L,
             guest_area->idtr.attrib.fields.db, guest_area->idtr.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->idtr.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->idtr.limit);
   tmp_reg.r_reg = guest_area->idtr.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
-  PrintDebug("tr Selector (at 0x%.8x): \n", &(guest_area->tr));
+  PrintDebug("tr Selector (at 0x%p): \n", &(guest_area->tr));
   PrintDebug("\tSelector: %d\n", guest_area->tr.selector); 
   PrintDebug("\t(type=%x), (S=%d), (dpl=%d), (P=%d), (avl=%d), (L=%d), (db=%d), (G=%d)\n", 
             guest_area->tr.attrib.fields.type, guest_area->tr.attrib.fields.S, 
             guest_area->tr.attrib.fields.dpl, guest_area->tr.attrib.fields.P,
             guest_area->tr.attrib.fields.avl, guest_area->tr.attrib.fields.L,
             guest_area->tr.attrib.fields.db, guest_area->tr.attrib.fields.G);
-  PrintDebug("\tlimit: %lu\n", guest_area->tr.limit);
+  PrintDebug("\tlimit: %u\n", guest_area->tr.limit);
   tmp_reg.r_reg = guest_area->tr.base;
-  PrintDebug("\tBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("\tBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
   PrintDebug("cpl: %d\n", guest_area->cpl);
 
   
   tmp_reg.r_reg = guest_area->efer;
-  PrintDebug("EFER: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("EFER: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
   tmp_reg.r_reg = guest_area->cr4;
-  PrintDebug("CR4: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("CR4: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->cr3;
-  PrintDebug("CR3: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("CR3: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->cr0;
-  PrintDebug("CR0: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("CR0: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->dr7;
-  PrintDebug("DR7: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("DR7: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->dr6;
-  PrintDebug("DR6: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("DR6: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->rflags;
-  PrintDebug("RFLAGS: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("RFLAGS: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->rip;
-  PrintDebug("RIP: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("RIP: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
   tmp_reg.r_reg = guest_area->rsp;
-  PrintDebug("RSP: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("RSP: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
   
   tmp_reg.r_reg = guest_area->rax;
-  PrintDebug("RAX: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("RAX: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->star;
-  PrintDebug("STAR: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("STAR: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->lstar;
-  PrintDebug("LSTAR: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("LSTAR: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->cstar;
-  PrintDebug("CSTAR: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("CSTAR: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->sfmask;
-  PrintDebug("SFMASK: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("SFMASK: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->KernelGsBase;
-  PrintDebug("KernelGsBase: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("KernelGsBase: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->sysenter_cs;
-  PrintDebug("sysenter_cs: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("sysenter_cs: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->sysenter_esp;
-  PrintDebug("sysenter_esp: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("sysenter_esp: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->sysenter_eip;
-  PrintDebug("sysenter_eip: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("sysenter_eip: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->cr2;
-  PrintDebug("CR2: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("CR2: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
   tmp_reg.r_reg = guest_area->g_pat;
-  PrintDebug("g_pat: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("g_pat: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->dbgctl;
-  PrintDebug("dbgctl: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("dbgctl: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->br_from;
-  PrintDebug("br_from: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("br_from: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->br_to;
-  PrintDebug("br_to: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("br_to: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->lastexcpfrom;
-  PrintDebug("lastexcpfrom: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("lastexcpfrom: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
   tmp_reg.r_reg = guest_area->lastexcpto;
-  PrintDebug("lastexcpto: hi: 0x%.8x, lo: 0x%.8x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
+  PrintDebug("lastexcpto: hi: 0x%x, lo: 0x%x\n", tmp_reg.e_reg.high, tmp_reg.e_reg.low);
 
 
 
index c010167..4502a80 100644 (file)
 #include <palacios/vmm_decoder.h>
 
 v3_cpu_arch_t v3_cpu_type;
-struct vmm_os_hooks * os_hooks = NULL;
+struct v3_os_hooks * os_hooks = NULL;
 
 
 
-struct guest_info * allocate_guest() {
+static struct guest_info * allocate_guest() {
   void * info = V3_Malloc(sizeof(struct guest_info));
   memset(info, 0, sizeof(struct guest_info));
   return info;
@@ -38,19 +38,19 @@ struct guest_info * allocate_guest() {
 
 
 
-void Init_V3(struct vmm_os_hooks * hooks, struct vmm_ctrl_ops * vmm_ops) {
+void Init_V3(struct v3_os_hooks * hooks, struct v3_ctrl_ops * vmm_ops) {
   os_hooks = hooks;
 
   v3_cpu_type = V3_INVALID_CPU;
 
-  init_decoder();
+  v3_init_decoder();
 
-  if (is_svm_capable()) {
+  if (v3_is_svm_capable()) {
 
     PrintDebug("Machine is SVM Capable\n");
     vmm_ops->allocate_guest = &allocate_guest;
-    vmm_ops->config_guest = &config_guest;
-    Init_SVM(vmm_ops);
+    vmm_ops->config_guest = &v3_config_guest;
+    v3_init_SVM(vmm_ops);
 
     /*
   } else if (is_vmx_capable()) {
index 3533e72..f7ae6e3 100644 (file)
 #include <devices/generic.h>
 #include <devices/ramdisk.h>
 #include <devices/cdrom.h>
+#include <devices/bochs_debug.h>
 
 
-#define USE_GENERIC 1
-
-#define MAGIC_CODE 0xf1e2d3c4
-
+#include <palacios/vmm_host_events.h>
 
+#define USE_GENERIC 1
 
-struct layout_region {
-  ulong_t length;
-  ulong_t final_addr;
-};
 
-struct guest_mem_layout {
-  ulong_t magic;
-  ulong_t num_regions;
-  struct layout_region regions[0];
-};
+#define ROMBIOS_START 0x000f0000
+#define VGABIOS_START 0x000c0000
 
 
 
@@ -59,7 +51,7 @@ static int mem_test_read(addr_t guest_addr, void * dst, uint_t length, void * pr
 
   memcpy(dst, &foo, length);
 
-  PrintDebug("Passthrough mem read returning: %d (length=%d)\n", foo + (guest_addr & 0xfff), length);
+  PrintDebug("Passthrough mem read returning: %p (length=%d)\n", (void *)(foo + (guest_addr & 0xfff)), length);
   return length;
 }
 
@@ -74,31 +66,10 @@ static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, v
 }
 
 
-/*static int IO_Read(ushort_t port, void * dst, uint_t length, void * priv_data) {
-
-  struct guest_info * info = priv_data;
-  ulong_t tsc_spread = 0;
-  ullong_t exit_tsc = 0;
-
-  
-  *(ulong_t *)(&exit_tsc) = info->vm_regs.rbx;
-  *(ulong_t *)((&exit_tsc) + 4) = info->vm_regs.rcx; 
-  tsc_spread = info->exit_tsc - exit_tsc;
-  
-  PrintError("IOREAD tsc diff = %lu\n",tsc_spread); 
-  info->rip += 3;
-
-
-  return 1;
-}
-*/
-
-int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
 
-  struct guest_mem_layout * layout = (struct guest_mem_layout *)config_ptr->vm_kernel;
+int v3_config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
   extern v3_cpu_arch_t v3_cpu_type;
-  void * region_start;
-  int i;
+
 
   int use_ramdisk = config_ptr->use_ramdisk;
   int use_generic = USE_GENERIC;
@@ -110,7 +81,7 @@ int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
   if (v3_cpu_type == V3_SVM_REV3_CPU) {
     info->shdw_pg_mode = NESTED_PAGING;
   } else {
-    init_shadow_page_state(info);
+    v3_init_shadow_page_state(info);
     info->shdw_pg_mode = SHADOW_PAGING;
   }
   
@@ -118,45 +89,50 @@ int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
   info->mem_mode = PHYSICAL_MEM;
   
  
-  init_vmm_io_map(info);
-  init_interrupt_state(info);
+  v3_init_vmm_io_map(info);
+  v3_init_interrupt_state(info);
   
-  dev_mgr_init(info);
+  v3_init_dev_mgr(info);
 
-  init_emulator(info);
+  v3_init_emulator(info);
   
+  v3_init_host_events(info);
+
  
-  //     SerialPrint("Guest Mem Dump at 0x%x\n", 0x100000);
-  //PrintDebugMemDump((unsigned char *)(0x100000), 261 * 1024);
-  if (layout->magic != MAGIC_CODE) {
+
+  /* layout rombios */
+  {
+    uint_t num_pages = (config_ptr->rombios_size + PAGE_SIZE - 1) / PAGE_SIZE;
+    void * guest_mem =  V3_AllocPages(num_pages);
+
+    PrintDebug("Layout Region %d bytes\n", config_ptr->rombios_size);
+    memcpy(V3_VAddr(guest_mem), config_ptr->rombios, config_ptr->rombios_size);
+
+    add_shadow_region_passthrough(info, ROMBIOS_START, ROMBIOS_START + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
     
-    PrintDebug("Layout Magic Mismatch (0x%x)\n", layout->magic);
-    return -1;
+    PrintDebug("Adding Shadow Region (0x%p-0x%p) -> 0x%p\n", 
+              (void *)ROMBIOS_START, 
+              (void *)ROMBIOS_START + (num_pages * PAGE_SIZE), 
+              (void *)guest_mem);
   }
-  
-  PrintDebug("%d layout regions\n", layout->num_regions);
-  
-  region_start = (void *)&(layout->regions[layout->num_regions]);
-  
-  PrintDebug("region start = 0x%x\n", region_start);
-  
-  for (i = 0; i < layout->num_regions; i++) {
-    struct layout_region * reg = &(layout->regions[i]);
-    uint_t num_pages = (reg->length / PAGE_SIZE) + ((reg->length % PAGE_SIZE) ? 1 : 0);
-    void * guest_mem = V3_AllocPages(num_pages);
-    
-    PrintDebug("Layout Region %d bytes\n", reg->length);
-    memcpy(guest_mem, region_start, reg->length);
-    
-    PrintDebugMemDump((unsigned char *)(guest_mem), 16);
-    
-    add_shadow_region_passthrough(info, reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
-    
-    PrintDebug("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
+
+
+  /* layout vgabios */
+  {
+    uint_t num_pages = (config_ptr->vgabios_size + PAGE_SIZE - 1) / PAGE_SIZE;
+    void * guest_mem =  V3_AllocPages(num_pages);
+
+    PrintDebug("Layout Region %d bytes\n", config_ptr->vgabios_size);
+    memcpy(V3_VAddr(guest_mem), config_ptr->vgabios, config_ptr->vgabios_size);
+
+    add_shadow_region_passthrough(info, VGABIOS_START, VGABIOS_START + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
     
-    region_start += reg->length;
+    PrintDebug("Adding Shadow Region (0x%p-0x%p) -> 0x%p\n", 
+              (void *)VGABIOS_START, 
+              (void *)VGABIOS_START + (num_pages * PAGE_SIZE), 
+              (void *)guest_mem);
   }
-  
+
       //     
   add_shadow_region_passthrough(info, 0x0, 0xa0000, (addr_t)V3_AllocPages(160));
   
@@ -196,18 +172,18 @@ int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
   
   
   print_shadow_map(&(info->mem_map));
-
   
   {
     struct vm_device * ramdisk = NULL;
     struct vm_device * cdrom = NULL;
-    struct vm_device * nvram = create_nvram();
-    //struct vm_device * timer = create_timer();
-    struct vm_device * pic = create_pic();
-    struct vm_device * keyboard = create_keyboard();
-    struct vm_device * pit = create_pit(); 
-
-    //struct vm_device * serial = create_serial();
+    struct vm_device * nvram = v3_create_nvram();
+    //struct vm_device * timer = v3_create_timer();
+    struct vm_device * pic = v3_create_pic();
+    struct vm_device * keyboard = v3_create_keyboard();
+    struct vm_device * pit = v3_create_pit(); 
+    struct vm_device * bochs_debug = v3_create_bochs_debug();
+
+    //struct vm_device * serial = v3_create_serial();
     struct vm_device * generic = NULL;
 
 
@@ -215,14 +191,14 @@ int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
 
     if (use_ramdisk) {
       PrintDebug("Creating Ramdisk\n");
-      ramdisk = create_ramdisk();
+      ramdisk = v3_create_ramdisk();
       cdrom = v3_create_cdrom(ramdisk, config_ptr->ramdisk, config_ptr->ramdisk_size); 
     }
     
     
     if (use_generic) {
       PrintDebug("Creating Generic Device\n");
-      generic = create_generic();
+      generic = v3_create_generic();
       
       // Make the DMA controller invisible
       v3_generic_add_port_range(generic, 0x00, 0x07, GENERIC_PRINT_AND_IGNORE);   // DMA 1 channels 0,1,2,3 (address, counter)
@@ -340,6 +316,7 @@ int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
     v3_attach_device(info, pit);
     v3_attach_device(info, keyboard);
     // v3_attach_device(info, serial);
+    v3_attach_device(info, bochs_debug);
 
     if (use_ramdisk) {
       v3_attach_device(info, ramdisk);
@@ -365,6 +342,8 @@ int config_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
   
 
   if (!use_ramdisk) {
+    PrintDebug("Hooking IDE IRQs\n");
+
     //primary ide
     v3_hook_passthrough_irq(info, 14);
   
index 3dab368..f56c5a6 100644 (file)
@@ -41,7 +41,7 @@
 
 // First Attempt = 494 lines
 // current = 106 lines
-int handle_cr0_write(struct guest_info * info) {
+int v3_handle_cr0_write(struct guest_info * info) {
   uchar_t instr[15];
   int ret;
   struct x86_instr dec_instr;
@@ -66,7 +66,7 @@ int handle_cr0_write(struct guest_info * info) {
   }
 
 
-  if (opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  if (v3_opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
     struct cr0_real *real_cr0  = (struct cr0_real*)&(info->ctrl_regs.cr0);
     struct cr0_real *new_cr0 = (struct cr0_real *)(dec_instr.src_operand.operand);     
     uchar_t new_cr0_val;
@@ -77,21 +77,21 @@ int handle_cr0_write(struct guest_info * info) {
     
     PrintDebug("OperandVal = %x\n", new_cr0_val);
 
-    PrintDebug("Old CR0=%x\n", *real_cr0);     
+    PrintDebug("Old CR0=%x\n", *(uint_t *)real_cr0);   
     *(uchar_t*)real_cr0 &= 0xf0;
     *(uchar_t*)real_cr0 |= new_cr0_val;
-    PrintDebug("New CR0=%x\n", *real_cr0);     
+    PrintDebug("New CR0=%x\n", *(uint_t *)real_cr0);   
       
 
     if (info->shdw_pg_mode == SHADOW_PAGING) {
       struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
       
-      PrintDebug(" Old Shadow CR0=%x\n", *shadow_cr0); 
+      PrintDebug(" Old Shadow CR0=%x\n", *(uint_t *)shadow_cr0);       
       *(uchar_t*)shadow_cr0 &= 0xf0;
       *(uchar_t*)shadow_cr0 |= new_cr0_val;
-      PrintDebug("New Shadow CR0=%x\n", *shadow_cr0);  
+      PrintDebug("New Shadow CR0=%x\n", *(uint_t *)shadow_cr0);        
     }
-  } else if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  } else if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
     PrintDebug("MOV2CR0\n");
 
     if (info->cpu_mode == LONG) {
@@ -101,38 +101,38 @@ int handle_cr0_write(struct guest_info * info) {
        struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
        struct cr0_32 *new_cr0= (struct cr0_32 *)(dec_instr.src_operand.operand);
 
-       PrintDebug("OperandVal = %x, length=%d\n", *new_cr0, dec_instr.src_operand.size);
+       PrintDebug("OperandVal = %x, length=%d\n", *(uint_t *)new_cr0, dec_instr.src_operand.size);
 
 
-       PrintDebug("Old CR0=%x\n", *real_cr0);
+       PrintDebug("Old CR0=%x\n", *(uint_t *)real_cr0);
        *real_cr0 = *new_cr0;
        
 
        if (info->shdw_pg_mode == SHADOW_PAGING) {
          struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
          
-         PrintDebug("Old Shadow CR0=%x\n", *shadow_cr0);       
+         PrintDebug("Old Shadow CR0=%x\n", *(uint_t *)shadow_cr0);     
          
          real_cr0->et = 1;
          
          *shadow_cr0 = *new_cr0;
          shadow_cr0->et = 1;
          
-         if (get_mem_mode(info) == VIRTUAL_MEM) {
+         if (v3_get_mem_mode(info) == VIRTUAL_MEM) {
            struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
-           
+           PrintDebug("Setting up Shadow Page Table\n");
            info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
          } else  {
            info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
            real_cr0->pg = 1;
          }
          
-         PrintDebug("New Shadow CR0=%x\n",*shadow_cr0);
+         PrintDebug("New Shadow CR0=%x\n",*(uint_t *)shadow_cr0);
        }
-       PrintDebug("New CR0=%x\n", *real_cr0);
+       PrintDebug("New CR0=%x\n", *(uint_t *)real_cr0);
     }
 
-  } else if (opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  } else if (v3_opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
     // CLTS
     struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
        
@@ -155,7 +155,7 @@ int handle_cr0_write(struct guest_info * info) {
 
 // First attempt = 253 lines
 // current = 51 lines
-int handle_cr0_read(struct guest_info * info) {
+int v3_handle_cr0_read(struct guest_info * info) {
   uchar_t instr[15];
   int ret;
   struct x86_instr dec_instr;
@@ -179,12 +179,12 @@ int handle_cr0_read(struct guest_info * info) {
     return -1;
   }
   
-  if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
     struct cr0_32 * virt_cr0 = (struct cr0_32 *)(dec_instr.dst_operand.operand);
     struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
     
     PrintDebug("MOVCR2\n");
-    PrintDebug("CR0 at 0x%x\n", real_cr0);
+    PrintDebug("CR0 at 0x%p\n", (void *)real_cr0);
 
     if (info->shdw_pg_mode == SHADOW_PAGING) {
       *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
@@ -194,14 +194,14 @@ int handle_cr0_read(struct guest_info * info) {
     
     PrintDebug("real CR0: %x\n", *(uint_t*)real_cr0);
     PrintDebug("returned CR0: %x\n", *(uint_t*)virt_cr0);
-  } else if (opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  } else if (v3_opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
     struct cr0_real *real_cr0= (struct cr0_real*)&(info->ctrl_regs.cr0);
     struct cr0_real *virt_cr0 = (struct cr0_real *)(dec_instr.dst_operand.operand);
     char cr0_val = *(char*)real_cr0 & 0x0f;
     
     PrintDebug("SMSW\n");
 
-    PrintDebug("CR0 at 0x%x\n", real_cr0);
+    PrintDebug("CR0 at 0x%p\n", real_cr0);
 
     *(char *)virt_cr0 &= 0xf0;
     *(char *)virt_cr0 |= cr0_val;
@@ -220,7 +220,7 @@ int handle_cr0_read(struct guest_info * info) {
 
 // First Attempt = 256 lines
 // current = 65 lines
-int handle_cr3_write(struct guest_info * info) {
+int v3_handle_cr3_write(struct guest_info * info) {
   int ret;
   uchar_t instr[15];
   struct x86_instr dec_instr;
@@ -244,11 +244,11 @@ int handle_cr3_write(struct guest_info * info) {
     return -1;
   }
 
-  if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
 
     PrintDebug("MOV2CR3\n");
 
-    PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
+    PrintDebug("CR3 at 0x%p\n", &(info->ctrl_regs.cr3));
 
     if (info->shdw_pg_mode == SHADOW_PAGING) {
       struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);      
@@ -261,25 +261,34 @@ int handle_cr3_write(struct guest_info * info) {
                 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
       
 
-      cached = cache_page_tables32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
 
+      cached = v3_cache_page_tables32(info, (addr_t)V3_PAddr((void *)(addr_t)CR3_TO_PDE32((void *)*(addr_t *)new_cr3)));
+       
       if (cached == -1) {
        PrintError("CR3 Cache failed\n");
        return -1;
       } else if (cached == 0) {
        addr_t shadow_pt;
        
-       PrintDebug("New CR3 is different - flushing shadow page table\n");      
+       if( info->mem_mode == VIRTUAL_MEM )
+       {
+               PrintDebug("New CR3 is different - flushing shadow page table %p\n", shadow_cr3 );      
        
-       delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
+               delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
+       }
        
-       shadow_pt =  create_new_shadow_pt32();
+       shadow_pt =  v3_create_new_shadow_pt32();
        
-       shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);    
+       shadow_cr3->pdt_base_addr = (addr_t)V3_PAddr((void *)(addr_t)PD32_BASE_ADDR(shadow_pt));
+       PrintDebug( "Created new shadow page table %p\n", shadow_cr3->pdt_base_addr );
+       //PrintDebugPageTables( (pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3) );
+
+
       } else {
        PrintDebug("Reusing cached shadow Page table\n");
       }
       
+      
       shadow_cr3->pwt = new_cr3->pwt;
       shadow_cr3->pcd = new_cr3->pcd;
       
@@ -308,7 +317,7 @@ int handle_cr3_write(struct guest_info * info) {
 
 // first attempt = 156 lines
 // current = 36 lines
-int handle_cr3_read(struct guest_info * info) {
+int v3_handle_cr3_read(struct guest_info * info) {
   uchar_t instr[15];
   int ret;
   struct x86_instr dec_instr;
@@ -332,11 +341,11 @@ int handle_cr3_read(struct guest_info * info) {
     return -1;
   }
 
-  if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
+  if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
     PrintDebug("MOVCR32\n");
     struct cr3_32 * virt_cr3 = (struct cr3_32 *)(dec_instr.dst_operand.operand);
 
-    PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
+    PrintDebug("CR3 at 0x%p\n", &(info->ctrl_regs.cr3));
 
     if (info->shdw_pg_mode == SHADOW_PAGING) {
       *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
index ed98acc..9865dd1 100644 (file)
@@ -36,7 +36,7 @@ void PrintDebugMemDump(uchar_t *start, int n)
   int i, j;
 
   for (i = 0; i < n; i += 16) {
-    PrintDebug("%8x", (start + i));
+    PrintDebug("%p", (void *)(start + i));
 
     for (j = i; (j < (i + 16)) && (j < n); j += 2) {
       PrintDebug(" ");
index 8aca0e6..593b038 100644 (file)
@@ -21,7 +21,7 @@
 #include <palacios/vmm_decoder.h>
 
 
-int opcode_cmp(const uchar_t * op1, const uchar_t * op2) {
+int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2) {
   if (op1[0] != op2[0]) {
     return op1[0] - op2[0];;
   } else {
@@ -30,7 +30,7 @@ int opcode_cmp(const uchar_t * op1, const uchar_t * op2) {
 }
 
 
-void strip_rep_prefix(uchar_t * instr, int length) {
+void v3_strip_rep_prefix(uchar_t * instr, int length) {
   int read_ctr = 0;
   int write_ctr = 0;
   int found = 0;
index bc9a940..a49e25d 100644 (file)
 #include <palacios/vmm_decoder.h>
 
 
-
-#ifndef NULL
-#define NULL 0
+#ifndef DEBUG_DEV_MGR
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
 #endif
 
-int dev_mgr_init(struct guest_info * info) {
+
+
+int v3_init_dev_mgr(struct guest_info * info) {
   struct vmm_dev_mgr * mgr = &(info->dev_mgr);
   INIT_LIST_HEAD(&(mgr->dev_list));
   mgr->num_devs = 0;
@@ -41,14 +43,14 @@ int dev_mgr_init(struct guest_info * info) {
 }
 
 
-int dev_mgr_deinit(struct guest_info * info) {
+int v3_dev_mgr_deinit(struct guest_info * info) {
   struct vm_device * dev;
   struct vmm_dev_mgr * mgr = &(info->dev_mgr);
   struct vm_device * tmp;
 
   list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
     v3_unattach_device(dev);
-    free_device(dev);
+    v3_free_device(dev);
   }
 
   return 0;
@@ -74,14 +76,14 @@ static int dev_mgr_remove_device(struct vmm_dev_mgr * mgr, struct vm_device * de
 
 
 /* IO HOOKS */
-int dev_mgr_add_io_hook(struct vmm_dev_mgr * mgr, struct dev_io_hook * hook) {
+static int dev_mgr_add_io_hook(struct vmm_dev_mgr * mgr, struct dev_io_hook * hook) {
   list_add(&(hook->mgr_list), &(mgr->io_hooks));
   mgr->num_io_hooks++;
   return 0;
 }
 
 
-int dev_mgr_remove_io_hook(struct vmm_dev_mgr * mgr, struct dev_io_hook * hook) {
+static int dev_mgr_remove_io_hook(struct vmm_dev_mgr * mgr, struct dev_io_hook * hook) {
   list_del(&(hook->mgr_list));
   mgr->num_io_hooks--;
 
@@ -89,14 +91,14 @@ int dev_mgr_remove_io_hook(struct vmm_dev_mgr * mgr, struct dev_io_hook * hook)
 }
 
 
-int dev_add_io_hook(struct vm_device * dev, struct dev_io_hook * hook) {
+static int dev_add_io_hook(struct vm_device * dev, struct dev_io_hook * hook) {
   list_add(&(hook->dev_list), &(dev->io_hooks));
   dev->num_io_hooks++;
   return 0;
 }
 
 
-int dev_remove_io_hook(struct vm_device * dev, struct dev_io_hook * hook) {
+static int dev_remove_io_hook(struct vm_device * dev, struct dev_io_hook * hook) {
   list_del(&(hook->dev_list));
   dev->num_io_hooks--;
 
@@ -107,8 +109,8 @@ int dev_remove_io_hook(struct vm_device * dev, struct dev_io_hook * hook) {
 
 
 
-struct dev_io_hook * dev_mgr_find_io_hook(struct vmm_dev_mgr * mgr, ushort_t port) {
-  struct dev_io_hook * tmp;
+static struct dev_io_hook * dev_mgr_find_io_hook(struct vmm_dev_mgr * mgr, ushort_t port) {
+  struct dev_io_hook * tmp = NULL;
 
   list_for_each_entry(tmp, &(mgr->io_hooks), mgr_list) {
     if (tmp->port == port) {
@@ -118,8 +120,10 @@ struct dev_io_hook * dev_mgr_find_io_hook(struct vmm_dev_mgr * mgr, ushort_t por
   return NULL;
 }
 
-struct dev_io_hook * dev_find_io_hook(struct vm_device * dev, ushort_t port) {
-  struct dev_io_hook * tmp;
+
+/*
+static struct dev_io_hook * dev_find_io_hook(struct vm_device * dev, ushort_t port) {
+  struct dev_io_hook * tmp = NULL;
 
   list_for_each_entry(tmp, &(dev->io_hooks), dev_list) {
     if (tmp->port == port) {
@@ -128,15 +132,15 @@ struct dev_io_hook * dev_find_io_hook(struct vm_device * dev, ushort_t port) {
   }
   return NULL;
 }
+*/
 
 
 
-
-int dev_hook_io(struct vm_device   *dev,
-               ushort_t            port,
-               int (*read)(ushort_t port, void * dst, uint_t length, struct vm_device * dev),
-               int (*write)(ushort_t port, void * src, uint_t length, struct vm_device * dev)) {
-
+int v3_dev_hook_io(struct vm_device   *dev,
+                  ushort_t            port,
+                  int (*read)(ushort_t port, void * dst, uint_t length, struct vm_device * dev),
+                  int (*write)(ushort_t port, void * src, uint_t length, struct vm_device * dev)) {
+  
   struct dev_io_hook *hook = (struct dev_io_hook *)V3_Malloc(sizeof(struct dev_io_hook));
   
   if (!hook) { 
@@ -165,7 +169,7 @@ int dev_hook_io(struct vm_device   *dev,
 }
 
 
-int dev_unhook_io(struct vm_device   *dev,
+int v3_dev_unhook_io(struct vm_device   *dev,
                  ushort_t            port) {
 
   struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
@@ -205,11 +209,11 @@ int v3_unattach_device(struct vm_device * dev) {
 
 
 
-
-int dev_mgr_hook_mem(struct guest_info    *vm,
-                    struct vm_device   *device,
-                    void               *start,
-                    void               *end)
+#if 0
+static int dev_mgr_hook_mem(struct guest_info    *vm,
+                           struct vm_device   *device,
+                           void               *start,
+                           void               *end)
 {
 
   struct dev_mem_hook * hook = (struct dev_mem_hook*)V3_Malloc(sizeof(struct dev_mem_hook));
@@ -240,9 +244,9 @@ int dev_mgr_hook_mem(struct guest_info    *vm,
 }
 
 
-int dev_mgr_unhook_mem(struct vm_device   *dev,
-                      addr_t start,
-                      addr_t end)  {
+static int dev_mgr_unhook_mem(struct vm_device   *dev,
+                             addr_t start,
+                             addr_t end)  {
   /*
   struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
   struct dev_mem_hook *hook = dev_mgr_find_mem_hook(mgr, start, end);
@@ -261,9 +265,10 @@ int dev_mgr_unhook_mem(struct vm_device   *dev,
   */
   return -1;
 }
+#endif
 
 
-
+#ifdef DEBUG_DEV_MGR
 
 void PrintDebugDevMgr(struct guest_info * info) {
   struct vmm_dev_mgr * mgr = &(info->dev_mgr);
@@ -300,3 +305,10 @@ void PrintDebugDevIO(struct vm_device * dev) {
 
   return;
 }
+
+#else 
+void PrintDebugDevMgr(struct guest_info * info) {}
+void PrintDebugDev(struct vm_device * dev) {}
+void PrintDebugDevMgrIO(struct vmm_dev_mgr * mgr) {}
+void PrintDebugDevIO(struct vm_device * dev) {}
+#endif
index 3294aa0..db53ca8 100644 (file)
@@ -33,7 +33,7 @@ static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
 #endif
 
 
-int init_emulator(struct guest_info * info) {
+int v3_init_emulator(struct guest_info * info) {
   struct emulation_state * emulator = &(info->emulator);
 
   emulator->num_emulated_pages = 0;
@@ -55,7 +55,7 @@ int init_emulator(struct guest_info * info) {
 }
 
 static addr_t get_new_page() {
-  void * page = V3_AllocPages(1);
+  void * page = V3_VAddr(V3_AllocPages(1));
   memset(page, 0, PAGE_SIZE);
 
   return (addr_t)page;
@@ -154,6 +154,11 @@ int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
   }
 
+  if (ret == -1) {
+    PrintError("Could not read guest memory\n");
+    return -1;
+  }
+
 #ifdef DEBUG_EMULATOR
   PrintDebug("Instr (15 bytes) at %x:\n", instr);
   PrintTraceMemDump(instr, 15);
@@ -179,13 +184,14 @@ int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
   data_page->pte.present = 1;
   data_page->pte.writable = 0;
   data_page->pte.user_page = 1;
-  data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
+  data_page->pte.page_base_addr = PT32_BASE_ADDR((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr)));
 
 
   // Read the data directly onto the emulated page
-  if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
+  ret = read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data);
+  if ((ret == -1) || ((uint_t)ret != instr_info.op_size)) {
     PrintError("Read error in emulator\n");
-    V3_FreePage((void *)(data_page->page_addr));
+    V3_FreePage((void *)V3_PAddr((void *)(data_page->page_addr)));
     V3_Free(data_page);
     return -1;
   }
@@ -269,7 +275,7 @@ int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
   data_page->pte.present = 1;
   data_page->pte.writable = 1;
   data_page->pte.user_page = 1;
-  data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
+  data_page->pte.page_base_addr = PT32_BASE_ADDR((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr)));
 
 
 
@@ -345,7 +351,7 @@ int v3_emulation_exit_handler(struct guest_info * info) {
     PrintDebug("wiping page %x\n", empg->va); 
 
     v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
-    V3_FreePage((void *)(empg->page_addr));
+    V3_FreePage((void *)(V3_PAddr((void *)(empg->page_addr))));
 
     list_del(&(empg->page_list));
     V3_Free(empg);
index 65dbca1..612ae78 100644 (file)
@@ -125,7 +125,7 @@ ulong_t hash_long(ulong_t val, uint_t bits) {
 ulong_t hash_buffer(uchar_t * msg, uint_t length) {
   ulong_t hash = 0;
   ulong_t temp = 0;
-  int i;
+  uint_t i;
 
   for (i = 0; i < length; i++) {
     hash = (hash << 4) + *(msg + i) + i;
diff --git a/palacios/src/palacios/vmm_host_events.c b/palacios/src/palacios/vmm_host_events.c
new file mode 100644 (file)
index 0000000..b9d122a
--- /dev/null
@@ -0,0 +1,110 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_host_events.h>
+
+
+int v3_init_host_events(struct guest_info * info) {
+  struct v3_host_events * host_evts = &(info->host_event_hooks);
+
+  INIT_LIST_HEAD(&(host_evts->keyboard_events));
+  INIT_LIST_HEAD(&(host_evts->mouse_events));
+  INIT_LIST_HEAD(&(host_evts->timer_events));
+
+  return 0;
+}
+
+
+int v3_hook_host_event(struct guest_info * info, 
+                      v3_host_evt_type_t event_type, 
+                      union v3_host_event_handler cb, 
+                      void * private_data) {
+  
+  struct v3_host_events * host_evts = &(info->host_event_hooks);
+  struct v3_host_event_hook * hook = NULL;
+
+  hook = (struct v3_host_event_hook *)V3_Malloc(sizeof(struct v3_host_event_hook));
+  if (hook == NULL) {
+    PrintError("Could not allocate event hook\n");
+    return -1;
+  }
+
+  hook->cb = cb;
+  hook->private_data = private_data;
+
+  switch (event_type)  {
+  case HOST_KEYBOARD_EVT:
+    list_add(&(hook->link), &(host_evts->keyboard_events));
+    break;
+  case HOST_MOUSE_EVT:
+    list_add(&(hook->link), &(host_evts->mouse_events));
+    break;
+  case HOST_TIMER_EVT:
+    list_add(&(hook->link), &(host_evts->timer_events));
+    break;
+  }
+
+  return 0;
+}
+
+
+int v3_deliver_keyboard_event(struct guest_info * info, 
+                             struct v3_keyboard_event * evt) {
+  struct v3_host_events * host_evts = &(info->host_event_hooks);
+  struct v3_host_event_hook * hook = NULL;
+
+  list_for_each_entry(hook, &(host_evts->keyboard_events), link) {
+    if (hook->cb.keyboard_handler(info, evt, hook->private_data) == -1) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+
+int v3_deliver_mouse_event(struct guest_info * info, 
+                          struct v3_mouse_event * evt) {
+  struct v3_host_events * host_evts = &(info->host_event_hooks);
+  struct v3_host_event_hook * hook = NULL;
+
+  list_for_each_entry(hook, &(host_evts->mouse_events), link) {
+    if (hook->cb.mouse_handler(info, evt, hook->private_data) == -1) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+
+int v3_deliver_timer_event(struct guest_info * info, 
+                          struct v3_timer_event * evt) {
+  struct v3_host_events * host_evts = &(info->host_event_hooks);
+  struct v3_host_event_hook * hook = NULL;
+
+  list_for_each_entry(hook, &(host_evts->timer_events), link) {
+    if (hook->cb.timer_handler(info, evt, hook->private_data) == -1) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
index 6bdca1a..46e1e42 100644 (file)
 
 
 
-void init_interrupt_state(struct guest_info * info) {
+void v3_init_interrupt_state(struct guest_info * info) {
   info->intr_state.excp_pending = 0;
   info->intr_state.excp_num = 0;
   info->intr_state.excp_error_code = 0;
 
   memset((uchar_t *)(info->intr_state.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
-
-  info->vm_ops.raise_irq = &v3_raise_irq;
-  info->vm_ops.lower_irq = &v3_lower_irq; 
 }
 
-void set_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * state) {
+void v3_set_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * state) {
   info->intr_state.controller = ops;
   info->intr_state.controller_state = state;
 }
@@ -91,7 +88,8 @@ int v3_hook_irq(struct guest_info * info,
 static int passthrough_irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * priv_data)
 {
 
-  PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%x)\n", intr->irq, info);
+  PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
+            intr->irq, (void *)info);
   return v3_raise_irq(info, intr->irq);
 
 }
@@ -105,10 +103,10 @@ int v3_hook_passthrough_irq(struct guest_info * info, uint_t irq)
                       NULL);
 
   if (rc) { 
-    PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%x)\n", irq, info);
+    PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)info);
     return -1;
   } else {
-    PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%x)\n", irq, info);
+    PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)info);
     return 0;
   }
 }
@@ -118,7 +116,7 @@ int v3_hook_passthrough_irq(struct guest_info * info, uint_t irq)
 
 
 int v3_deliver_irq(struct guest_info * info, struct v3_interrupt * intr) {
-  PrintDebug("v3_deliver_irq: irq=%d state=0x%x, \n", intr->irq, intr);
+  PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
   
   struct v3_irq_hook * hook = get_irq_hook(info, intr->irq);
 
@@ -183,7 +181,7 @@ int v3_lower_irq(struct guest_info * info, int irq) {
       (info->intr_state.controller->lower_intr)) {
     info->intr_state.controller->lower_intr(info->intr_state.controller_state, irq);
   } else {
-    PrintDebug("There is no registered Interrupt Controller... (NULL POINTER)\n");
+    PrintError("There is no registered Interrupt Controller... (NULL POINTER)\n");
     return -1;
   }
 
@@ -202,16 +200,16 @@ int v3_raise_irq(struct guest_info * info, int irq) {
       (info->intr_state.controller->raise_intr)) {
     info->intr_state.controller->raise_intr(info->intr_state.controller_state, irq);
   } else {
-    PrintDebug("There is no registered Interrupt Controller... (NULL POINTER)\n");
+    PrintError("There is no registered Interrupt Controller... (NULL POINTER)\n");
     return -1;
   }
 
   return 0;
 }
 
 
-int intr_pending(struct guest_info * info) {
+
+int v3_intr_pending(struct guest_info * info) {
   struct v3_intr_state * intr_state = &(info->intr_state);
 
   //  PrintDebug("[intr_pending]\n");
@@ -227,7 +225,7 @@ int intr_pending(struct guest_info * info) {
 }
 
 
-uint_t get_intr_number(struct guest_info * info) {
+uint_t v3_get_intr_number(struct guest_info * info) {
   struct v3_intr_state * intr_state = &(info->intr_state);
 
   if (intr_state->excp_pending == 1) {
@@ -243,7 +241,7 @@ uint_t get_intr_number(struct guest_info * info) {
 }
 
 
-intr_type_t get_intr_type(struct guest_info * info) {
+intr_type_t v3_get_intr_type(struct guest_info * info) {
   struct v3_intr_state * intr_state = &(info->intr_state);
 
   if (intr_state->excp_pending) {
@@ -262,7 +260,7 @@ intr_type_t get_intr_type(struct guest_info * info) {
 
 
 
-int injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
+int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
   struct v3_intr_state * intr_state = &(info->intr_state);
 
   if (type == EXCEPTION) {
index b056441..514d8e1 100644 (file)
@@ -34,7 +34,7 @@ static int default_write(ushort_t port, void *src, uint_t length, void * priv_da
 static int default_read(ushort_t port, void * dst, uint_t length, void * priv_data);
 
 
-void init_vmm_io_map(struct guest_info * info) {
+void v3_init_vmm_io_map(struct guest_info * info) {
   struct vmm_io_map * io_map = &(info->io_map);
   io_map->num_ports = 0;
   io_map->head = NULL;
@@ -170,13 +170,15 @@ struct vmm_io_hook * v3_get_io_hook(struct vmm_io_map * io_map, uint_t port) {
 
 
 
-void PrintDebugIOMap(struct vmm_io_map * io_map) {
+void v3_print_io_map(struct vmm_io_map * io_map) {
   struct vmm_io_hook * iter = io_map->head;
 
   PrintDebug("VMM IO Map (Entries=%d)\n", io_map->num_ports);
 
   while (iter) {
-    PrintDebug("IO Port: %hu (Read=%x) (Write=%x)\n", iter->port, iter->read, iter->write);
+    PrintDebug("IO Port: %hu (Read=%p) (Write=%p)\n", 
+              iter->port, 
+              (void *)(iter->read), (void *)(iter->write));
   }
 }
 
diff --git a/palacios/src/palacios/vmm_lowlevel.asm b/palacios/src/palacios/vmm_lowlevel.asm
deleted file mode 100644 (file)
index 8b22b5d..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-; -*- fundamental -*-
-;;
-;; This file is part of the Palacios Virtual Machine Monitor developed
-;; by the V3VEE Project with funding from the United States National 
-;; Science Foundation and the Department of Energy.  
-;;
-;; The V3VEE Project is a joint project between Northwestern University
-;; and the University of New Mexico.  You can find out more at 
-;; http://www.v3vee.org
-;;
-;; Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
-;; Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
-;; All rights reserved.
-;;
-;; Author: Jack Lange <jarusl@cs.northwestern.edu>
-;;
-;; This is free software.  You are permitted to use,
-;; redistribute, and modify it as specified in the file "V3VEE_LICENSE"
-;;
-
-%ifndef VMM_ASM
-%define VMM_ASM
-
-%include "vmm_symbol.asm"
-
-EXPORT DisableInts
-EXPORT EnableInts
-
-EXPORT GetGDTR
-EXPORT GetIDTR
-EXPORT GetTR
-
-
-; CPUID functions
-EXPORT cpuid_ecx
-EXPORT cpuid_eax
-EXPORT cpuid_edx
-
-; Utility Functions
-EXPORT Set_MSR
-EXPORT Get_MSR
-
-
-
-align 8
-DisableInts:
-       cli
-       ret
-
-
-align 8
-EnableInts:
-       sti
-       ret
-
-align 8
-GetGDTR:
-       push    ebp
-       mov     ebp, esp
-       pusha   
-       mov     ebx, [ebp + 8]
-       sgdt    [ebx]
-       
-       popa
-       pop     ebp
-       ret
-
-
-align 8
-GetIDTR:
-       push    ebp
-       mov     ebp, esp
-       pusha   
-
-       mov     ebx, [ebp + 8]
-       sidt    [ebx]
-       
-       popa
-       pop     ebp
-       ret
-
-
-
-align 8
-GetTR:
-       push    ebp
-       mov     ebp, esp
-       pusha   
-       mov     ebx, [ebp + 8]
-       str     [ebx]
-       
-       popa
-       pop     ebp
-       ret
-
-
-;
-; cpuid_edx - return the edx register from cpuid
-;
-align 8
-cpuid_edx:
-       push    ebp
-       mov     ebp, esp
-       push    edx
-       push    ecx
-       push    ebx
-
-       mov     eax, [ebp + 8]
-       cpuid
-       mov     eax, edx
-
-       pop     ebx
-       pop     ecx
-       pop     edx
-       pop     ebp
-       ret
-
-
-;
-; cpuid_ecx - return the ecx register from cpuid
-;
-align 8
-cpuid_ecx:
-       push    ebp
-       mov     ebp, esp
-       push    edx
-       push    ecx
-       push    ebx
-
-       mov     eax, [ebp + 8]
-       cpuid
-       mov     eax, ecx
-
-       pop     ebx
-       pop     ecx
-       pop     edx
-       pop     ebp
-       ret
-
-;
-; cpuid_eax - return the eax register from cpuid
-;
-align 8
-cpuid_eax:
-       push    ebp
-       mov     ebp, esp
-       push    edx
-       push    ecx
-       push    ebx
-
-       mov     eax, [esp+4]
-       cpuid
-
-       pop     ebx
-       pop     ecx
-       pop     edx
-       pop     ebp
-       ret
-
-;
-; Set_MSR  - Set the value of a given MSR
-;
-align 8
-Set_MSR:
-       push    ebp
-       mov     ebp, esp
-       pusha
-       mov     eax, [ebp+16]
-       mov     edx, [ebp+12]
-       mov     ecx, [ebp+8]
-       wrmsr
-       popa
-       pop     ebp
-       ret
-
-
-
-;
-; Get_MSR  -  Get the value of a given MSR
-; void Get_MSR(int MSR, void * high_byte, void * low_byte);
-;
-align 8
-Get_MSR:
-       push    ebp
-       mov     ebp, esp
-       pusha
-       mov     ecx, [ebp+8]
-       rdmsr
-       mov     ebx, [ebp+12]
-       mov     [ebx], edx
-       mov     ebx, [ebp+16]
-       mov     [ebx], eax
-       popa
-       pop     ebp
-       ret
-
-
-
-
-
-%endif
index c10f446..1b9f16d 100644 (file)
@@ -81,7 +81,7 @@ struct vmm_mem_hook * get_mem_hook(struct guest_info * info, addr_t guest_addr)
   struct shadow_region * region = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
 
   if (region == NULL) {
-    PrintDebug("Could not find shadow region for addr: %x\n", guest_addr);
+    PrintDebug("Could not find shadow region for addr: %p\n", (void *)guest_addr);
     return NULL;
   }
 
@@ -122,6 +122,8 @@ int handle_special_page_fault(struct guest_info * info,
 {
   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa);
 
+  PrintDebug("Handling Special Page Fault\n");
+
   switch (reg->host_type) {
   case HOST_REGION_HOOK:
     return mem_hook_dispatch(info, fault_gva, fault_gpa, access_info, (struct vmm_mem_hook *)(reg->host_addr));
@@ -165,7 +167,8 @@ int add_shadow_region(struct shadow_map * map,
 {
   struct shadow_region * cursor = map->head;
 
-  PrintDebug("Adding Shadow Region: (0x%x-0x%x)\n", region->guest_start, region->guest_end);
+  PrintDebug("Adding Shadow Region: (0x%p-0x%p)\n", 
+            (void *)region->guest_start, (void *)region->guest_end);
 
   if ((!cursor) || (cursor->guest_start >= region->guest_end)) {
     region->prev = NULL;
@@ -306,7 +309,8 @@ void print_shadow_map(struct shadow_map * map) {
   PrintDebug("Memory Layout (regions: %d) \n", map->num_regions);
 
   while (cur) {
-    PrintDebug("%d:  0x%x - 0x%x (%s) -> ", i, cur->guest_start, cur->guest_end - 1,
+    PrintDebug("%d:  0x%p - 0x%p (%s) -> ", i, 
+              (void *)cur->guest_start, (void *)(cur->guest_end - 1),
               cur->guest_type == GUEST_REGION_PHYSICAL_MEMORY ? "GUEST_REGION_PHYSICAL_MEMORY" :
               cur->guest_type == GUEST_REGION_NOTHING ? "GUEST_REGION_NOTHING" :
               cur->guest_type == GUEST_REGION_MEMORY_MAPPED_DEVICE ? "GUEST_REGION_MEMORY_MAPPED_DEVICE" :
@@ -314,7 +318,7 @@ void print_shadow_map(struct shadow_map * map) {
     if (cur->host_type == HOST_REGION_PHYSICAL_MEMORY || 
        cur->host_type == HOST_REGION_UNALLOCATED ||
        cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) { 
-      PrintDebug("0x%x", cur->host_addr);
+      PrintDebug("0x%p", (void *)(cur->host_addr));
     }
     PrintDebug("(%s)\n",
               cur->host_type == HOST_REGION_PHYSICAL_MEMORY ? "HOST_REGION_PHYSICAL_MEMORY" :
index 58d3359..dff74dd 100644 (file)
@@ -26,6 +26,9 @@
 
 
 
+  
+
+
 void delete_page_tables_pde32(pde32_t * pde) {
   int i;//, j;
 
@@ -36,7 +39,8 @@ void delete_page_tables_pde32(pde32_t * pde) {
   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) {
     if (pde[i].present) {
       // We double cast, first to an addr_t to handle 64 bit issues, then to the pointer
-      pte32_t * pte = (pte32_t *)((addr_t)(pde[i].pt_base_addr << PAGE_POWER));
+      PrintDebug("PTE base addr %x \n", pde[i].pt_base_addr);
+      pte32_t * pte = (pte32_t *)((addr_t)(uint_t)(pde[i].pt_base_addr << PAGE_POWER));
 
       /*
        for (j = 0; (j < MAX_PTE32_ENTRIES); j++) {
@@ -45,13 +49,13 @@ void delete_page_tables_pde32(pde32_t * pde) {
        }
        }
       */
-      //PrintDebug("Deleting PTE %d (%x)\n", i, pte);
+      PrintDebug("Deleting PTE %d (%p)\n", i, pte);
       V3_FreePage(pte);
     }
   }
 
-  //  PrintDebug("Deleting PDE (%x)\n", pde);
-  V3_FreePage(pde);
+  PrintDebug("Deleting PDE (%p)\n", pde);
+  V3_FreePage(V3_PAddr(pde));
 }
 
 
@@ -165,16 +169,16 @@ pt_access_status_t can_access_pte32(pte32_t * pte, addr_t addr, pf_error_t acces
  * pulling pages from the mem_list when necessary
  * If there are any gaps in the layout, we add them as unmapped pages
  */
-pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
-  ullong_t current_page_addr = 0;
+pde32_t * create_passthrough_pts_32(struct guest_info * guest_info) {
+  addr_t current_page_addr = 0;
   int i, j;
   struct shadow_map * map = &(guest_info->mem_map);
 
-  pde32_t * pde = V3_AllocPages(1);
+  pde32_t * pde = V3_VAddr(V3_AllocPages(1));
 
   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
     int pte_present = 0;
-    pte32_t * pte = V3_AllocPages(1);
+    pte32_t * pte = V3_VAddr(V3_AllocPages(1));
     
 
     for (j = 0; j < MAX_PTE32_ENTRIES; j++) {
@@ -225,7 +229,7 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
     }
 
     if (pte_present == 0) { 
-      V3_FreePage(pte);
+      V3_FreePage(V3_PAddr(pte));
 
       pde[i].present = 0;
       pde[i].writable = 0;
@@ -249,7 +253,7 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
       pde[i].large_page = 0;
       pde[i].global_page = 0;
       pde[i].vmm_info = 0;
-      pde[i].pt_base_addr = PAGE_ALIGNED_ADDR((addr_t)pte);
+      pde[i].pt_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pte));
     }
 
   }
@@ -260,12 +264,186 @@ pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info) {
 
 
 
+pml4e64_t * create_passthrough_pts_64(struct guest_info * info) {
+  addr_t current_page_addr = 0;
+  int i, j, k, m;
+  struct shadow_map * map = &(info->mem_map);
+  
+  pml4e64_t * pml = V3_VAddr(V3_AllocPages(1));
+
+  for (i = 0; i < 1; i++) {
+    int pdpe_present = 0;
+    pdpe64_t * pdpe = V3_VAddr(V3_AllocPages(1));
+
+    for (j = 0; j < 1; j++) {
+      int pde_present = 0;
+      pde64_t * pde = V3_VAddr(V3_AllocPages(1));
+
+      for (k = 0; k < MAX_PDE64_ENTRIES; k++) {
+       int pte_present = 0;
+       pte64_t * pte = V3_VAddr(V3_AllocPages(1));
+
+
+       for (m = 0; m < MAX_PTE64_ENTRIES; m++) {
+         struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr);
+         
+
+         
+         if (!region || 
+             (region->host_type == HOST_REGION_HOOK) || 
+             (region->host_type == HOST_REGION_UNALLOCATED) || 
+             (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || 
+             (region->host_type == HOST_REGION_REMOTE) ||
+             (region->host_type == HOST_REGION_SWAPPED)) {
+           pte[m].present = 0;
+           pte[m].writable = 0;
+           pte[m].user_page = 0;
+           pte[m].write_through = 0;
+           pte[m].cache_disable = 0;
+           pte[m].accessed = 0;
+           pte[m].dirty = 0;
+           pte[m].pte_attr = 0;
+           pte[m].global_page = 0;
+           pte[m].vmm_info = 0;
+           pte[m].page_base_addr = 0;
+         } else {
+           addr_t host_addr;
+           pte[m].present = 1;
+           pte[m].writable = 1;
+           pte[m].user_page = 1;
+           pte[m].write_through = 0;
+           pte[m].cache_disable = 0;
+           pte[m].accessed = 0;
+           pte[m].dirty = 0;
+           pte[m].pte_attr = 0;
+           pte[m].global_page = 0;
+           pte[m].vmm_info = 0;
+           
+           if (guest_pa_to_host_pa(info, current_page_addr, &host_addr) == -1) {
+             // BIG ERROR
+             // PANIC
+             return NULL;
+           }
+
+           pte[m].page_base_addr = PTE64_BASE_ADDR(host_addr);
+
+           //PrintPTE64(current_page_addr, &(pte[m]));
+
+           pte_present = 1;      
+         }
+
+
+
+
+         current_page_addr += PAGE_SIZE;
+       }
+       
+       if (pte_present == 0) {
+         V3_FreePage(V3_PAddr(pte));
+
+         pde[k].present = 0;
+         pde[k].writable = 0;
+         pde[k].user_page = 0;
+         pde[k].write_through = 0;
+         pde[k].cache_disable = 0;
+         pde[k].accessed = 0;
+         pde[k].reserved = 0;
+         pde[k].large_page = 0;
+         //pde[k].global_page = 0;
+         pde[k].vmm_info = 0;
+         pde[k].pt_base_addr = 0;
+       } else {
+         pde[k].present = 1;
+         pde[k].writable = 1;
+         pde[k].user_page = 1;
+         pde[k].write_through = 0;
+         pde[k].cache_disable = 0;
+         pde[k].accessed = 0;
+         pde[k].reserved = 0;
+         pde[k].large_page = 0;
+         //pde[k].global_page = 0;
+         pde[k].vmm_info = 0;
+         pde[k].pt_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pte));
+
+         pde_present = 1;
+       }
+      }
+
+      if (pde_present == 0) {
+       V3_FreePage(V3_PAddr(pde));
+       
+       pdpe[j].present = 0;
+       pdpe[j].writable = 0;
+       pdpe[j].user_page = 0;
+       pdpe[j].write_through = 0;
+       pdpe[j].cache_disable = 0;
+       pdpe[j].accessed = 0;
+       pdpe[j].reserved = 0;
+       pdpe[j].large_page = 0;
+       //pdpe[j].global_page = 0;
+       pdpe[j].vmm_info = 0;
+       pdpe[j].pd_base_addr = 0;
+      } else {
+       pdpe[j].present = 1;
+       pdpe[j].writable = 1;
+       pdpe[j].user_page = 1;
+       pdpe[j].write_through = 0;
+       pdpe[j].cache_disable = 0;
+       pdpe[j].accessed = 0;
+       pdpe[j].reserved = 0;
+       pdpe[j].large_page = 0;
+       //pdpe[j].global_page = 0;
+       pdpe[j].vmm_info = 0;
+       pdpe[j].pd_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pde));
+
+
+       pdpe_present = 1;
+      }
+
+    }
+
+    PrintDebug("PML index=%d\n", i);
+
+    if (pdpe_present == 0) {
+      V3_FreePage(V3_PAddr(pdpe));
+      
+      pml[i].present = 0;
+      pml[i].writable = 0;
+      pml[i].user_page = 0;
+      pml[i].write_through = 0;
+      pml[i].cache_disable = 0;
+      pml[i].accessed = 0;
+      pml[i].reserved = 0;
+      //pml[i].large_page = 0;
+      //pml[i].global_page = 0;
+      pml[i].vmm_info = 0;
+      pml[i].pdp_base_addr = 0;
+    } else {
+      pml[i].present = 1;
+      pml[i].writable = 1;
+      pml[i].user_page = 1;
+      pml[i].write_through = 0;
+      pml[i].cache_disable = 0;
+      pml[i].accessed = 0;
+      pml[i].reserved = 0;
+      //pml[i].large_page = 0;
+      //pml[i].global_page = 0;
+      pml[i].vmm_info = 0;
+      pml[i].pdp_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pdpe));
+    }
+  }
+
+  return pml;
+}
+
+
+
 
 
 void PrintPDE32(addr_t virtual_address, pde32_t * pde)
 {
-  PrintDebug("PDE %x -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
-            virtual_address,
+  PrintDebug("PDE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+            (void *)virtual_address,
             (void *)(addr_t) (pde->pt_base_addr << PAGE_POWER),
             pde->present,
             pde->writable,
@@ -278,11 +456,12 @@ void PrintPDE32(addr_t virtual_address, pde32_t * pde)
             pde->global_page,
             pde->vmm_info);
 }
+
   
 void PrintPTE32(addr_t virtual_address, pte32_t * pte)
 {
   PrintDebug("PTE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
-            virtual_address,
+            (void *)virtual_address,
             (void*)(addr_t)(pte->page_base_addr << PAGE_POWER),
             pte->present,
             pte->writable,
@@ -297,6 +476,45 @@ void PrintPTE32(addr_t virtual_address, pte32_t * pte)
 }
 
 
+void PrintPDE64(addr_t virtual_address, pde64_t * pde)
+{
+  PrintDebug("PDE64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+            (void *)virtual_address,
+            (void *)(addr_t) (pde->pt_base_addr << PAGE_POWER),
+            pde->present,
+            pde->writable,
+            pde->user_page, 
+            pde->write_through,
+            pde->cache_disable,
+            pde->accessed,
+            pde->reserved,
+            pde->large_page,
+            0,//pde->global_page,
+            pde->vmm_info);
+}
+
+  
+void PrintPTE64(addr_t virtual_address, pte64_t * pte)
+{
+  PrintDebug("PTE64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
+            (void *)virtual_address,
+            (void*)(addr_t)(pte->page_base_addr << PAGE_POWER),
+            pte->present,
+            pte->writable,
+            pte->user_page,
+            pte->write_through,
+            pte->cache_disable,
+            pte->accessed,
+            pte->dirty,
+            pte->pte_attr,
+            pte->global_page,
+            pte->vmm_info);
+}
+
+  
+
+
+
 
 void PrintPD32(pde32_t * pde)
 {
@@ -335,7 +553,7 @@ void PrintDebugPageTables(pde32_t * pde)
   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) { 
     if (pde[i].present) {
       PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
-      PrintPT32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), (pte32_t *)(addr_t)(pde[i].pt_base_addr << PAGE_POWER));
+      PrintPT32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), (pte32_t *)V3_VAddr((void *)(addr_t)(pde[i].pt_base_addr << PAGE_POWER)));
     }
   }
 }
index 54347e3..1f8e7a2 100644 (file)
@@ -76,10 +76,8 @@ static int handle_shadow_pte32_fault(struct guest_info* info,
 
 static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
 
-int init_shadow_page_state(struct guest_info * info) {
+int v3_init_shadow_page_state(struct guest_info * info) {
   struct shadow_page_state * state = &(info->shdw_pg_state);
-  state->guest_mode = PDE32;
-  state->shadow_mode = PDE32;
   
   state->guest_cr3 = 0;
   state->shadow_cr3 = 0;
@@ -146,7 +144,7 @@ int cache_page_tables32(struct guest_info * info, addr_t pde) {
 }
 */
 
-int cache_page_tables32(struct guest_info * info, addr_t pde) {
+int v3_cache_page_tables32(struct guest_info * info, addr_t pde) {
   struct shadow_page_state * state = &(info->shdw_pg_state);
   addr_t pde_host_addr;
   pde32_t * tmp_pde;
@@ -167,7 +165,7 @@ int cache_page_tables32(struct guest_info * info, addr_t pde) {
   pte_cache = create_hashtable(0, &pte_hash_fn, &pte_equals);
   state->cached_ptes = pte_cache;
 
-  if (guest_pa_to_host_pa(info, pde, &pde_host_addr) == -1) {
+  if (guest_pa_to_host_va(info, pde, &pde_host_addr) == -1) {
     PrintError("Could not lookup host address of guest PDE\n");
     return -1;
   }
@@ -181,7 +179,7 @@ int cache_page_tables32(struct guest_info * info, addr_t pde) {
     if ((tmp_pde[i].present) && (tmp_pde[i].large_page == 0)) {
       addr_t pte_host_addr;
 
-      if (guest_pa_to_host_pa(info, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), &pte_host_addr) == -1) {
+      if (guest_pa_to_host_va(info, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), &pte_host_addr) == -1) {
        PrintError("Could not lookup host address of guest PDE\n");
        return -1;
       }
@@ -223,7 +221,7 @@ int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t *
 
 
 
-int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
   
   if (info->mem_mode == PHYSICAL_MEM) {
     // If paging is not turned on we need to handle the special cases
@@ -246,10 +244,10 @@ int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_erro
   }
 }
 
-addr_t create_new_shadow_pt32() {
+addr_t v3_create_new_shadow_pt32() {
   void * host_pde = 0;
 
-  host_pde = V3_AllocPages(1);
+  host_pde = V3_VAddr(V3_AllocPages(1));
   memset(host_pde, 0, PAGE_SIZE);
 
   return (addr_t)host_pde;
@@ -322,7 +320,7 @@ static int handle_large_pagefault32(struct guest_info * info,
 
     if (host_page_type == HOST_REGION_INVALID) {
       // Inject a machine check in the guest
-      PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_fault_pa);
+      PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
       v3_raise_exception(info, MC_EXCEPTION);
       return 0;
     }
@@ -361,7 +359,7 @@ static int handle_large_pagefault32(struct guest_info * info,
     } else {
       // Handle hooked pages as well as other special pages
       if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) {
-       PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
+       PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
        return -1;
       }
     }
@@ -387,16 +385,16 @@ static int handle_large_pagefault32(struct guest_info * info,
 static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
   pde32_t * guest_pd = NULL;
   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
-  addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
+  addr_t guest_cr3 = (addr_t) V3_PAddr( CR3_TO_PDE32(info->shdw_pg_state.guest_cr3) );
   pt_access_status_t guest_pde_access;
   pt_access_status_t shadow_pde_access;
   pde32_t * guest_pde = NULL;
   pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
 
-  PrintDebug("Shadow page fault handler\n");
+  PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
 
   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
-    PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
+    PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
     return -1;
   } 
 
@@ -412,7 +410,7 @@ static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr
   /* Was the page fault caused by the Guest's page tables? */
   if (is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
     PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", 
-              guest_pde_access, error_code);
+              *(uint_t *)&guest_pde_access, *(uint_t *)&error_code);
     inject_guest_pf(info, fault_addr, error_code);
     return 0;
   }
@@ -420,7 +418,7 @@ static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr
   
   if (shadow_pde_access == PT_ENTRY_NOT_PRESENT) 
     {
-      pte32_t * shadow_pt =  (pte32_t *)create_new_shadow_pt32();
+      pte32_t * shadow_pt =  (pte32_t *)v3_create_new_shadow_pt32();
 
       shadow_pde->present = 1;
       shadow_pde->user_page = guest_pde->user_page;
@@ -436,11 +434,12 @@ static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr
       
       guest_pde->accessed = 1;
       
-      shadow_pde->pt_base_addr = PD32_BASE_ADDR((addr_t)shadow_pt);
+      shadow_pde->pt_base_addr = PD32_BASE_ADDR((addr_t)V3_PAddr(shadow_pt));
       
       if (guest_pde->large_page == 0) {
        shadow_pde->writable = guest_pde->writable;
       } else {
+       // ??  What if guest pde is dirty a this point?
        ((pde32_4MB_t *)guest_pde)->dirty = 0;
        shadow_pde->writable = 0;
       }
@@ -450,7 +449,7 @@ static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr
       //
       // PTE fault
       //
-      pte32_t * shadow_pt = (pte32_t *)(addr_t)PDE32_T_ADDR((*shadow_pde));
+      pte32_t * shadow_pt = (pte32_t *)V3_VAddr( (void*)(addr_t) PDE32_T_ADDR(*shadow_pde) );
 
       if (guest_pde->large_page == 0) {
        pte32_t * guest_pt = NULL;
@@ -513,7 +512,7 @@ static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr
       return 0; 
     }
 
-  PrintDebug("Returning end of PDE function (rip=%x)\n", info->rip);
+  PrintDebug("Returning end of PDE function (rip=%p)\n", (void *)(info->rip));
   return 0;
 }
 
@@ -574,7 +573,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
 
     if (host_page_type == HOST_REGION_INVALID) {
       // Inject a machine check in the guest
-      PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
+      PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
       v3_raise_exception(info, MC_EXCEPTION);
       return 0;
     }
@@ -600,7 +599,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
       
       if (find_pte_map(state->cached_ptes, PT32_PAGE_ADDR(guest_pa)) != NULL) {
        // Check if the entry is a page table...
-       PrintDebug("Marking page as Guest Page Table\n", shadow_pte->writable);
+       PrintDebug("Marking page as Guest Page Table %d\n", shadow_pte->writable);
        shadow_pte->vmm_info = PT32_GUEST_PT;
       }
 
@@ -617,7 +616,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
          state->cached_cr3 = 0;
        }
 
-      } else if ((guest_pte->dirty = 0) && (error_code.write == 0)) {
+      } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {  // was =
        shadow_pte->writable = 0;
       }
 
@@ -626,7 +625,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
     } else {
       // Page fault handled by hook functions
       if (handle_special_page_fault(info, fault_addr, guest_pa, error_code) == -1) {
-       PrintError("Special Page fault handler returned error for address: %x\n", fault_addr);
+       PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
        return -1;
       }
     }
@@ -664,56 +663,64 @@ static int handle_shadow_pte32_fault(struct guest_info * info,
 
 
 /* Currently Does not work with Segmentation!!! */
-int handle_shadow_invlpg(struct guest_info * info) {
-  if (info->mem_mode != VIRTUAL_MEM) {
-    // Paging must be turned on...
-    // should handle with some sort of fault I think
-    PrintError("ERROR: INVLPG called in non paged mode\n");
-    return -1;
-  }
+int v3_handle_shadow_invlpg(struct guest_info * info)
+{
+       if (info->mem_mode != VIRTUAL_MEM) {
+               // Paging must be turned on...
+               // should handle with some sort of fault I think
+               PrintError("ERROR: INVLPG called in non paged mode\n");
+               return -1;
+       }
 
 
-  if (info->cpu_mode == PROTECTED) {
-    uchar_t instr[15];
-    int ret;
-    int index = 0;
+       if (info->cpu_mode != PROTECTED)
+               return 0;
 
-    ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
-    if (ret != 15) {
-      PrintError("Could not read instruction 0x%x (ret=%d)\n", info->rip, ret);
-      return -1;
-    }
+       uchar_t instr[15];
+       int index = 0;
+
+       int ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+       if (ret != 15) {
+         PrintError("Could not read instruction 0x%p (ret=%d)\n",  (void *)(addr_t)(info->rip), ret);
+               return -1;
+       }
 
    
-    /* Can INVLPG work with Segments?? */
-    while (is_prefix_byte(instr[index])) {
-      index++;
-    }
+       /* Can INVLPG work with Segments?? */
+       while (is_prefix_byte(instr[index])) {
+               index++;
+       }
     
     
-    if ((instr[index] == (uchar_t)0x0f) &&
-       (instr[index + 1] == (uchar_t)0x01)) {
+       if( instr[index + 0] != (uchar_t) 0x0f
+       ||  instr[index + 1] != (uchar_t) 0x01
+       ) {
+               PrintError("invalid Instruction Opcode\n");
+               PrintTraceMemDump(instr, 15);
+               return -1;
+       }
 
-      addr_t first_operand;
-      addr_t second_operand;
-      operand_type_t addr_type;
-      addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
+       addr_t first_operand;
+       addr_t second_operand;
+       addr_t guest_cr3 = (addr_t)V3_PAddr( (void*)(addr_t) CR3_TO_PDE32(info->shdw_pg_state.guest_cr3) );
 
-      pde32_t * guest_pd = NULL;
+       pde32_t * guest_pd = NULL;
 
-      if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
-       PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
-       return -1;
-      }
-
-      
+       if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1)
+       {
+               PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
+               return -1;
+       }
 
+       index += 2;
 
-      index += 2;
+       v3_operand_type_t addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
 
-      addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
+       if (addr_type != MEM_OPERAND) {
+               PrintError("Invalid Operand type\n");
+               return -1;
+       }
 
-      if (addr_type == MEM_OPERAND) {
        pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
        pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
        pde32_t * guest_pde;
@@ -721,42 +728,29 @@ int handle_shadow_invlpg(struct guest_info * info) {
        //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
        //PrintDebug("FirstOperand = %x\n", first_operand);
 
-       PrintDebug("Invalidating page for %x\n", first_operand);
+       PrintDebug("Invalidating page for %p\n", (void *)first_operand);
 
        guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
 
        if (guest_pde->large_page == 1) {
-         shadow_pde->present = 0;
-         PrintDebug("Invalidating Large Page\n");
-       } else {
-        
-         if (shadow_pde->present == 1) {
-           pte32_t * shadow_pt = (pte32_t *)(addr_t)PDE32_T_ADDR((*shadow_pde));
-           pte32_t * shadow_pte = (pte32_t *)&shadow_pt[PTE32_INDEX(first_operand)];
+               shadow_pde->present = 0;
+               PrintDebug("Invalidating Large Page\n");
+       } else
+       if (shadow_pde->present == 1) {
+               pte32_t * shadow_pt = (pte32_t *)(addr_t)PDE32_T_ADDR((*shadow_pde));
+               pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(first_operand)] );
 
 #ifdef DEBUG_SHADOW_PAGING
-           PrintDebug("Setting not present\n");
-           PrintPTE32(first_operand, shadow_pte);
+               PrintDebug("Setting not present\n");
+               PrintPTE32(first_operand, shadow_pte );
 #endif
 
-           shadow_pte->present = 0;
-         }
+               shadow_pte->present = 0;
        }
 
        info->rip += index;
 
-      } else {
-       PrintError("Invalid Operand type\n");
-       return -1;
-      }
-    } else {
-      PrintError("invalid Instruction Opcode\n");
-      PrintTraceMemDump(instr, 15);
-      return -1;
-    }
-  }
-
-  return 0;
+       return 0;
 }
 
 
index 0f502b3..029f9fd 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <palacios/vmm.h>
 
-extern struct vmm_os_hooks * os_hooks;
+extern struct v3_os_hooks * os_hooks;
 
 
 void PrintTraceHex(unsigned char x) {
@@ -48,7 +48,7 @@ void PrintTraceMemDump(uchar_t * start, int n) {
   int i, j;
 
   for (i = 0; i < n; i += 16) {
-    PrintTrace("%8x", (start + i));
+    PrintTrace("%p", (void *)(start + i));
     for (j = i; (j < (i + 16)) && (j < n); j += 2) {
       PrintTrace(" ");
       PrintTraceHex(*(uchar_t *)(start + j));
index 7830458..cc25dc5 100644 (file)
 
 #endif
 
+
+
+#ifndef DEBUG_XED
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+
+
 static xed_state_t decoder_state;
 
 #define GPR_REGISTER     0
@@ -115,7 +124,7 @@ static int set_decoder_mode(struct guest_info * info, xed_state_t * state) {
   return 0;
 }
 
-int is_flags_reg(xed_reg_enum_t xed_reg) {
+static int is_flags_reg(xed_reg_enum_t xed_reg) {
   switch (xed_reg) {
   case XED_REG_FLAGS:
   case XED_REG_EFLAGS:
@@ -128,7 +137,7 @@ int is_flags_reg(xed_reg_enum_t xed_reg) {
 
 
 
-int init_decoder() {
+int v3_init_decoder() {
   xed_tables_init();
   xed_state_zero(&decoder_state);
   return 0;