From c71294cdd3581c3738d24ffd65414f8644a1094d Mon Sep 17 00:00:00 2001 From: Hanjie Wu Date: Tue, 18 Apr 2023 02:21:10 -0400 Subject: initial commit --- .gitignore | 13 + 410guests/cliff.bin | Bin 0 -> 94244 bytes 410guests/cliff/config.mk | 7 + 410guests/cliff/kern/cliff.S | 26 + 410guests/cliff/kern/fake_console.c | 87 + 410guests/cliff/kern/hvstubs.S | 33 + 410guests/cliff/kern/inc/console.h | 159 + 410guests/console.bin | Bin 0 -> 96196 bytes 410guests/console/config.mk | 7 + 410guests/console/kern/console.c | 173 + 410guests/console/kern/fake_console.c | 87 + 410guests/console/kern/hvstubs.S | 33 + 410guests/console/kern/inc/console.h | 159 + 410guests/dog.bin | Bin 0 -> 92376 bytes 410guests/dog/config.mk | 9 + 410guests/dog/kern/devices.S | 37 + 410guests/dog/kern/dog.c | 110 + 410guests/dog/kern/fake_console.c | 43 + 410guests/dog/kern/hvstubs.S | 33 + 410guests/dog/kern/inc/console.h | 159 + 410guests/dog/kern/inc/devices.h | 32 + 410guests/dumper.bin | Bin 0 -> 95716 bytes 410guests/dumper/config.mk | 7 + 410guests/dumper/kern/dumper.c | 63 + 410guests/dumper/kern/fake_console.c | 87 + 410guests/dumper/kern/hvstubs.S | 33 + 410guests/dumper/kern/inc/console.h | 159 + 410guests/flayrod.bin | Bin 0 -> 94020 bytes 410guests/flayrod/config.mk | 8 + 410guests/flayrod/kern/fake_console.c | 87 + 410guests/flayrod/kern/flayrod.c | 20 + 410guests/flayrod/kern/inc/console.h | 159 + 410guests/flayrod/kern/try_catch.S | 42 + 410guests/fondle.bin | Bin 0 -> 96164 bytes 410guests/fondle/config.mk | 7 + 410guests/fondle/kern/fake_console.c | 87 + 410guests/fondle/kern/fondle2.c | 245 + 410guests/fondle/kern/hvstubs.S | 33 + 410guests/fondle/kern/inc/console.h | 159 + 410guests/gomoku.bin | Bin 0 -> 99556 bytes 410guests/guests.mk | 28 + 410guests/hello.bin | Bin 0 -> 94404 bytes 410guests/hello/config.mk | 7 + 410guests/hello/kern/fake_console.c | 87 + 410guests/hello/kern/hello.c | 59 + 410guests/hello/kern/hvstubs.S | 33 + 410guests/hello/kern/inc/console.h | 159 + 410guests/magic.bin | Bin 0 -> 94564 bytes 410guests/magic/config.mk | 7 + 410guests/magic/kern/fake_console.c | 87 + 410guests/magic/kern/hvstubs.S | 33 + 410guests/magic/kern/inc/console.h | 159 + 410guests/magic/kern/magic.c | 66 + 410guests/pathos.bin | Bin 0 -> 748768 bytes 410guests/station.bin | Bin 0 -> 94904 bytes 410guests/station/config.mk | 7 + 410guests/station/kern/fake_console.c | 87 + 410guests/station/kern/hvstubs.S | 33 + 410guests/station/kern/inc/console.h | 159 + 410guests/station/kern/station.c | 97 + 410guests/teeny.bin | Bin 0 -> 95300 bytes 410guests/teeny/config.mk | 7 + 410guests/teeny/kern/fake_console.c | 87 + 410guests/teeny/kern/hvstubs.S | 33 + 410guests/teeny/kern/inc/console.h | 159 + 410guests/teeny/kern/teeny.c | 97 + 410guests/tick_tock.bin | Bin 0 -> 94756 bytes 410guests/tick_tock/config.mk | 7 + 410guests/tick_tock/kern/fake_console.c | 87 + 410guests/tick_tock/kern/hvstubs.S | 33 + 410guests/tick_tock/kern/inc/console.h | 159 + 410guests/tick_tock/kern/tick_tock.c | 107 + 410guests/vast.bin | Bin 0 -> 95236 bytes 410guests/vast/config.mk | 7 + 410guests/vast/kern/fake_console.c | 87 + 410guests/vast/kern/hvstubs.S | 33 + 410guests/vast/kern/inc/console.h | 159 + 410guests/vast/kern/vast.c | 111 + 410guests/warp.bin | Bin 0 -> 119428 bytes 410guests/warp/config.mk | 7 + 410guests/warp/kern/fake_console.c | 87 + 410guests/warp/kern/hvstubs.S | 33 + 410guests/warp/kern/inc/console.h | 159 + 410guests/warp/kern/inc/warp.h | 11 + 410guests/warp/kern/warp.S | 35 + 410guests/warp/kern/warp_main.c | 118 + 410guests/warp/kern/warp_map.S | 4126 +++++++++++++ 410kern/RNG/kernel.mk | 6 + 410kern/RNG/mt19937int.c | 97 + 410kern/RNG/mt19937int.h | 35 + 410kern/boot/head.S | 200 + 410kern/boot/kernel.mk | 13 + 410kern/boot/multiboot.h | 181 + 410kern/boot/util.h | 10 + 410kern/boot/util_cmdline.c | 82 + 410kern/boot/util_lmm.c | 150 + 410kern/bootfd.img.gz | Bin 0 -> 274856 bytes 410kern/elf/elf32.h | 245 + 410kern/elf/elf_410.h | 39 + 410kern/elf/elf_common.h | 866 +++ 410kern/elf/kernel.mk | 9 + 410kern/elf/load_helper.c | 212 + 410kern/entry.c | 111 + 410kern/inc/asm_style.h | 126 + 410kern/inc/assert.h | 69 + 410kern/inc/exec2obj.h | 29 + 410kern/inc/kvmphys.h | 47 + 410kern/inc/malloc.h | 16 + 410kern/inc/stdarg.h | 18 + 410kern/inc/stdbool.h | 15 + 410kern/inc/stddef.h | 12 + 410kern/inc/stdint.h | 114 + 410kern/inc/types.h | 23 + 410kern/kernel.lds | 191 + 410kern/kernel.mk | 32 + 410kern/lmm/README | 50 + 410kern/lmm/kernel.mk | 21 + 410kern/lmm/lmm.h | 65 + 410kern/lmm/lmm_add_free.c | 80 + 410kern/lmm/lmm_add_region.c | 73 + 410kern/lmm/lmm_alloc.c | 87 + 410kern/lmm/lmm_alloc_aligned.c | 32 + 410kern/lmm/lmm_alloc_gen.c | 156 + 410kern/lmm/lmm_alloc_page.c | 31 + 410kern/lmm/lmm_avail.c | 51 + 410kern/lmm/lmm_dump.c | 75 + 410kern/lmm/lmm_find_free.c | 75 + 410kern/lmm/lmm_free.c | 109 + 410kern/lmm/lmm_free_page.c | 30 + 410kern/lmm/lmm_init.c | 29 + 410kern/lmm/lmm_remove_free.c | 50 + 410kern/lmm/lmm_types.h | 58 + 410kern/malloc/calloc.c | 38 + 410kern/malloc/free.c | 31 + 410kern/malloc/kernel.mk | 18 + 410kern/malloc/malloc.c | 39 + 410kern/malloc/malloc_internal.h | 53 + 410kern/malloc/malloc_lmm.c | 39 + 410kern/malloc/memalign.c | 51 + 410kern/malloc/realloc.c | 56 + 410kern/malloc/sfree.c | 33 + 410kern/malloc/smalloc.c | 40 + 410kern/malloc/smemalign.c | 53 + 410kern/menu.lst | 4 + 410kern/misc/gccisms.c | 346 ++ 410kern/misc/kernel.mk | 9 + 410kern/simics/kernel.mk | 10 + 410kern/simics/simics.S | 13 + 410kern/simics/simics.h | 75 + 410kern/simics/simics_c.c | 60 + 410kern/smp/L36_P4.pdf | Bin 0 -> 92302 bytes 410kern/smp/README | 17 + 410kern/smp/apic.c | 104 + 410kern/smp/apic.h | 139 + 410kern/smp/kernel.mk | 12 + 410kern/smp/mptable.c | 246 + 410kern/smp/mptable.h | 119 + 410kern/smp/smp.c | 200 + 410kern/smp/smp.h | 20 + 410kern/smp/smp4.pdf | Bin 0 -> 284148 bytes 410kern/smp/smp_start.S | 55 + 410kern/smp/smpboot.h | 19 + 410kern/stdio/doprnt.c | 646 +++ 410kern/stdio/doprnt.h | 34 + 410kern/stdio/doscan.c | 181 + 410kern/stdio/doscan.h | 30 + 410kern/stdio/hexdump.c | 71 + 410kern/stdio/kernel.mk | 17 + 410kern/stdio/printf.c | 109 + 410kern/stdio/putchar.c | 30 + 410kern/stdio/puts.c | 39 + 410kern/stdio/sprintf.c | 104 + 410kern/stdio/sscanf.c | 65 + 410kern/stdio/stdio.h | 46 + 410kern/stdlib/abs.c | 27 + 410kern/stdlib/atol.c | 8 + 410kern/stdlib/ctype.c | 91 + 410kern/stdlib/ctype.h | 37 + 410kern/stdlib/kernel.mk | 17 + 410kern/stdlib/panic.c | 52 + 410kern/stdlib/qsort.c | 170 + 410kern/stdlib/rand.c | 62 + 410kern/stdlib/stdlib.h | 23 + 410kern/stdlib/strtol.c | 68 + 410kern/stdlib/strtoul.c | 62 + 410kern/string/kernel.mk | 27 + 410kern/string/memcmp.c | 53 + 410kern/string/memset.c | 34 + 410kern/string/rindex.c | 35 + 410kern/string/strcat.c | 38 + 410kern/string/strchr.c | 35 + 410kern/string/strcmp.c | 55 + 410kern/string/strcpy.c | 45 + 410kern/string/strcspn.c | 64 + 410kern/string/strdup.c | 31 + 410kern/string/string.h | 57 + 410kern/string/strlen.c | 45 + 410kern/string/strncat.c | 64 + 410kern/string/strncmp.c | 38 + 410kern/string/strncpy.c | 51 + 410kern/string/strpbrk.c | 54 + 410kern/string/strrchr.c | 35 + 410kern/string/strspn.c | 57 + 410kern/string/strstr.c | 37 + 410kern/string/strtok.c | 86 + 410kern/toplevel.mk | 46 + 410kern/x86/asm.S | 220 + 410kern/x86/asm.h | 47 + 410kern/x86/bcopy.S | 135 + 410kern/x86/bzero.S | 47 + 410kern/x86/cr.h | 123 + 410kern/x86/eflags.S | 27 + 410kern/x86/eflags.h | 60 + 410kern/x86/idt.h | 36 + 410kern/x86/interrupt_defines.h | 20 + 410kern/x86/interrupts.c | 13 + 410kern/x86/kernel.mk | 17 + 410kern/x86/keyhelp.c | 401 ++ 410kern/x86/keyhelp.h | 205 + 410kern/x86/keylayout.c | 234 + 410kern/x86/keylayout.h | 66 + 410kern/x86/misc.h | 13 + 410kern/x86/page.h | 20 + 410kern/x86/pic.c | 123 + 410kern/x86/pic.h | 224 + 410kern/x86/rtc.c | 17 + 410kern/x86/rtc.h | 27 + 410kern/x86/seg.h | 39 + 410kern/x86/timer_defines.h | 24 + 410kern/x86/video_defines.h | 54 + 410user/crt0.c | 19 + 410user/exec2obj.c | 208 + 410user/inc/410_tests.h | 77 + 410user/inc/asm_style.h | 126 + 410user/inc/assert.h | 69 + 410user/inc/cond.h | 18 + 410user/inc/malloc.h | 17 + 410user/inc/mutex.h | 15 + 410user/inc/rand.h | 35 + 410user/inc/rwlock.h | 20 + 410user/inc/sem.h | 16 + 410user/inc/stdarg.h | 18 + 410user/inc/stdbool.h | 15 + 410user/inc/stddef.h | 12 + 410user/inc/stdint.h | 114 + 410user/inc/thread.h | 26 + 410user/inc/types.h | 23 + 410user/libRNG/mt19937int.c | 97 + 410user/libRNG/user.mk | 6 + 410user/libmalloc/malloc.c | 639 ++ 410user/libmalloc/memlib.c | 72 + 410user/libmalloc/memlib.h | 13 + 410user/libmalloc/user.mk | 7 + 410user/libsimics/simics.S | 14 + 410user/libsimics/simics.h | 84 + 410user/libsimics/simics_c.c | 61 + 410user/libsimics/user.mk | 10 + 410user/libstdio/doprnt.c | 646 +++ 410user/libstdio/doprnt.h | 34 + 410user/libstdio/doscan.c | 181 + 410user/libstdio/doscan.h | 30 + 410user/libstdio/hexdump.c | 71 + 410user/libstdio/printf.c | 97 + 410user/libstdio/putchar.c | 31 + 410user/libstdio/puts.c | 14 + 410user/libstdio/sprintf.c | 104 + 410user/libstdio/sscanf.c | 65 + 410user/libstdio/stdio.h | 46 + 410user/libstdio/user.mk | 16 + 410user/libstdlib/abs.c | 27 + 410user/libstdlib/atol.c | 9 + 410user/libstdlib/ctype.c | 91 + 410user/libstdlib/ctype.h | 37 + 410user/libstdlib/exit.c | 15 + 410user/libstdlib/qsort.c | 170 + 410user/libstdlib/rand.c | 62 + 410user/libstdlib/stdlib.h | 30 + 410user/libstdlib/strtol.c | 68 + 410user/libstdlib/strtoul.c | 62 + 410user/libstdlib/user.mk | 17 + 410user/libstring/memcmp.c | 53 + 410user/libstring/memset.c | 34 + 410user/libstring/rindex.c | 35 + 410user/libstring/strcat.c | 38 + 410user/libstring/strchr.c | 35 + 410user/libstring/strcmp.c | 55 + 410user/libstring/strcpy.c | 45 + 410user/libstring/strcspn.c | 64 + 410user/libstring/strdup.c | 31 + 410user/libstring/string.h | 57 + 410user/libstring/strlen.c | 45 + 410user/libstring/strncat.c | 64 + 410user/libstring/strncmp.c | 38 + 410user/libstring/strncpy.c | 51 + 410user/libstring/strpbrk.c | 54 + 410user/libstring/strrchr.c | 35 + 410user/libstring/strspn.c | 57 + 410user/libstring/strstr.c | 37 + 410user/libstring/strtok.c | 86 + 410user/libstring/user.mk | 27 + 410user/libtest/report.c | 98 + 410user/libtest/report.h | 109 + 410user/libtest/test.c | 0 410user/libtest/test.h | 52 + 410user/libtest/testasm.S | 82 + 410user/libtest/user.mk | 6 + 410user/libthrgrp/thrgrp.c | 201 + 410user/libthrgrp/thrgrp.h | 71 + 410user/libthrgrp/user.mk | 7 + 410user/libx86/bcopy.S | 135 + 410user/libx86/bzero.S | 47 + 410user/libx86/gccisms.c | 346 ++ 410user/libx86/user.mk | 11 + 410user/progs/ack.c | 56 + 410user/progs/actual_wait.c | 131 + 410user/progs/bg.c | 39 + 410user/progs/bistromath.c | 7711 +++++++++++++++++++++++++ 410user/progs/cat.c | 30 + 410user/progs/cho.c | 103 + 410user/progs/cho2.c | 108 + 410user/progs/cho_variant.c | 171 + 410user/progs/chow.c | 142 + 410user/progs/ck1.c | 26 + 410user/progs/coolness.c | 26 + 410user/progs/deschedule_hang.c | 32 + 410user/progs/exec_basic.c | 33 + 410user/progs/exec_basic_helper.c | 25 + 410user/progs/exec_nonexist.c | 31 + 410user/progs/fib.c | 49 + 410user/progs/fork_bomb.c | 27 + 410user/progs/fork_exit_bomb.c | 41 + 410user/progs/fork_test1.c | 41 + 410user/progs/fork_wait.c | 46 + 410user/progs/fork_wait_bomb.c | 50 + 410user/progs/getpid_test1.c | 34 + 410user/progs/halt_test.c | 26 + 410user/progs/idle.c | 14 + 410user/progs/init.c | 28 + 410user/progs/knife.c | 43 + 410user/progs/loader_test1.c | 94 + 410user/progs/loader_test2.c | 273 + 410user/progs/make_crash.c | 50 + 410user/progs/make_crash_helper.c | 41 + 410user/progs/mem_eat_test.c | 58 + 410user/progs/mem_permissions.c | 98 + 410user/progs/merchant.c | 59 + 410user/progs/minclone_many.S | 177 + 410user/progs/minclone_mem.S | 78 + 410user/progs/new_pages.c | 95 + 410user/progs/new_shell.c | 27 + 410user/progs/peon.c | 35 + 410user/progs/print_basic.c | 27 + 410user/progs/progs.mk | 15 + 410user/progs/readline_basic.c | 25 + 410user/progs/register_test.S | 172 + 410user/progs/remove_pages_test1.c | 63 + 410user/progs/remove_pages_test2.c | 60 + 410user/progs/score.c | 146 + 410user/progs/shell.c | 276 + 410user/progs/slaughter.c | 144 + 410user/progs/sleep_test1.c | 32 + 410user/progs/stack_test1.c | 47 + 410user/progs/swexn_basic_test.c | 77 + 410user/progs/swexn_cookie_monster.c | 85 + 410user/progs/swexn_dispatch.c | 55 + 410user/progs/swexn_rampage.c | 96 + 410user/progs/swexn_regs.c | 65 + 410user/progs/swexn_stands_for_swextensible.c | 58 + 410user/progs/swexn_uninstall_test.c | 60 + 410user/progs/wait_getpid.c | 48 + 410user/progs/wild_test1.c | 31 + 410user/progs/work.c | 58 + 410user/progs/yield_desc_mkrun.c | 68 + 410user/user.mk | 60 + Makefile | 487 ++ README.STARTING_P4 | 26 + config.mk | 218 + doxygen.conf | 1101 ++++ guests/README | 60 + kern/asm_instr.S | 22 + kern/common.c | 472 ++ kern/console.c | 212 + kern/inc/asm_instr.h | 25 + kern/inc/common.h | 228 + kern/inc/console.h | 162 + kern/inc/interrupt.h | 27 + kern/inc/kbd.h | 30 + kern/inc/loader.h | 46 + kern/inc/mm.h | 55 + kern/inc/paging.h | 155 + kern/inc/sched.h | 361 ++ kern/inc/sync.h | 102 + kern/inc/timer.h | 24 + kern/inc/usermem.h | 50 + kern/interrupt.c | 502 ++ kern/interrupt_asm.S | 134 + kern/kbd.c | 218 + kern/kernel.c | 109 + kern/loader.c | 58 + kern/malloc_wrappers.c | 70 + kern/mm.c | 318 + kern/paging.c | 76 + kern/sched.c | 762 +++ kern/sched_asm.S | 67 + kern/sync.c | 78 + kern/sync_asm.S | 75 + kern/syscall_asm.S | 61 + kern/syscall_io.c | 151 + kern/syscall_memory.c | 137 + kern/syscall_misc.c | 169 + kern/syscall_process.c | 397 ++ kern/syscall_thread.c | 274 + kern/timer.c | 74 + kern/usermem.c | 153 + kern/usermem_asm.S | 35 + spec/common_kern.h | 56 + spec/compiler.h | 23 + spec/contracts.h | 32 + spec/hvcall.h | 135 + spec/hvcall_int.h | 49 + spec/limits.h | 36 + spec/syscall.h | 98 + spec/syscall_int.h | 69 + spec/ureg.h | 50 + update.sh | 107 + user/files/README | 5 + user/inc/README.userinc | 2 + user/inc/cond_type.h | 32 + user/inc/mutex_type.h | 38 + user/inc/rwlock_type.h | 41 + user/inc/sem_type.h | 24 + user/inc/thr_internals.h | 74 + user/libautostack/autostack.c | 71 + user/libsyscall/syscall.S | 218 + user/libthread/cond.c | 108 + user/libthread/malloc.c | 40 + user/libthread/mutex.c | 35 + user/libthread/mutex_lock.S | 114 + user/libthread/panic.c | 25 + user/libthread/rb_tcb.c | 283 + user/libthread/rwlock.c | 89 + user/libthread/sem.c | 71 + user/libthread/thread.c | 325 ++ user/libthread/thread_fork.S | 26 + user/progs/README.userprogs | 1 + user/progs/mandelbrot.c | 533 ++ user/progs/nibbles.c | 462 ++ user/progs/racer.c | 207 + 448 files changed, 49383 insertions(+) create mode 100644 .gitignore create mode 100755 410guests/cliff.bin create mode 100644 410guests/cliff/config.mk create mode 100644 410guests/cliff/kern/cliff.S create mode 100644 410guests/cliff/kern/fake_console.c create mode 100644 410guests/cliff/kern/hvstubs.S create mode 100644 410guests/cliff/kern/inc/console.h create mode 100755 410guests/console.bin create mode 100644 410guests/console/config.mk create mode 100644 410guests/console/kern/console.c create mode 100644 410guests/console/kern/fake_console.c create mode 100644 410guests/console/kern/hvstubs.S create mode 100644 410guests/console/kern/inc/console.h create mode 100755 410guests/dog.bin create mode 100644 410guests/dog/config.mk create mode 100644 410guests/dog/kern/devices.S create mode 100644 410guests/dog/kern/dog.c create mode 100644 410guests/dog/kern/fake_console.c create mode 100644 410guests/dog/kern/hvstubs.S create mode 100644 410guests/dog/kern/inc/console.h create mode 100644 410guests/dog/kern/inc/devices.h create mode 100755 410guests/dumper.bin create mode 100644 410guests/dumper/config.mk create mode 100644 410guests/dumper/kern/dumper.c create mode 100644 410guests/dumper/kern/fake_console.c create mode 100644 410guests/dumper/kern/hvstubs.S create mode 100644 410guests/dumper/kern/inc/console.h create mode 100755 410guests/flayrod.bin create mode 100644 410guests/flayrod/config.mk create mode 100644 410guests/flayrod/kern/fake_console.c create mode 100644 410guests/flayrod/kern/flayrod.c create mode 100644 410guests/flayrod/kern/inc/console.h create mode 100644 410guests/flayrod/kern/try_catch.S create mode 100755 410guests/fondle.bin create mode 100644 410guests/fondle/config.mk create mode 100644 410guests/fondle/kern/fake_console.c create mode 100644 410guests/fondle/kern/fondle2.c create mode 100644 410guests/fondle/kern/hvstubs.S create mode 100644 410guests/fondle/kern/inc/console.h create mode 100755 410guests/gomoku.bin create mode 100644 410guests/guests.mk create mode 100755 410guests/hello.bin create mode 100644 410guests/hello/config.mk create mode 100644 410guests/hello/kern/fake_console.c create mode 100644 410guests/hello/kern/hello.c create mode 100644 410guests/hello/kern/hvstubs.S create mode 100644 410guests/hello/kern/inc/console.h create mode 100755 410guests/magic.bin create mode 100644 410guests/magic/config.mk create mode 100644 410guests/magic/kern/fake_console.c create mode 100644 410guests/magic/kern/hvstubs.S create mode 100644 410guests/magic/kern/inc/console.h create mode 100644 410guests/magic/kern/magic.c create mode 100755 410guests/pathos.bin create mode 100755 410guests/station.bin create mode 100644 410guests/station/config.mk create mode 100644 410guests/station/kern/fake_console.c create mode 100644 410guests/station/kern/hvstubs.S create mode 100644 410guests/station/kern/inc/console.h create mode 100644 410guests/station/kern/station.c create mode 100755 410guests/teeny.bin create mode 100644 410guests/teeny/config.mk create mode 100644 410guests/teeny/kern/fake_console.c create mode 100644 410guests/teeny/kern/hvstubs.S create mode 100644 410guests/teeny/kern/inc/console.h create mode 100644 410guests/teeny/kern/teeny.c create mode 100755 410guests/tick_tock.bin create mode 100644 410guests/tick_tock/config.mk create mode 100644 410guests/tick_tock/kern/fake_console.c create mode 100644 410guests/tick_tock/kern/hvstubs.S create mode 100644 410guests/tick_tock/kern/inc/console.h create mode 100644 410guests/tick_tock/kern/tick_tock.c create mode 100755 410guests/vast.bin create mode 100644 410guests/vast/config.mk create mode 100644 410guests/vast/kern/fake_console.c create mode 100644 410guests/vast/kern/hvstubs.S create mode 100644 410guests/vast/kern/inc/console.h create mode 100644 410guests/vast/kern/vast.c create mode 100755 410guests/warp.bin create mode 100644 410guests/warp/config.mk create mode 100644 410guests/warp/kern/fake_console.c create mode 100644 410guests/warp/kern/hvstubs.S create mode 100644 410guests/warp/kern/inc/console.h create mode 100644 410guests/warp/kern/inc/warp.h create mode 100644 410guests/warp/kern/warp.S create mode 100644 410guests/warp/kern/warp_main.c create mode 100644 410guests/warp/kern/warp_map.S create mode 100644 410kern/RNG/kernel.mk create mode 100644 410kern/RNG/mt19937int.c create mode 100644 410kern/RNG/mt19937int.h create mode 100644 410kern/boot/head.S create mode 100644 410kern/boot/kernel.mk create mode 100644 410kern/boot/multiboot.h create mode 100644 410kern/boot/util.h create mode 100644 410kern/boot/util_cmdline.c create mode 100644 410kern/boot/util_lmm.c create mode 100644 410kern/bootfd.img.gz create mode 100644 410kern/elf/elf32.h create mode 100644 410kern/elf/elf_410.h create mode 100644 410kern/elf/elf_common.h create mode 100644 410kern/elf/kernel.mk create mode 100644 410kern/elf/load_helper.c create mode 100644 410kern/entry.c create mode 100644 410kern/inc/asm_style.h create mode 100644 410kern/inc/assert.h create mode 100644 410kern/inc/exec2obj.h create mode 100644 410kern/inc/kvmphys.h create mode 100644 410kern/inc/malloc.h create mode 100644 410kern/inc/stdarg.h create mode 100644 410kern/inc/stdbool.h create mode 100644 410kern/inc/stddef.h create mode 100644 410kern/inc/stdint.h create mode 100644 410kern/inc/types.h create mode 100644 410kern/kernel.lds create mode 100644 410kern/kernel.mk create mode 100644 410kern/lmm/README create mode 100644 410kern/lmm/kernel.mk create mode 100644 410kern/lmm/lmm.h create mode 100644 410kern/lmm/lmm_add_free.c create mode 100644 410kern/lmm/lmm_add_region.c create mode 100644 410kern/lmm/lmm_alloc.c create mode 100644 410kern/lmm/lmm_alloc_aligned.c create mode 100644 410kern/lmm/lmm_alloc_gen.c create mode 100644 410kern/lmm/lmm_alloc_page.c create mode 100644 410kern/lmm/lmm_avail.c create mode 100644 410kern/lmm/lmm_dump.c create mode 100644 410kern/lmm/lmm_find_free.c create mode 100644 410kern/lmm/lmm_free.c create mode 100644 410kern/lmm/lmm_free_page.c create mode 100644 410kern/lmm/lmm_init.c create mode 100644 410kern/lmm/lmm_remove_free.c create mode 100644 410kern/lmm/lmm_types.h create mode 100644 410kern/malloc/calloc.c create mode 100644 410kern/malloc/free.c create mode 100644 410kern/malloc/kernel.mk create mode 100644 410kern/malloc/malloc.c create mode 100644 410kern/malloc/malloc_internal.h create mode 100644 410kern/malloc/malloc_lmm.c create mode 100644 410kern/malloc/memalign.c create mode 100644 410kern/malloc/realloc.c create mode 100644 410kern/malloc/sfree.c create mode 100644 410kern/malloc/smalloc.c create mode 100644 410kern/malloc/smemalign.c create mode 100644 410kern/menu.lst create mode 100644 410kern/misc/gccisms.c create mode 100644 410kern/misc/kernel.mk create mode 100644 410kern/simics/kernel.mk create mode 100644 410kern/simics/simics.S create mode 100644 410kern/simics/simics.h create mode 100644 410kern/simics/simics_c.c create mode 100644 410kern/smp/L36_P4.pdf create mode 100644 410kern/smp/README create mode 100644 410kern/smp/apic.c create mode 100644 410kern/smp/apic.h create mode 100644 410kern/smp/kernel.mk create mode 100644 410kern/smp/mptable.c create mode 100644 410kern/smp/mptable.h create mode 100644 410kern/smp/smp.c create mode 100644 410kern/smp/smp.h create mode 100644 410kern/smp/smp4.pdf create mode 100644 410kern/smp/smp_start.S create mode 100644 410kern/smp/smpboot.h create mode 100644 410kern/stdio/doprnt.c create mode 100644 410kern/stdio/doprnt.h create mode 100644 410kern/stdio/doscan.c create mode 100644 410kern/stdio/doscan.h create mode 100644 410kern/stdio/hexdump.c create mode 100644 410kern/stdio/kernel.mk create mode 100644 410kern/stdio/printf.c create mode 100644 410kern/stdio/putchar.c create mode 100644 410kern/stdio/puts.c create mode 100644 410kern/stdio/sprintf.c create mode 100644 410kern/stdio/sscanf.c create mode 100644 410kern/stdio/stdio.h create mode 100644 410kern/stdlib/abs.c create mode 100644 410kern/stdlib/atol.c create mode 100644 410kern/stdlib/ctype.c create mode 100644 410kern/stdlib/ctype.h create mode 100644 410kern/stdlib/kernel.mk create mode 100644 410kern/stdlib/panic.c create mode 100644 410kern/stdlib/qsort.c create mode 100644 410kern/stdlib/rand.c create mode 100644 410kern/stdlib/stdlib.h create mode 100644 410kern/stdlib/strtol.c create mode 100644 410kern/stdlib/strtoul.c create mode 100644 410kern/string/kernel.mk create mode 100644 410kern/string/memcmp.c create mode 100644 410kern/string/memset.c create mode 100644 410kern/string/rindex.c create mode 100644 410kern/string/strcat.c create mode 100644 410kern/string/strchr.c create mode 100644 410kern/string/strcmp.c create mode 100644 410kern/string/strcpy.c create mode 100644 410kern/string/strcspn.c create mode 100644 410kern/string/strdup.c create mode 100644 410kern/string/string.h create mode 100644 410kern/string/strlen.c create mode 100644 410kern/string/strncat.c create mode 100644 410kern/string/strncmp.c create mode 100644 410kern/string/strncpy.c create mode 100644 410kern/string/strpbrk.c create mode 100644 410kern/string/strrchr.c create mode 100644 410kern/string/strspn.c create mode 100644 410kern/string/strstr.c create mode 100644 410kern/string/strtok.c create mode 100644 410kern/toplevel.mk create mode 100644 410kern/x86/asm.S create mode 100644 410kern/x86/asm.h create mode 100644 410kern/x86/bcopy.S create mode 100644 410kern/x86/bzero.S create mode 100644 410kern/x86/cr.h create mode 100644 410kern/x86/eflags.S create mode 100644 410kern/x86/eflags.h create mode 100644 410kern/x86/idt.h create mode 100644 410kern/x86/interrupt_defines.h create mode 100644 410kern/x86/interrupts.c create mode 100644 410kern/x86/kernel.mk create mode 100644 410kern/x86/keyhelp.c create mode 100644 410kern/x86/keyhelp.h create mode 100644 410kern/x86/keylayout.c create mode 100644 410kern/x86/keylayout.h create mode 100644 410kern/x86/misc.h create mode 100644 410kern/x86/page.h create mode 100644 410kern/x86/pic.c create mode 100644 410kern/x86/pic.h create mode 100644 410kern/x86/rtc.c create mode 100644 410kern/x86/rtc.h create mode 100644 410kern/x86/seg.h create mode 100644 410kern/x86/timer_defines.h create mode 100644 410kern/x86/video_defines.h create mode 100644 410user/crt0.c create mode 100644 410user/exec2obj.c create mode 100644 410user/inc/410_tests.h create mode 100644 410user/inc/asm_style.h create mode 100644 410user/inc/assert.h create mode 100644 410user/inc/cond.h create mode 100644 410user/inc/malloc.h create mode 100644 410user/inc/mutex.h create mode 100644 410user/inc/rand.h create mode 100644 410user/inc/rwlock.h create mode 100644 410user/inc/sem.h create mode 100644 410user/inc/stdarg.h create mode 100644 410user/inc/stdbool.h create mode 100644 410user/inc/stddef.h create mode 100644 410user/inc/stdint.h create mode 100644 410user/inc/thread.h create mode 100644 410user/inc/types.h create mode 100644 410user/libRNG/mt19937int.c create mode 100644 410user/libRNG/user.mk create mode 100644 410user/libmalloc/malloc.c create mode 100644 410user/libmalloc/memlib.c create mode 100644 410user/libmalloc/memlib.h create mode 100644 410user/libmalloc/user.mk create mode 100644 410user/libsimics/simics.S create mode 100644 410user/libsimics/simics.h create mode 100644 410user/libsimics/simics_c.c create mode 100644 410user/libsimics/user.mk create mode 100644 410user/libstdio/doprnt.c create mode 100644 410user/libstdio/doprnt.h create mode 100644 410user/libstdio/doscan.c create mode 100644 410user/libstdio/doscan.h create mode 100644 410user/libstdio/hexdump.c create mode 100644 410user/libstdio/printf.c create mode 100644 410user/libstdio/putchar.c create mode 100644 410user/libstdio/puts.c create mode 100644 410user/libstdio/sprintf.c create mode 100644 410user/libstdio/sscanf.c create mode 100644 410user/libstdio/stdio.h create mode 100644 410user/libstdio/user.mk create mode 100644 410user/libstdlib/abs.c create mode 100644 410user/libstdlib/atol.c create mode 100644 410user/libstdlib/ctype.c create mode 100644 410user/libstdlib/ctype.h create mode 100644 410user/libstdlib/exit.c create mode 100644 410user/libstdlib/qsort.c create mode 100644 410user/libstdlib/rand.c create mode 100644 410user/libstdlib/stdlib.h create mode 100644 410user/libstdlib/strtol.c create mode 100644 410user/libstdlib/strtoul.c create mode 100644 410user/libstdlib/user.mk create mode 100644 410user/libstring/memcmp.c create mode 100644 410user/libstring/memset.c create mode 100644 410user/libstring/rindex.c create mode 100644 410user/libstring/strcat.c create mode 100644 410user/libstring/strchr.c create mode 100644 410user/libstring/strcmp.c create mode 100644 410user/libstring/strcpy.c create mode 100644 410user/libstring/strcspn.c create mode 100644 410user/libstring/strdup.c create mode 100644 410user/libstring/string.h create mode 100644 410user/libstring/strlen.c create mode 100644 410user/libstring/strncat.c create mode 100644 410user/libstring/strncmp.c create mode 100644 410user/libstring/strncpy.c create mode 100644 410user/libstring/strpbrk.c create mode 100644 410user/libstring/strrchr.c create mode 100644 410user/libstring/strspn.c create mode 100644 410user/libstring/strstr.c create mode 100644 410user/libstring/strtok.c create mode 100644 410user/libstring/user.mk create mode 100644 410user/libtest/report.c create mode 100644 410user/libtest/report.h create mode 100644 410user/libtest/test.c create mode 100644 410user/libtest/test.h create mode 100644 410user/libtest/testasm.S create mode 100644 410user/libtest/user.mk create mode 100644 410user/libthrgrp/thrgrp.c create mode 100644 410user/libthrgrp/thrgrp.h create mode 100644 410user/libthrgrp/user.mk create mode 100644 410user/libx86/bcopy.S create mode 100644 410user/libx86/bzero.S create mode 100644 410user/libx86/gccisms.c create mode 100644 410user/libx86/user.mk create mode 100644 410user/progs/ack.c create mode 100644 410user/progs/actual_wait.c create mode 100644 410user/progs/bg.c create mode 100644 410user/progs/bistromath.c create mode 100644 410user/progs/cat.c create mode 100644 410user/progs/cho.c create mode 100644 410user/progs/cho2.c create mode 100644 410user/progs/cho_variant.c create mode 100644 410user/progs/chow.c create mode 100644 410user/progs/ck1.c create mode 100644 410user/progs/coolness.c create mode 100644 410user/progs/deschedule_hang.c create mode 100644 410user/progs/exec_basic.c create mode 100644 410user/progs/exec_basic_helper.c create mode 100644 410user/progs/exec_nonexist.c create mode 100644 410user/progs/fib.c create mode 100644 410user/progs/fork_bomb.c create mode 100644 410user/progs/fork_exit_bomb.c create mode 100644 410user/progs/fork_test1.c create mode 100644 410user/progs/fork_wait.c create mode 100644 410user/progs/fork_wait_bomb.c create mode 100644 410user/progs/getpid_test1.c create mode 100644 410user/progs/halt_test.c create mode 100644 410user/progs/idle.c create mode 100644 410user/progs/init.c create mode 100644 410user/progs/knife.c create mode 100644 410user/progs/loader_test1.c create mode 100644 410user/progs/loader_test2.c create mode 100644 410user/progs/make_crash.c create mode 100644 410user/progs/make_crash_helper.c create mode 100644 410user/progs/mem_eat_test.c create mode 100644 410user/progs/mem_permissions.c create mode 100644 410user/progs/merchant.c create mode 100644 410user/progs/minclone_many.S create mode 100644 410user/progs/minclone_mem.S create mode 100644 410user/progs/new_pages.c create mode 100644 410user/progs/new_shell.c create mode 100644 410user/progs/peon.c create mode 100644 410user/progs/print_basic.c create mode 100644 410user/progs/progs.mk create mode 100644 410user/progs/readline_basic.c create mode 100644 410user/progs/register_test.S create mode 100644 410user/progs/remove_pages_test1.c create mode 100644 410user/progs/remove_pages_test2.c create mode 100644 410user/progs/score.c create mode 100644 410user/progs/shell.c create mode 100644 410user/progs/slaughter.c create mode 100644 410user/progs/sleep_test1.c create mode 100644 410user/progs/stack_test1.c create mode 100644 410user/progs/swexn_basic_test.c create mode 100644 410user/progs/swexn_cookie_monster.c create mode 100644 410user/progs/swexn_dispatch.c create mode 100644 410user/progs/swexn_rampage.c create mode 100644 410user/progs/swexn_regs.c create mode 100644 410user/progs/swexn_stands_for_swextensible.c create mode 100644 410user/progs/swexn_uninstall_test.c create mode 100644 410user/progs/wait_getpid.c create mode 100644 410user/progs/wild_test1.c create mode 100644 410user/progs/work.c create mode 100644 410user/progs/yield_desc_mkrun.c create mode 100644 410user/user.mk create mode 100644 Makefile create mode 100644 README.STARTING_P4 create mode 100644 config.mk create mode 100644 doxygen.conf create mode 100644 guests/README create mode 100644 kern/asm_instr.S create mode 100644 kern/common.c create mode 100644 kern/console.c create mode 100644 kern/inc/asm_instr.h create mode 100644 kern/inc/common.h create mode 100644 kern/inc/console.h create mode 100644 kern/inc/interrupt.h create mode 100644 kern/inc/kbd.h create mode 100644 kern/inc/loader.h create mode 100644 kern/inc/mm.h create mode 100644 kern/inc/paging.h create mode 100644 kern/inc/sched.h create mode 100644 kern/inc/sync.h create mode 100644 kern/inc/timer.h create mode 100644 kern/inc/usermem.h create mode 100644 kern/interrupt.c create mode 100644 kern/interrupt_asm.S create mode 100644 kern/kbd.c create mode 100644 kern/kernel.c create mode 100644 kern/loader.c create mode 100644 kern/malloc_wrappers.c create mode 100644 kern/mm.c create mode 100644 kern/paging.c create mode 100644 kern/sched.c create mode 100644 kern/sched_asm.S create mode 100644 kern/sync.c create mode 100644 kern/sync_asm.S create mode 100644 kern/syscall_asm.S create mode 100644 kern/syscall_io.c create mode 100644 kern/syscall_memory.c create mode 100644 kern/syscall_misc.c create mode 100644 kern/syscall_process.c create mode 100644 kern/syscall_thread.c create mode 100644 kern/timer.c create mode 100644 kern/usermem.c create mode 100644 kern/usermem_asm.S create mode 100644 spec/common_kern.h create mode 100644 spec/compiler.h create mode 100644 spec/contracts.h create mode 100644 spec/hvcall.h create mode 100644 spec/hvcall_int.h create mode 100644 spec/limits.h create mode 100644 spec/syscall.h create mode 100644 spec/syscall_int.h create mode 100644 spec/ureg.h create mode 100755 update.sh create mode 100644 user/files/README create mode 100644 user/inc/README.userinc create mode 100644 user/inc/cond_type.h create mode 100644 user/inc/mutex_type.h create mode 100644 user/inc/rwlock_type.h create mode 100644 user/inc/sem_type.h create mode 100644 user/inc/thr_internals.h create mode 100644 user/libautostack/autostack.c create mode 100644 user/libsyscall/syscall.S create mode 100644 user/libthread/cond.c create mode 100644 user/libthread/malloc.c create mode 100644 user/libthread/mutex.c create mode 100644 user/libthread/mutex_lock.S create mode 100644 user/libthread/panic.c create mode 100644 user/libthread/rb_tcb.c create mode 100644 user/libthread/rwlock.c create mode 100644 user/libthread/sem.c create mode 100644 user/libthread/thread.c create mode 100644 user/libthread/thread_fork.S create mode 100644 user/progs/README.userprogs create mode 100644 user/progs/mandelbrot.c create mode 100644 user/progs/nibbles.c create mode 100644 user/progs/racer.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05ea1e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.vscode/ +*.o +*.a +*.dep +temp/ +bootfd.img +kernel +kernel.strip +.gdb_history +410user/progs/ +410user/exec2obj +.md5s +user/progs/ diff --git a/410guests/cliff.bin b/410guests/cliff.bin new file mode 100755 index 0000000..8f0e661 Binary files /dev/null and b/410guests/cliff.bin differ diff --git a/410guests/cliff/config.mk b/410guests/cliff/config.mk new file mode 100644 index 0000000..b707451 --- /dev/null +++ b/410guests/cliff/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + cliff.o \ + fake_console.o hvstubs.o diff --git a/410guests/cliff/kern/cliff.S b/410guests/cliff/kern/cliff.S new file mode 100644 index 0000000..f780183 --- /dev/null +++ b/410guests/cliff/kern/cliff.S @@ -0,0 +1,26 @@ +/** @file cliff.S + * @brief Exception delivery will try to push information onto the stack. + * If pushing fails, then the guest should die. We install a (fake) IDT + * entry for the divide-by-zero exception, then we divide by zero. + * + * @author rpearl + */ + +#include +#include + +.globl kernel_main +kernel_main: + pushl $1 # Privileged (it's an exception handler) + pushl $badness # Valid handler address in case hv is careful + pushl $IDT_DE + movl $HV_SETIDT_OP, %eax + int $HV_INT # ok, "handler" is installed + + movl $0xFFF00000, %esp # bad stack pointer + + xorl %ecx, %ecx + idiv %ecx # game over, hv should slay us + +badness: + jmp badness diff --git a/410guests/cliff/kern/fake_console.c b/410guests/cliff/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/cliff/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/cliff/kern/hvstubs.S b/410guests/cliff/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/cliff/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/cliff/kern/inc/console.h b/410guests/cliff/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/cliff/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/console.bin b/410guests/console.bin new file mode 100755 index 0000000..935df5a Binary files /dev/null and b/410guests/console.bin differ diff --git a/410guests/console/config.mk b/410guests/console/config.mk new file mode 100644 index 0000000..0f9c788 --- /dev/null +++ b/410guests/console/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + console.o \ + fake_console.o hvstubs.o diff --git a/410guests/console/kern/console.c b/410guests/console/kern/console.c new file mode 100644 index 0000000..b1f4958 --- /dev/null +++ b/410guests/console/kern/console.c @@ -0,0 +1,173 @@ +/** @file console.c + * + * @brief Exercises the hypervisor console + * + * @author relong + * @author de0u + * + * PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include +#include + +#define DEBUG +#include + +#include +#include + +static const int TOP_ROW = 2; +static const int BOT_ROW = 22; + +static const int MAGIC_ROW = 5; +static const int MAGIC_COL = 10; + +#define STRLEN(s) (sizeof(s) - 1) +static const char BLANKS[] = " "; +static const char STARS[] = "************************************************************"; +static const char IN_HV[] = "We are in the hypervisor\n"; +static const char COLORS[] = "Look at the pretty colors!\n"; +static const char PASSING[] = "All tests passing\n"; +static const char TEST[] = "This is a test"; +static const char CRACKERS[] = "It's crackers to slip a rozzer the dropsy in snide.\n"; +static const char EXITING[] = "About to: hv_exit(77)...\n"; + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) { + + /* We do NOT want to print that tests passed if they didn't. + * Some hypervisors might botch hv_exit() -- it might return! + * Note that hv_exit() is declared as NORETURN. + * So GCC will **DELETE** a call to panic() after hv_exit(). + * Thanks, GCC hyper-optimizers! + */ + int pass = 1; + + if (!hv_isguest()) { + pass = 0; + lprintf("@@@@@ FAIL @@@@@ I am NOT supposed to be here!!!"); + panic("This payload is guest-only"); + return (-1); + } + + lprintf(STARS); + lprintf("In guest kernel"); + + int magic = hv_magic(); + lprintf("Found magic: %d", magic); + if (magic != HV_MAGIC) { + pass = 0; + lprintf("@@@@@ FAIL @@@@@ Magic Failed"); + hv_exit(-10); + } + + + lprintf("Blank area"); + hv_cons_set_cursor_pos(TOP_ROW, 0); + hv_cons_set_term_color(FGND_RED | BGND_BLACK); + hv_print(STRLEN(STARS), (unsigned char *)STARS); + hv_print(1, (unsigned char *)"\n"); + hv_cons_set_term_color(FGND_WHITE | BGND_BLACK); + for (int row = TOP_ROW+1; row < BOT_ROW-1; ++row) { + hv_print(STRLEN(BLANKS), (unsigned char *)BLANKS); + hv_print(1, (unsigned char *)"\n"); + } + hv_cons_set_term_color(FGND_RED | BGND_BLACK); + hv_print(STRLEN(STARS), (unsigned char *)STARS); + hv_print(1, (unsigned char *)"\n"); + hv_cons_set_term_color(FGND_WHITE | BGND_BLACK); + hv_cons_set_cursor_pos(TOP_ROW+1, 0); + + lprintf("Trying to print to the hypervisor"); + hv_print(STRLEN(IN_HV), (unsigned char *)IN_HV); + + lprintf("Color printing"); + hv_cons_set_term_color(FGND_PINK | BGND_LGRAY); + hv_print(STRLEN(COLORS), (unsigned char *)COLORS); + + lprintf("Moving cursor to (%d,%d)", MAGIC_ROW, MAGIC_COL); + hv_cons_set_cursor_pos(MAGIC_ROW, MAGIC_COL); + + lprintf("Trying to get the cursor information now"); + int row, col; + hv_cons_get_cursor_pos(&row, &col); + + lprintf("Found row, col: (%d,%d)", row, col); + + if (row != MAGIC_ROW || col != MAGIC_COL) { + pass = 0; + lprintf("@@@@@ FAIL @@@@@ Bad cursor position: (%d,%d)", row, col); + hv_exit(-11); + } + hv_cons_set_term_color(FGND_WHITE | BGND_BLACK); + + hv_print_at(STRLEN(TEST), + (unsigned char *)TEST, + MAGIC_ROW + 1, // Add some extra magic + 2 * MAGIC_COL, // Add some extra magic + FGND_CYAN | BGND_LGRAY); + + int new_row, new_col; + hv_cons_get_cursor_pos(&new_row, &new_col); + + if (new_row != row || new_col != col) { + pass = 0; + lprintf("@@@@@ FAIL @@@@@ hv_print_at() changes state!!!"); + hv_exit(-12); + } + + lprintf("Verifying movement"); + hv_cons_set_cursor_pos(MAGIC_ROW+5, 0); + hv_cons_set_term_color(FGND_GREEN | BGND_BLACK); + hv_print(STRLEN(CRACKERS), (unsigned char *)CRACKERS); + hv_cons_set_term_color(FGND_WHITE | BGND_BLACK); + hv_cons_get_cursor_pos(&new_row, &new_col); + if (new_row != MAGIC_ROW+6 || new_col != 0) { + pass = 0; + lprintf("@@@@@ FAIL @@@@@ hv_print() does not move cursor correctly!!!"); + hv_exit(-13); + } + hv_print(2, (unsigned char *)"\n\n"); + + if (pass) { + lprintf("ALL TESTS PASSED"); + hv_print(STRLEN(PASSING), (unsigned char *)PASSING); + } + + lprintf("About to: hv_exit(77)..."); + hv_print(STRLEN(EXITING), (unsigned char *)EXITING); + + lprintf(STARS); + hv_print(1, (unsigned char *)"\n"); + hv_exit(77); + + panic("Exit failed?"); +} diff --git a/410guests/console/kern/fake_console.c b/410guests/console/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/console/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/console/kern/hvstubs.S b/410guests/console/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/console/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/console/kern/inc/console.h b/410guests/console/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/console/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/dog.bin b/410guests/dog.bin new file mode 100755 index 0000000..8560e2c Binary files /dev/null and b/410guests/dog.bin differ diff --git a/410guests/dog/config.mk b/410guests/dog/config.mk new file mode 100644 index 0000000..a13ac5d --- /dev/null +++ b/410guests/dog/config.mk @@ -0,0 +1,9 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + dog.o \ + fake_console.o \ + devices.o \ + hvstubs.o diff --git a/410guests/dog/kern/devices.S b/410guests/dog/kern/devices.S new file mode 100644 index 0000000..a23095b --- /dev/null +++ b/410guests/dog/kern/devices.S @@ -0,0 +1,37 @@ +// @author de0u +// @author jrduvall +// +// "Creatures of the night, brought to light" + +#include + +.globl augchar +.globl kbd_intr +.globl timer_intr +.globl tick_count + +.data +.align 4 +ticks: + .long 0 +.text + +augchar: + movl $HV_ENABLE_OP, %eax + int $HV_INT +pause: + pause + jmp pause +kbd_intr: + addl $20, %esp // restore %esp + movl -16(%esp), %eax // augchar from red zone (interrupts are off) + ret + +timer_intr: + addl $20, %esp // restore %esp + incl ticks + jmp augchar // resume + +tick_count: + movl ticks, %eax + ret diff --git a/410guests/dog/kern/dog.c b/410guests/dog/kern/dog.c new file mode 100644 index 0000000..e627dd7 --- /dev/null +++ b/410guests/dog/kern/dog.c @@ -0,0 +1,110 @@ +/** @file dog.c + * + * @brief PebPeb port of P1 410_test.c + * + * @author cabauer + * @author jrduvall + * @author de0u + * + * PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include +#include +#include + +#include + +#include /* lprintf() */ +#include /* boot_info */ + +#include /* putbyte() */ +#include +#include /* augchar(), kbd_intr(), timer_intr() */ +#include /* KH_* */ +#include /* colors */ + +/* --- Stuff and Nonsense --- */ + +void wait_char(char testc); +void cls(void); + +/** + * @brief Wait for a specific character to be pressed + * + * @param testc the character to test for + * + * @requires interrupts are disabled + * @ensures interrupts are disabled + * @ensures returns only once the given character is typed + */ +void wait_char(char testc) { + kh_type a; + do { + a = augchar(); + lprintf("augchar()=%d hasdata=%d getchar=%d", a, KH_HASDATA(a), + KH_GETCHAR(a)); + } while (!KH_HASDATA(a) || KH_GETCHAR(a) != testc); +} + +/** @brief Clear screen */ +void cls(void) { + char row[CONSOLE_WIDTH]; + + memset(row, ' ', sizeof (row)); + + hv_cons_set_cursor_pos(0, 0); + for (int r = 0; r < CONSOLE_HEIGHT; ++r) + putbytes(row, CONSOLE_WIDTH); + hv_cons_set_cursor_pos(0, 0); +} + +/* --- Kernel entrypoint --- */ + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) { + int ticks; + + if (!hv_isguest()) { + lprintf("@@@@@ FAIL @@@@@ I am NOT supposed to be here!!!"); + panic("This payload is guest-only"); + return (-1); + } + + unsigned int magic = hv_magic(); + if (magic != HV_MAGIC) { + lprintf("@@@@@ FAIL @@@@@ Magic Failed"); + hv_exit(-10); + } + + hv_setidt(HV_TICKBACK, (void*)timer_intr, HV_SETIDT_PRIVILEGED); + hv_setidt(HV_KEYBOARD, (void*)kbd_intr, HV_SETIDT_PRIVILEGED); + + hv_cons_set_term_color(FGND_GREEN | BGND_BLACK); + cls(); + + hv_cons_set_cursor_pos(12, 34); + printf("Hello World!\n"); + hv_cons_set_cursor_pos(15, 34); + printf("Type \"dog\" now: "); + + lprintf("waiting for characters..."); + wait_char('d'); putbyte('c'); + wait_char('o'); putbyte('a'); + wait_char('g'); putbyte('t'); + hv_cons_set_cursor_pos(17, 34); + printf("Yay kitties!\n"); + + ticks = tick_count(); + lprintf("Ticks: %d", ticks); + hv_cons_set_cursor_pos(18, 34); + printf("Ticks: %d\n", ticks); + + hv_exit(0); +} diff --git a/410guests/dog/kern/fake_console.c b/410guests/dog/kern/fake_console.c new file mode 100644 index 0000000..eaa30f5 --- /dev/null +++ b/410guests/dog/kern/fake_console.c @@ -0,0 +1,43 @@ +/** @file fake_console.c + * @brief Not really a console driver. + * + * @author Harry Q. Bovik (hqbovik) + * @author Jack Duvall (jrduvall) + */ + +#include +#include +#include + +int putbyte(char ch) { + hv_print(1, (unsigned char*)&ch); + return ch; +} + +void putbytes(const char* s, int len) { + hv_print(len, (unsigned char *)(size_t)s); +} + +int set_term_color(int color) { + return (-1); +} + +void get_term_color(int* color) {} + +int set_cursor(int row, int col) { + return (-1); +} + +void get_cursor(int* row, int* col) {} + +void hide_cursor() {} + +void show_cursor() {} + +void clear_console() {} + +void draw_char(int row, int col, int ch, int color) {} + +char get_char(int row, int col) { + return ' '; +} diff --git a/410guests/dog/kern/hvstubs.S b/410guests/dog/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/dog/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/dog/kern/inc/console.h b/410guests/dog/kern/inc/console.h new file mode 100644 index 0000000..3e42f16 --- /dev/null +++ b/410guests/dog/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte(char ch); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(void); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(void); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(void); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/dog/kern/inc/devices.h b/410guests/dog/kern/inc/devices.h new file mode 100644 index 0000000..3862bd6 --- /dev/null +++ b/410guests/dog/kern/inc/devices.h @@ -0,0 +1,32 @@ +/** + * @file dog/inc/devices.h + * @brief Header for special-purpose "device drivers" + * @author jrduvall + * @author de0u + * + */ + +#ifndef DOG_DEVICES_H +#define DOG_DEVICES_H + +/** + * @brief Gets the next augchar via virtual interrupt handling + */ +int augchar(void); + +/** + * @brief Handles virtual keyboard interrupts + */ +void kbd_intr(void); + +/** + * @brief Handles virtual timer interrupts + */ +void timer_intr(void); + +/** + * @brief Return count of ticks since boot + */ +int tick_count(void); + +#endif /* DOG_DEVICES_H */ diff --git a/410guests/dumper.bin b/410guests/dumper.bin new file mode 100755 index 0000000..e1c975b Binary files /dev/null and b/410guests/dumper.bin differ diff --git a/410guests/dumper/config.mk b/410guests/dumper/config.mk new file mode 100644 index 0000000..f753f1b --- /dev/null +++ b/410guests/dumper/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + dumper.o \ + fake_console.o hvstubs.o diff --git a/410guests/dumper/kern/dumper.c b/410guests/dumper/kern/dumper.c new file mode 100644 index 0000000..64134b9 --- /dev/null +++ b/410guests/dumper/kern/dumper.c @@ -0,0 +1,63 @@ +/** @file dumper.c + * + * @brief Minimal guest kernel -- uses just lprintf() + * + * @author de0u + * @author relong + * + * Hello is a PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include + +#include +#include + +char bigarray[2 * 1024 * 1024]; + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) { + lprintf("Well, here I am!"); + + if (!hv_isguest()) { + lprintf("Not a guest?"); + panic("This payload is guest-only"); + return -1; + } + + extern lmm_t malloc_lmm; + lmm_dump(&malloc_lmm); + + lprintf("Successfully running as a guest"); + + while (1) { + continue; + } +} diff --git a/410guests/dumper/kern/fake_console.c b/410guests/dumper/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/dumper/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/dumper/kern/hvstubs.S b/410guests/dumper/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/dumper/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/dumper/kern/inc/console.h b/410guests/dumper/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/dumper/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/flayrod.bin b/410guests/flayrod.bin new file mode 100755 index 0000000..d63c02c Binary files /dev/null and b/410guests/flayrod.bin differ diff --git a/410guests/flayrod/config.mk b/410guests/flayrod/config.mk new file mode 100644 index 0000000..cd61df1 --- /dev/null +++ b/410guests/flayrod/config.mk @@ -0,0 +1,8 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + flayrod.o \ + try_catch.o \ + fake_console.o diff --git a/410guests/flayrod/kern/fake_console.c b/410guests/flayrod/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/flayrod/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/flayrod/kern/flayrod.c b/410guests/flayrod/kern/flayrod.c new file mode 100644 index 0000000..f321d44 --- /dev/null +++ b/410guests/flayrod/kern/flayrod.c @@ -0,0 +1,20 @@ +/** @file flayrod.c + * @brief Test hypervisor page-fault delivery. + * + * @author Axel Feldmann (asfeldma) + * @author Dave Eckhardt (de0u) + */ + +#include +#include +#include +#include + +void tryit(void); + +int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) { + lprintf("BEGIN TEST: flayrod"); + tryit(); + lprintf("*****FAIL*****"); + return -1; +} diff --git a/410guests/flayrod/kern/inc/console.h b/410guests/flayrod/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/flayrod/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/flayrod/kern/try_catch.S b/410guests/flayrod/kern/try_catch.S new file mode 100644 index 0000000..5bc355c --- /dev/null +++ b/410guests/flayrod/kern/try_catch.S @@ -0,0 +1,42 @@ +#include "hvcall_int.h" +#include "x86/idt.h" + +#define BAD_PTR 0x37373737 + +.global tryit +tryit: + // First hv_setidt(IDT_PF, askew, privileged=1) + pushl $1 + leal askew, %eax + pushl %eax + pushl $IDT_PF + movl $HV_SETIDT_OP, %eax + int $HV_INT + // Now dereference a bad pointer in %eax + movl $BAD_PTR, %eax + movl %eax, (%eax) + // Pretend that if we get back here we should just return + addl $12, %esp + ret + +// Page-fault handler (for when something has gone out askew) +.global askew +askew: + cmp (%esp), %eax + je success +fail: + // Hypervisor reported an incorrect value for the bad pointer + // so we exit with a bad return code. + pushl $0xBAD + jmp runaway +success: + // Hypervisor reported the correct value for the bad pointer + // so we exit with a good return code. + pushl $0 + jmp runaway + +runaway: + movl $HV_EXIT_OP, %eax + int $HV_INT + // Should not get here - so let's crash hard + ud2 diff --git a/410guests/fondle.bin b/410guests/fondle.bin new file mode 100755 index 0000000..41d70f1 Binary files /dev/null and b/410guests/fondle.bin differ diff --git a/410guests/fondle/config.mk b/410guests/fondle/config.mk new file mode 100644 index 0000000..b35a9d9 --- /dev/null +++ b/410guests/fondle/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + fondle2.o \ + fake_console.o hvstubs.o diff --git a/410guests/fondle/kern/fake_console.c b/410guests/fondle/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/fondle/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/fondle/kern/fondle2.c b/410guests/fondle/kern/fondle2.c new file mode 100644 index 0000000..16d5315 --- /dev/null +++ b/410guests/fondle/kern/fondle2.c @@ -0,0 +1,245 @@ +/** @file fondle2.c + * + * @brief A simple test of the hypervisor's virtual memory system. + * + * This test exercises hv_setpd(), hv_adjustpg(), and page-fault delivery. + * + * The test proceeds as follows. + * + * 1. Insert a static mapping which direct maps the bottom 16MB for user + * and kernel space. + * + * 2. A special 4MB region of the address space is mapped for kernel space + * only. + * + * 3. In kernel mode the numbers 0 through 1023 are written to the pages + * at the top of memory. + * + * 4. The top page table is reversed and hv_adjustpg() is called on all + * of the addresses in the top 4MB. + * + * 5. Values are checked to make sure they reversed along with the frames. + * + * 6. hv_iret goes to "user" mode and expects a page fault when it tries + * to touch the top memory. + * + * @author mischnal + * @author relong + * + * PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include + +#include +#include + +#define KERNEL_PAGE_DIRECTORY_INDEX 410 +#define STACK_SIZE 1024 + +static const uint32_t MB = 1024 * 1024; +static const uint32_t KERNEL_ADDRESS = KERNEL_PAGE_DIRECTORY_INDEX << 22; +static const uint32_t MAGIC_OFFSET = 0x9f1; + + +static int tests_run = 0; +static int tests_passed = 0; + +static uint32_t user_stack[STACK_SIZE]; +static uint32_t kernel_stack[STACK_SIZE]; + + +static void page_fault(void); +static void tick(void); +static void write_test(void); +static void rev_array(void* arrv, size_t elm_size, size_t array_size); +static void read_test(void); + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) { + lprintf("Well, here I am!"); + + if (!hv_isguest()) { + lprintf("Not a guest?"); + panic("This payload is guest-only"); + return -1; + } + + lprintf("Starting fondle"); + // Setup page table + // Bottom 16MB direct mapped for both kernel and user access + uint32_t* pageDirectory = _smemalign(PAGE_SIZE, PAGE_SIZE); + uint32_t* directMapPageTables = + _smemalign(PAGE_SIZE, PAGE_SIZE * sizeof(uint32_t)); + for (int pageTableIndex = 0; pageTableIndex < PAGE_SIZE; pageTableIndex++) { + uint32_t guestFrame = pageTableIndex * PAGE_SIZE; + directMapPageTables[pageTableIndex] = guestFrame | 7; // UWP + } + for (int pageDirectoryIndex = 0; pageDirectoryIndex < 4; + pageDirectoryIndex++) { + pageDirectory[pageDirectoryIndex] = + (uint32_t)&directMapPageTables[pageDirectoryIndex + * (PAGE_SIZE / sizeof(uint32_t))] + | 7; // UWP + } + // 4MB special region mapped for kernel only + uint32_t* kernelPageTable = _smemalign(PAGE_SIZE, PAGE_SIZE); + for (int pageTableIndex = 0; + pageTableIndex < (PAGE_SIZE / sizeof(uint32_t)); + pageTableIndex++) { + uint32_t guestFrame = USER_MEM_START + (pageTableIndex * PAGE_SIZE); + kernelPageTable[pageTableIndex] = guestFrame | 3; // KWP + } + pageDirectory[KERNEL_PAGE_DIRECTORY_INDEX] = + (uint32_t)kernelPageTable | 3; // KWP + + lprintf("Setting up page directory"); + hv_setpd(pageDirectory, 0); + + lprintf("Setting up IDT"); + + hv_setidt(14, page_fault, 1); + hv_setidt(32, tick, 1); + hv_setidt(33, tick, 1); + + write_test(); + + rev_array(kernelPageTable, sizeof(uint32_t), PAGE_SIZE / sizeof(uint32_t)); + + for (uint32_t guest_virtual = KERNEL_ADDRESS; + guest_virtual < (KERNEL_ADDRESS + 4 * MB); + guest_virtual += PAGE_SIZE) { + hv_adjustpg((void*)guest_virtual); + } + + read_test(); + + // Go to user mode + hv_iret(read_test, + get_eflags() & ~EFL_IF, // Force interrupts to be disabled + user_stack + STACK_SIZE - 1, + kernel_stack + STACK_SIZE - 1, + 0); + + lprintf("HV iret returned"); + + hv_exit(-12); + + while (1) { + continue; + } +} + +static void write_test(void) { + tests_run++; + int i = 0; + // Set values 0 - 1023 + for (uint32_t guest_virtual = KERNEL_ADDRESS; + guest_virtual < (KERNEL_ADDRESS + 4 * MB); + guest_virtual += PAGE_SIZE) { + *(int*)(guest_virtual + MAGIC_OFFSET) = i++; + } + i = 0; + for (uint32_t guest_virtual = KERNEL_ADDRESS; + guest_virtual < (KERNEL_ADDRESS + 4 * MB); + guest_virtual += PAGE_SIZE) { + int i_prime = *(int*)(guest_virtual + MAGIC_OFFSET); + if (i != i_prime) { + lprintf("Value written to page %lx did not appear (%d != %d)", + guest_virtual, + i, + i_prime); + hv_exit(-11); + } + i++; + } + lprintf("fondle: Write test complete"); + tests_passed++; +} + +static void read_test(void) { + tests_run++; + int i = (PAGE_SIZE / sizeof(uint32_t)) - 1; + + for (uint32_t guest_virtual = KERNEL_ADDRESS; + guest_virtual < (KERNEL_ADDRESS + 4 * MB); + guest_virtual += PAGE_SIZE) { + int i_prime = *(int*)(guest_virtual + MAGIC_OFFSET); + if (i != i_prime) { + lprintf("Value written to page %lx did not appear (%d != %d)", + guest_virtual, + i, + i_prime); + hv_exit(-11); + } + i--; + } + lprintf("fondle: Read test completed"); + tests_passed++; +} + +static void page_fault(void) { + lprintf("In page fault handler"); + + if (tests_run == 3 && tests_passed == 2) { + lprintf("Fondle passed"); + hv_exit(1); + } else { + lprintf("Fondle failed (early page fault)"); + hv_exit(-13); + } +} + +static void tick(void) { + // Interrupts never enabled + lprintf("Tick called?"); + hv_exit(-10); +} + +static void rev_array(void* arrv, size_t elm_size, size_t array_size) { + size_t beg, end; + char* arr = (char*)arrv; + + beg = 0; + end = (elm_size * (array_size - 1)); + + while (beg < end) { + int i; + for (i = 0; i < elm_size; i++) { + char temp = arr[beg + i]; + arr[beg + i] = arr[end + i]; + arr[end + i] = temp; + } + beg += elm_size; + end -= elm_size; + } +} diff --git a/410guests/fondle/kern/hvstubs.S b/410guests/fondle/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/fondle/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/fondle/kern/inc/console.h b/410guests/fondle/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/fondle/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/gomoku.bin b/410guests/gomoku.bin new file mode 100755 index 0000000..d9a66d9 Binary files /dev/null and b/410guests/gomoku.bin differ diff --git a/410guests/guests.mk b/410guests/guests.mk new file mode 100644 index 0000000..503f425 --- /dev/null +++ b/410guests/guests.mk @@ -0,0 +1,28 @@ +# Add hooks to push {very,}clean down into the guests +GUEST_CLEAN=for g in $(STUDENTGUESTS); do make -C $(STUGDIR)/$$g clean; done +GUEST_VERYCLEAN=for g in $(STUDENTGUESTS); do make -C $(STUGDIR)/$$g veryclean; done +GUEST_UPDATE=for g in $(STUDENTGUESTS); do make -C $(STUGDIR)/$$g update; done + +# Add guest images into the "ramdisk" +FILES+=$(STUDENTGUESTS) + +# Having done the above hook, we'll get asked to make targets for +# $(BUILDDIR)/${GUEST}; here's how we do that, using (ick) +# recursive make. We tell this make that these are .PHONY targets +# so that they always get rebuilt, because we don't have visibility +# into the dependency structure internally. Probably, that will +# go quickly, and it's not like it takes us a long time to rebuild +# the ramdisk image in light of spurious changes. +.PHONY: $(STUDENTGUESTS:%=$(BUILDDIR)/%) +$(STUDENTGUESTS:%=$(BUILDDIR)/%) : $(BUILDDIR)/% : + make -C $(STUGDIR)/$* kernel.strip + mkdir -p $(BUILDDIR) + cp -p $(STUGDIR)/$*/kernel.strip $@ + +# Add pre-compiled guest binaries into the "ramdisk" +FILES+=$(410GUESTBINS) + +$(410GUESTBINS:%=$(BUILDDIR)/%): \ +$(BUILDDIR)/%: $(410GDIR)/%.bin + mkdir -p $(BUILDDIR) + strip -o $@ $< diff --git a/410guests/hello.bin b/410guests/hello.bin new file mode 100755 index 0000000..bce972c Binary files /dev/null and b/410guests/hello.bin differ diff --git a/410guests/hello/config.mk b/410guests/hello/config.mk new file mode 100644 index 0000000..9cbd33c --- /dev/null +++ b/410guests/hello/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + hello.o \ + fake_console.o hvstubs.o diff --git a/410guests/hello/kern/fake_console.c b/410guests/hello/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/hello/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/hello/kern/hello.c b/410guests/hello/kern/hello.c new file mode 100644 index 0000000..e300387 --- /dev/null +++ b/410guests/hello/kern/hello.c @@ -0,0 +1,59 @@ +/** @file hello.c + * + * @brief Minimal guest kernel -- uses just lprintf() + * + * @author relong + * + * Hello is a PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include + +#include +#include + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int +kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) +{ + lprintf("Well, here I am!"); + + if (!hv_isguest()) { + lprintf("Not a guest?"); + panic("This payload is guest-only"); + return -1; + } + + lprintf("Successfully running as a guest"); + + while (1) { + continue; + } +} diff --git a/410guests/hello/kern/hvstubs.S b/410guests/hello/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/hello/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/hello/kern/inc/console.h b/410guests/hello/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/hello/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/magic.bin b/410guests/magic.bin new file mode 100755 index 0000000..88c289d Binary files /dev/null and b/410guests/magic.bin differ diff --git a/410guests/magic/config.mk b/410guests/magic/config.mk new file mode 100644 index 0000000..35ac3ca --- /dev/null +++ b/410guests/magic/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + magic.o \ + fake_console.o hvstubs.o diff --git a/410guests/magic/kern/fake_console.c b/410guests/magic/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/magic/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/magic/kern/hvstubs.S b/410guests/magic/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/magic/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/magic/kern/inc/console.h b/410guests/magic/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/magic/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/magic/kern/magic.c b/410guests/magic/kern/magic.c new file mode 100644 index 0000000..53fd3ae --- /dev/null +++ b/410guests/magic/kern/magic.c @@ -0,0 +1,66 @@ +/** @file magic.c + * + * @brief Simplistic guest kernel -- invokes only hv_magic(). + * + * @author de0u + * + * Magic is a PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include + +#include +#include + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int +kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) +{ + lprintf("Well, here I am!"); + + if (!hv_isguest()) { + lprintf("Not a guest?"); + panic("This payload is guest-only"); + return -1; + } + + if (hv_magic() == HV_MAGIC) { + lprintf("Ho, ho, ho,"); + lprintf("It's magic, you know..."); + lprintf("Never believe it's not so."); + } else { + lprintf("What's the difference between a duck?"); + /* One of its legs are both the same. */ + } + + while (1) { + continue; + } +} diff --git a/410guests/pathos.bin b/410guests/pathos.bin new file mode 100755 index 0000000..3e9fde0 Binary files /dev/null and b/410guests/pathos.bin differ diff --git a/410guests/station.bin b/410guests/station.bin new file mode 100755 index 0000000..f78e679 Binary files /dev/null and b/410guests/station.bin differ diff --git a/410guests/station/config.mk b/410guests/station/config.mk new file mode 100644 index 0000000..646b653 --- /dev/null +++ b/410guests/station/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + station.o \ + fake_console.o hvstubs.o diff --git a/410guests/station/kern/fake_console.c b/410guests/station/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/station/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/station/kern/hvstubs.S b/410guests/station/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/station/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/station/kern/inc/console.h b/410guests/station/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/station/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/station/kern/station.c b/410guests/station/kern/station.c new file mode 100644 index 0000000..b11bb0f --- /dev/null +++ b/410guests/station/kern/station.c @@ -0,0 +1,97 @@ +/** @file station.c + * + * @brief Exercises clock interrupts in a charming fashion. + * + * @author de0u + * + * PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include +#include + +#define DEBUG +#include + +#include +#include + +/* https://classictrainsongs.com/down_by_station/down_by_the_station.htm */ +char *lyrics[] = { + "Down by the station early in the morning,\n", + "See the little puffer bellies all in a row.\n", + "See the station master turn the little handle,\n", + "Chug, chug, toot, toot, off we go.\n", + NULL +}; + +void +twiddle(void) +{ + volatile int accumulator = 0; + while (accumulator != -1) + ++accumulator; + panic("Uh oh, overflow, population, common group"); +} + +#define DELAY_TICKS 10 // If you make this much larger, what happens next will shock you! + +volatile int tick = 0; +volatile int line = 0; + +void +tickback(void) +{ + if (++tick == DELAY_TICKS) { + tick = 0; + hv_print(strlen(lyrics[line]), (unsigned char *)lyrics[line]); + ++line; + if (lyrics[line] == NULL) + hv_exit(0); + } + hv_enable_interrupts(); + twiddle(); +} + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int +kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) +{ + if (!hv_isguest()) { + lprintf("I am NOT supposed to be here!!!"); + panic("This payload is guest-only"); + return (-1); + } + hv_setidt(HV_TICKBACK, tickback, HV_SETIDT_PRIVILEGED); + hv_setidt(HV_KEYBOARD, tickback, HV_SETIDT_PRIVILEGED); + hv_enable_interrupts(); + twiddle(); + return (-99); +} diff --git a/410guests/teeny.bin b/410guests/teeny.bin new file mode 100755 index 0000000..f666b9f Binary files /dev/null and b/410guests/teeny.bin differ diff --git a/410guests/teeny/config.mk b/410guests/teeny/config.mk new file mode 100644 index 0000000..aaa5e0e --- /dev/null +++ b/410guests/teeny/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + teeny.o \ + fake_console.o hvstubs.o diff --git a/410guests/teeny/kern/fake_console.c b/410guests/teeny/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/teeny/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/teeny/kern/hvstubs.S b/410guests/teeny/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/teeny/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/teeny/kern/inc/console.h b/410guests/teeny/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/teeny/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/teeny/kern/teeny.c b/410guests/teeny/kern/teeny.c new file mode 100644 index 0000000..6478fe0 --- /dev/null +++ b/410guests/teeny/kern/teeny.c @@ -0,0 +1,97 @@ +/** @file teeny.c + * + * @brief Creates a tiny address space (just big enough + * to map the guest-kernel ELF image). + * @author de0u + * + * PebPeb-only executable -- it doesn't work on hardware. + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include + +#include +#include + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) { + // start, end of kernel image (odd declarations) + extern unsigned char __kimg_start[]; + extern unsigned char _end[]; + unsigned char * addr; + uint32_t * pt0, *pd; + int p; + + lprintf("Well, here I am!"); + + if (!hv_isguest()) { + lprintf("I am NOT supposed to be here!!!"); + panic("This payload is guest-only"); + return (-1); + } + + assert(hv_magic() == HV_MAGIC); + + pt0 = _smemalign(PAGE_SIZE, PAGE_SIZE); + pd = _smemalign(PAGE_SIZE, PAGE_SIZE); + if (!pt0 || !pd) { + panic("Cannot allocate memory"); + } + bzero(pt0, PAGE_SIZE); + bzero(pd, PAGE_SIZE); + + addr = (unsigned char *)(((unsigned int)__kimg_start) + & ((unsigned int)~0x0FFF)); + p = (unsigned int)addr >> PAGE_SHIFT; + + lprintf("Addr %p, p %d (end %p)", addr, p, _end); + + while (addr <= _end) { + lprintf("Mapping %p as page %d", addr, p); + pt0[p] = (p << PAGE_SHIFT) | (1 << 10) | 3; + addr += PAGE_SIZE; + ++p; + } + + pd[0] = ((uint32_t)pt0) | 1; + + lprintf("Transitioning into hyperspace..."); + hv_setpd(pd, 0); + lprintf("Ok... Now, to pass the test, we must die without printing anything else."); + + p = *(int *) USER_MEM_START; + + lprintf("TEST HAS FAILED"); + lprintf("TEST HAS FAILED"); + lprintf("TEST HAS FAILED"); + lprintf("TEST HAS FAILED"); + lprintf("TEST HAS FAILED"); + + hv_exit(-99); + return (-99); +} diff --git a/410guests/tick_tock.bin b/410guests/tick_tock.bin new file mode 100755 index 0000000..76da012 Binary files /dev/null and b/410guests/tick_tock.bin differ diff --git a/410guests/tick_tock/config.mk b/410guests/tick_tock/config.mk new file mode 100644 index 0000000..4be80e9 --- /dev/null +++ b/410guests/tick_tock/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + tick_tock.o \ + fake_console.o hvstubs.o diff --git a/410guests/tick_tock/kern/fake_console.c b/410guests/tick_tock/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/tick_tock/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/tick_tock/kern/hvstubs.S b/410guests/tick_tock/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/tick_tock/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/tick_tock/kern/inc/console.h b/410guests/tick_tock/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/tick_tock/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/tick_tock/kern/tick_tock.c b/410guests/tick_tock/kern/tick_tock.c new file mode 100644 index 0000000..796b06b --- /dev/null +++ b/410guests/tick_tock/kern/tick_tock.c @@ -0,0 +1,107 @@ +/** + * @brief A simple test of interrupt delivery + * + * Prints tock every 50 timer tick received and print tick every + * time a key is hit + * + * Requires hv_iret going kernel to kernel, hv_print, and hv_setidt + * + * @author mischnal + * @author relong + * + * PebPeb-only executable -- it doesn't work on hardware. + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include +#include /* interrupt_setup() */ +#include +#include +#include /* install_user_segs() */ +#include + +#include +#include + +#include +#include + +static void tick(void); +static void tock(void); +static void loop(void); + +static long stack[1024]; + +#define STRLEN(s) (sizeof(s) - 1) +static const char tick_message[] = " tick\n"; +static const char tock_message[] = "tock\n"; + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) { + lprintf("Well, here I am!"); + + if (!hv_isguest()) { + lprintf("Not a guest?"); + panic("This payload is guest-only"); + return -1; + } + + lprintf("Successfully running as a guest"); + + hv_setidt(KEY_IDT_ENTRY, tick, HV_SETIDT_PRIVILEGED); + hv_setidt(TIMER_IDT_ENTRY, tock, HV_SETIDT_PRIVILEGED); + + hv_enable_interrupts(); + + while (1) { + continue; + } +} + +static void tick(void) { + hv_print(STRLEN(tick_message), (unsigned char *)tick_message); + hv_iret(loop, + get_eflags(), // Interrupts enabled + (stack + 1023), + 0, + 0); +} + +static void tock(void) { + static unsigned int tocks = 0; + tocks++; + if (tocks % 50 == 0) { + hv_print(STRLEN(tock_message), (unsigned char *)tock_message); + } + hv_iret(loop, + get_eflags(), // Interrupts enabled + stack + 1023, + 0, + 0); +} + +static void loop(void) { + while (1) { + continue; + } +} diff --git a/410guests/vast.bin b/410guests/vast.bin new file mode 100755 index 0000000..3ab730b Binary files /dev/null and b/410guests/vast.bin differ diff --git a/410guests/vast/config.mk b/410guests/vast/config.mk new file mode 100644 index 0000000..9a1bde3 --- /dev/null +++ b/410guests/vast/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + vast.o \ + fake_console.o hvstubs.o diff --git a/410guests/vast/kern/fake_console.c b/410guests/vast/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/vast/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/vast/kern/hvstubs.S b/410guests/vast/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/vast/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/vast/kern/inc/console.h b/410guests/vast/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/vast/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/vast/kern/vast.c b/410guests/vast/kern/vast.c new file mode 100644 index 0000000..3f810d1 --- /dev/null +++ b/410guests/vast/kern/vast.c @@ -0,0 +1,111 @@ +/** @file vast.c + * + * @brief Creates a large address space and explores it + * + * Vast maps the bottom four megabytes of "physical memory" + * repeatedly into the entire 32-bit virtual address space. + * It then reads from every other page (there shouldn't be + * any faults), totaling up the values it reads, and then + * lprintf()s the nonsense value that results. + * + * When complete, it hv_exit(99) + * + * @author de0u + * @author relong + * + * Hello is a PebPeb-only executable -- it doesn't work on hardware. + * + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include +#include + +#define STRLEN(s) (sizeof(s) - 1) +static const char READY_MESSAGE[] = "Setting Page Directory\n"; +static const char SET_MESSAGE[] = "Page Directory Set successfully\n"; +static const char PASSING_MESSAGE[] = "Vast passing\n"; + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) { + uint32_t *pt, *pd, *p; + int i, t = 0; + + + lprintf("Hello from a brand new kernel!"); + + if (!hv_isguest()) { + lprintf("I am NOT supposed to be here!!!"); + panic("This payload is guest-only"); + return (-1); + } + + pt = _smemalign(PAGE_SIZE, PAGE_SIZE); + pd = _smemalign(PAGE_SIZE, PAGE_SIZE); + if (!pt || !pd) { + panic("Cannot allocate memory"); + } + + for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); i++) { + pt[i] = (i << PAGE_SHIFT) | 3; + pd[i] = ((uint32_t)pt) | 3; + } + + // Unmap the last 16 MB + for (i = 0; i < 4; i++) { + pd[(PAGE_SIZE / sizeof(uint32_t)) - 1 - i] = 0; + } + + lprintf("I hope this works..."); + hv_print(STRLEN(READY_MESSAGE), (unsigned char *)READY_MESSAGE); + hv_setpd(pd, 0); + lprintf("Whew!! Now let's take a look around."); + hv_print(STRLEN(SET_MESSAGE), (unsigned char *)SET_MESSAGE); + lprintf("Reading now"); + + void *maxAddress = hv_maxvaddr(); + + lprintf("Max Address: %p", maxAddress); + + for (p = (uint32_t *)0; p <= (uint32_t *)maxAddress; p += 8192) { + t += *p; + } + + lprintf("YAY!!! (t = 0x%x, FWIW)", t); + hv_print(STRLEN(PASSING_MESSAGE), (unsigned char *)PASSING_MESSAGE); + + hv_exit(99); + + while (1) { + lprintf("In dead man loop"); + continue; + } + + return -1; +} diff --git a/410guests/warp.bin b/410guests/warp.bin new file mode 100755 index 0000000..d1271b7 Binary files /dev/null and b/410guests/warp.bin differ diff --git a/410guests/warp/config.mk b/410guests/warp/config.mk new file mode 100644 index 0000000..a8a2b83 --- /dev/null +++ b/410guests/warp/config.mk @@ -0,0 +1,7 @@ +UPDATE_METHOD = afs + +CC = gcc + +KERNEL_OBJS = \ + warp.o warp_main.o warp_map.o \ + fake_console.o hvstubs.o diff --git a/410guests/warp/kern/fake_console.c b/410guests/warp/kern/fake_console.c new file mode 100644 index 0000000..f79a60e --- /dev/null +++ b/410guests/warp/kern/fake_console.c @@ -0,0 +1,87 @@ +/** @file console.c + * @brief A console driver. + * + * These empty function definitions are provided + * so that stdio will build without complaining. + * You will need to fill these functions in. This + * is the implementation of the console driver. + * Important details about its implementation + * should go in these comments. + * + * @author Harry Q. Bovik (hqbovik) + * @author Fred Hacker (fhacker) + * @bug No know bugs. + */ + +#include + +/* Not very reentrant, but enough to lmm_dump() */ +#include +int putbyte( char ch ) +{ + static char buf[1024], *cp = buf; + + if (ch == '\n') { + *cp = '\0'; + lprintf("%s", buf); + cp = buf; + } else if (cp < buf + sizeof (buf) - 1) { + *cp++ = ch; + } + return ch; +} + +void +putbytes( const char *s, int len ) +{ + while (len-- > 0) + (void) putbyte(*s++); +} + +int +set_term_color( int color ) +{ + return (-1); +} + +void +get_term_color( int *color ) +{ +} + +int +set_cursor( int row, int col ) +{ + return (-1); +} + +void +get_cursor( int *row, int *col ) +{ +} + +void +hide_cursor() +{ +} + +void +show_cursor() +{ +} + +void +clear_console() +{ +} + +void +draw_char( int row, int col, int ch, int color ) +{ +} + +char +get_char( int row, int col ) +{ + return ' '; +} diff --git a/410guests/warp/kern/hvstubs.S b/410guests/warp/kern/hvstubs.S new file mode 100644 index 0000000..01f5bf6 --- /dev/null +++ b/410guests/warp/kern/hvstubs.S @@ -0,0 +1,33 @@ +.globl hv_magic +.globl hv_exit +.globl hv_setidt +.globl hv_disable_interrupts +.globl hv_enable_interrupts +.globl hv_setpd +.globl hv_adjustpg +.globl hv_print +.globl hv_cons_set_term_color +.globl hv_cons_set_cursor_pos +.globl hv_cons_get_cursor_pos +.globl hv_iret +.globl hv_print_at + +hv_magic: +hv_exit: +hv_setidt: +hv_disable_interrupts: +hv_enable_interrupts: +hv_setpd: +hv_adjustpg: +hv_print: +hv_cons_set_term_color: +hv_cons_set_cursor_pos: +hv_cons_get_cursor_pos: +hv_iret: +hv_print_at: + pushl %ebp + movl %esp, %ebp + movl $80808080, %eax + movl %eax, (%eax) + leave + ret diff --git a/410guests/warp/kern/inc/console.h b/410guests/warp/kern/inc/console.h new file mode 100644 index 0000000..e763057 --- /dev/null +++ b/410guests/warp/kern/inc/console.h @@ -0,0 +1,159 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes and global variables for the console + * driver + * + * @author Michael Berman (mberman) + * @bug No known bugs. + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte( char ch ); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/410guests/warp/kern/inc/warp.h b/410guests/warp/kern/inc/warp.h new file mode 100644 index 0000000..9bc6666 --- /dev/null +++ b/410guests/warp/kern/inc/warp.h @@ -0,0 +1,11 @@ +#ifndef __WARP_H__ +#define __WARP_H__ + +extern uint32_t *dmap; /* warp_map.S */ + +#define WARP_VADDR 0x01000000 +#define WARP_PADDR 0x0100f000 + +void warp(void *esp, char *s, int len); /* warp.S */ + +#endif /* __WARP_H__ */ diff --git a/410guests/warp/kern/warp.S b/410guests/warp/kern/warp.S new file mode 100644 index 0000000..10e4a81 --- /dev/null +++ b/410guests/warp/kern/warp.S @@ -0,0 +1,35 @@ +/** @file warp.S + * + * @brief Just point our stack at the top of the indirectly mapped frame, + * trigger a hypercall, and clean up after ourselves. + * + * @param esp new stack pointer to adopt + * @param s guest-virtual address of string to print + * @param len number of bytes to print + * + * @author rpearl + * @author de0u + */ +#include + +.globl warp + +warp: + pushl %ebp + movl %esp, %ebp + + movl 8(%ebp), %esp /* adopt new stack pointer */ + + movl 12(%ebp), %eax /* string address */ + pushl %eax + + movl 16(%ebp), %eax /* string length */ + pushl %eax + + movl $HV_PRINT_OP, %eax /* hypercall */ + int $HV_INT + + movl %ebp, %esp /* back to old stack */ + popl %ebp + + ret diff --git a/410guests/warp/kern/warp_main.c b/410guests/warp/kern/warp_main.c new file mode 100644 index 0000000..3df7795 --- /dev/null +++ b/410guests/warp/kern/warp_main.c @@ -0,0 +1,118 @@ +/** @file warp_main.c + * @brief Tests that hypercall addresses are translated appropriatedly. + * + * The virtual address 0x01000000 (16 MB) is mapped in a non-direct + * way (to 0x0100f000, 15 pages higher), then the stack pointer is + * shifted to the top of that page (0x01000FF0), then a hypercall + * is made to print a string. + * + * You would naively think that would fail horribly unless hv_setpd() + * is working, but you would be wrong. If hv_setpd() does absolutely + * nothing, then virtual 0x01000000 remains mapped to physical + * 0x01000000, the stack works fine, and the test passes. This is + * not wild speculation; is was observed S'19. + * + * To combat this, we can't use a string in the kernel's rodata, + * which never "moves". So before we install the new warped page + * tables we put a string at the bottom of the "physical" page, + * install the new warped page tables, swing the stack pointer + * to the warped virtual address, and print the string using the + * warped virtual address. If the warped mapping wasn't established + * the string shouldn't print. + * + * If the test works right, the host kernel should display a greeting + * message in the guest's console window, a success message should + * be printed on the Simics console (if running under Simics), and + * then the guest should exit. + * + * @author rpearl + * @author de0u + * + * PebPeb-only executable -- it doesn't work on hardware. + */ + +#include + +/* libc includes. */ +#include +#include /* lprintf() */ +#include + +/* multiboot header file */ +#include /* boot_info */ + +/* memory includes. */ +#include /* lmm_remove_free() */ + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include +#include /* interrupt_setup() */ +#include +#include /* install_user_segs() */ + +#include +#include + +#include +#include + +#include + +/* We're going to construct a page directory and page table + * which is not direct-mapped. + * + * So, in C, we're going to construct a vm with kernel direct-mapped, + * and also have the top most page table mapped. The topmost page will + * be mapped... to a frame from the kernel. This will be our stack. + * + * In assembly, we'll switch to that stack, and then make a hypercall. + */ + + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp) { + + char msg[] = "Hello down there!"; + int msglen = sizeof (msg) - 1; + + lprintf("Hello from a brand new kernel!"); + + if (!hv_isguest()) { + lprintf("I am NOT supposed to be here!!!"); + panic("This payload is guest-only"); + return (-1); + } + + /* Install the string in physical memory where the virtual + * address should be mapped to. + */ + strcpy((char *)WARP_PADDR, msg); + + /* Right now, &dmap contains all the information we need. + * But, it assumes that the page directory is at USER_MEM_START, + * so we'll move it up there. + */ + uint32_t *pd = (uint32_t *)USER_MEM_START; + /* One frame for PD, and 5 PTs. */ + memcpy(pd, &dmap, 6 * PAGE_SIZE); + + lprintf("Remapping..."); + hv_setpd(pd, 0); + + lprintf("After stack warping, guest console should display:\"%s\"", msg); + + lprintf("Warping..."); + warp((void *)(WARP_VADDR + PAGE_SIZE - sizeof (uint32_t)), (char *)WARP_VADDR, msglen); + lprintf("***** SURVIVED, CHECK GUEST CONSOLE FOR MESSAGE *****"); + + hv_exit(0xfaded); + + lprintf("hv_exit() returned"); + return -1; +} diff --git a/410guests/warp/kern/warp_map.S b/410guests/warp/kern/warp_map.S new file mode 100644 index 0000000..c9cba6f --- /dev/null +++ b/410guests/warp/kern/warp_map.S @@ -0,0 +1,4126 @@ +/** @file dmap.S + * + * @brief Horrifying VM hacks. + * This file defines a direct-mapped page directory. The directory address + * is at 16MB (0x01000000), and the page tables are in the next consecutive + * pages. + * + * We also map in the virtual address 0x01000000 to the physical address + * 0x0100f000, which is the point of this test. Hypercalls must translate + * through the guest's VM--in many guests (say, a P1 game or a Pebbles kernel) + * the relevant addresses are always direct-mapped; the point of this test + * is to make sure things work when non-direct mappings are used. + * + * @author rpearl + */ + +.global dmap +dmap: +# This is the page directory, at 0x01000000 +# It contains entries for the bottom 20MB of address space. +.long 0x01001003 # 0 ( 0 - 4MB) +.long 0x01002003 # 1 ( 4MB - 8MB) +.long 0x01003003 # 2 ( 8MB - 12MB) +.long 0x01004003 # 3 (12MB - 16MB) +.long 0x01005003 # 4 (16MB - 20MB) +.fill 1019, 4, 0 +.long 0x00000000 #First page table (next 1024 entries) +.long 0x00001000 +.long 0x00002000 +.long 0x00003000 +.long 0x00004003 +.long 0x00005003 +.long 0x00006003 +.long 0x00007003 +.long 0x00008003 +.long 0x00009003 +.long 0x0000a003 +.long 0x0000b003 +.long 0x0000c003 +.long 0x0000d003 +.long 0x0000e003 +.long 0x0000f003 +.long 0x00010003 +.long 0x00011003 +.long 0x00012003 +.long 0x00013003 +.long 0x00014003 +.long 0x00015003 +.long 0x00016003 +.long 0x00017003 +.long 0x00018003 +.long 0x00019003 +.long 0x0001a003 +.long 0x0001b003 +.long 0x0001c003 +.long 0x0001d003 +.long 0x0001e003 +.long 0x0001f003 +.long 0x00020003 +.long 0x00021003 +.long 0x00022003 +.long 0x00023003 +.long 0x00024003 +.long 0x00025003 +.long 0x00026003 +.long 0x00027003 +.long 0x00028003 +.long 0x00029003 +.long 0x0002a003 +.long 0x0002b003 +.long 0x0002c003 +.long 0x0002d003 +.long 0x0002e003 +.long 0x0002f003 +.long 0x00030003 +.long 0x00031003 +.long 0x00032003 +.long 0x00033003 +.long 0x00034003 +.long 0x00035003 +.long 0x00036003 +.long 0x00037003 +.long 0x00038003 +.long 0x00039003 +.long 0x0003a003 +.long 0x0003b003 +.long 0x0003c003 +.long 0x0003d003 +.long 0x0003e003 +.long 0x0003f003 +.long 0x00040003 +.long 0x00041003 +.long 0x00042003 +.long 0x00043003 +.long 0x00044003 +.long 0x00045003 +.long 0x00046003 +.long 0x00047003 +.long 0x00048003 +.long 0x00049003 +.long 0x0004a003 +.long 0x0004b003 +.long 0x0004c003 +.long 0x0004d003 +.long 0x0004e003 +.long 0x0004f003 +.long 0x00050003 +.long 0x00051003 +.long 0x00052003 +.long 0x00053003 +.long 0x00054003 +.long 0x00055003 +.long 0x00056003 +.long 0x00057003 +.long 0x00058003 +.long 0x00059003 +.long 0x0005a003 +.long 0x0005b003 +.long 0x0005c003 +.long 0x0005d003 +.long 0x0005e003 +.long 0x0005f003 +.long 0x00060003 +.long 0x00061003 +.long 0x00062003 +.long 0x00063003 +.long 0x00064003 +.long 0x00065003 +.long 0x00066003 +.long 0x00067003 +.long 0x00068003 +.long 0x00069003 +.long 0x0006a003 +.long 0x0006b003 +.long 0x0006c003 +.long 0x0006d003 +.long 0x0006e003 +.long 0x0006f003 +.long 0x00070003 +.long 0x00071003 +.long 0x00072003 +.long 0x00073003 +.long 0x00074003 +.long 0x00075003 +.long 0x00076003 +.long 0x00077003 +.long 0x00078003 +.long 0x00079003 +.long 0x0007a003 +.long 0x0007b003 +.long 0x0007c003 +.long 0x0007d003 +.long 0x0007e003 +.long 0x0007f003 +.long 0x00080003 +.long 0x00081003 +.long 0x00082003 +.long 0x00083003 +.long 0x00084003 +.long 0x00085003 +.long 0x00086003 +.long 0x00087003 +.long 0x00088003 +.long 0x00089003 +.long 0x0008a003 +.long 0x0008b003 +.long 0x0008c003 +.long 0x0008d003 +.long 0x0008e003 +.long 0x0008f003 +.long 0x00090003 +.long 0x00091003 +.long 0x00092003 +.long 0x00093003 +.long 0x00094003 +.long 0x00095003 +.long 0x00096003 +.long 0x00097003 +.long 0x00098003 +.long 0x00099003 +.long 0x0009a003 +.long 0x0009b003 +.long 0x0009c003 +.long 0x0009d003 +.long 0x0009e003 +.long 0x0009f003 +.long 0x000a0003 +.long 0x000a1003 +.long 0x000a2003 +.long 0x000a3003 +.long 0x000a4003 +.long 0x000a5003 +.long 0x000a6003 +.long 0x000a7003 +.long 0x000a8003 +.long 0x000a9003 +.long 0x000aa003 +.long 0x000ab003 +.long 0x000ac003 +.long 0x000ad003 +.long 0x000ae003 +.long 0x000af003 +.long 0x000b0003 +.long 0x000b1003 +.long 0x000b2003 +.long 0x000b3003 +.long 0x000b4003 +.long 0x000b5003 +.long 0x000b6003 +.long 0x000b7003 +.long 0x000b8003 +.long 0x000b9003 +.long 0x000ba003 +.long 0x000bb003 +.long 0x000bc003 +.long 0x000bd003 +.long 0x000be003 +.long 0x000bf003 +.long 0x000c0003 +.long 0x000c1003 +.long 0x000c2003 +.long 0x000c3003 +.long 0x000c4003 +.long 0x000c5003 +.long 0x000c6003 +.long 0x000c7003 +.long 0x000c8003 +.long 0x000c9003 +.long 0x000ca003 +.long 0x000cb003 +.long 0x000cc003 +.long 0x000cd003 +.long 0x000ce003 +.long 0x000cf003 +.long 0x000d0003 +.long 0x000d1003 +.long 0x000d2003 +.long 0x000d3003 +.long 0x000d4003 +.long 0x000d5003 +.long 0x000d6003 +.long 0x000d7003 +.long 0x000d8003 +.long 0x000d9003 +.long 0x000da003 +.long 0x000db003 +.long 0x000dc003 +.long 0x000dd003 +.long 0x000de003 +.long 0x000df003 +.long 0x000e0003 +.long 0x000e1003 +.long 0x000e2003 +.long 0x000e3003 +.long 0x000e4003 +.long 0x000e5003 +.long 0x000e6003 +.long 0x000e7003 +.long 0x000e8003 +.long 0x000e9003 +.long 0x000ea003 +.long 0x000eb003 +.long 0x000ec003 +.long 0x000ed003 +.long 0x000ee003 +.long 0x000ef003 +.long 0x000f0003 +.long 0x000f1003 +.long 0x000f2003 +.long 0x000f3003 +.long 0x000f4003 +.long 0x000f5003 +.long 0x000f6003 +.long 0x000f7003 +.long 0x000f8003 +.long 0x000f9003 +.long 0x000fa003 +.long 0x000fb003 +.long 0x000fc003 +.long 0x000fd003 +.long 0x000fe003 +.long 0x000ff003 +.long 0x00100003 +.long 0x00101003 +.long 0x00102003 +.long 0x00103003 +.long 0x00104003 +.long 0x00105003 +.long 0x00106003 +.long 0x00107003 +.long 0x00108003 +.long 0x00109003 +.long 0x0010a003 +.long 0x0010b003 +.long 0x0010c003 +.long 0x0010d003 +.long 0x0010e003 +.long 0x0010f003 +.long 0x00110003 +.long 0x00111003 +.long 0x00112003 +.long 0x00113003 +.long 0x00114003 +.long 0x00115003 +.long 0x00116003 +.long 0x00117003 +.long 0x00118003 +.long 0x00119003 +.long 0x0011a003 +.long 0x0011b003 +.long 0x0011c003 +.long 0x0011d003 +.long 0x0011e003 +.long 0x0011f003 +.long 0x00120003 +.long 0x00121003 +.long 0x00122003 +.long 0x00123003 +.long 0x00124003 +.long 0x00125003 +.long 0x00126003 +.long 0x00127003 +.long 0x00128003 +.long 0x00129003 +.long 0x0012a003 +.long 0x0012b003 +.long 0x0012c003 +.long 0x0012d003 +.long 0x0012e003 +.long 0x0012f003 +.long 0x00130003 +.long 0x00131003 +.long 0x00132003 +.long 0x00133003 +.long 0x00134003 +.long 0x00135003 +.long 0x00136003 +.long 0x00137003 +.long 0x00138003 +.long 0x00139003 +.long 0x0013a003 +.long 0x0013b003 +.long 0x0013c003 +.long 0x0013d003 +.long 0x0013e003 +.long 0x0013f003 +.long 0x00140003 +.long 0x00141003 +.long 0x00142003 +.long 0x00143003 +.long 0x00144003 +.long 0x00145003 +.long 0x00146003 +.long 0x00147003 +.long 0x00148003 +.long 0x00149003 +.long 0x0014a003 +.long 0x0014b003 +.long 0x0014c003 +.long 0x0014d003 +.long 0x0014e003 +.long 0x0014f003 +.long 0x00150003 +.long 0x00151003 +.long 0x00152003 +.long 0x00153003 +.long 0x00154003 +.long 0x00155003 +.long 0x00156003 +.long 0x00157003 +.long 0x00158003 +.long 0x00159003 +.long 0x0015a003 +.long 0x0015b003 +.long 0x0015c003 +.long 0x0015d003 +.long 0x0015e003 +.long 0x0015f003 +.long 0x00160003 +.long 0x00161003 +.long 0x00162003 +.long 0x00163003 +.long 0x00164003 +.long 0x00165003 +.long 0x00166003 +.long 0x00167003 +.long 0x00168003 +.long 0x00169003 +.long 0x0016a003 +.long 0x0016b003 +.long 0x0016c003 +.long 0x0016d003 +.long 0x0016e003 +.long 0x0016f003 +.long 0x00170003 +.long 0x00171003 +.long 0x00172003 +.long 0x00173003 +.long 0x00174003 +.long 0x00175003 +.long 0x00176003 +.long 0x00177003 +.long 0x00178003 +.long 0x00179003 +.long 0x0017a003 +.long 0x0017b003 +.long 0x0017c003 +.long 0x0017d003 +.long 0x0017e003 +.long 0x0017f003 +.long 0x00180003 +.long 0x00181003 +.long 0x00182003 +.long 0x00183003 +.long 0x00184003 +.long 0x00185003 +.long 0x00186003 +.long 0x00187003 +.long 0x00188003 +.long 0x00189003 +.long 0x0018a003 +.long 0x0018b003 +.long 0x0018c003 +.long 0x0018d003 +.long 0x0018e003 +.long 0x0018f003 +.long 0x00190003 +.long 0x00191003 +.long 0x00192003 +.long 0x00193003 +.long 0x00194003 +.long 0x00195003 +.long 0x00196003 +.long 0x00197003 +.long 0x00198003 +.long 0x00199003 +.long 0x0019a003 +.long 0x0019b003 +.long 0x0019c003 +.long 0x0019d003 +.long 0x0019e003 +.long 0x0019f003 +.long 0x001a0003 +.long 0x001a1003 +.long 0x001a2003 +.long 0x001a3003 +.long 0x001a4003 +.long 0x001a5003 +.long 0x001a6003 +.long 0x001a7003 +.long 0x001a8003 +.long 0x001a9003 +.long 0x001aa003 +.long 0x001ab003 +.long 0x001ac003 +.long 0x001ad003 +.long 0x001ae003 +.long 0x001af003 +.long 0x001b0003 +.long 0x001b1003 +.long 0x001b2003 +.long 0x001b3003 +.long 0x001b4003 +.long 0x001b5003 +.long 0x001b6003 +.long 0x001b7003 +.long 0x001b8003 +.long 0x001b9003 +.long 0x001ba003 +.long 0x001bb003 +.long 0x001bc003 +.long 0x001bd003 +.long 0x001be003 +.long 0x001bf003 +.long 0x001c0003 +.long 0x001c1003 +.long 0x001c2003 +.long 0x001c3003 +.long 0x001c4003 +.long 0x001c5003 +.long 0x001c6003 +.long 0x001c7003 +.long 0x001c8003 +.long 0x001c9003 +.long 0x001ca003 +.long 0x001cb003 +.long 0x001cc003 +.long 0x001cd003 +.long 0x001ce003 +.long 0x001cf003 +.long 0x001d0003 +.long 0x001d1003 +.long 0x001d2003 +.long 0x001d3003 +.long 0x001d4003 +.long 0x001d5003 +.long 0x001d6003 +.long 0x001d7003 +.long 0x001d8003 +.long 0x001d9003 +.long 0x001da003 +.long 0x001db003 +.long 0x001dc003 +.long 0x001dd003 +.long 0x001de003 +.long 0x001df003 +.long 0x001e0003 +.long 0x001e1003 +.long 0x001e2003 +.long 0x001e3003 +.long 0x001e4003 +.long 0x001e5003 +.long 0x001e6003 +.long 0x001e7003 +.long 0x001e8003 +.long 0x001e9003 +.long 0x001ea003 +.long 0x001eb003 +.long 0x001ec003 +.long 0x001ed003 +.long 0x001ee003 +.long 0x001ef003 +.long 0x001f0003 +.long 0x001f1003 +.long 0x001f2003 +.long 0x001f3003 +.long 0x001f4003 +.long 0x001f5003 +.long 0x001f6003 +.long 0x001f7003 +.long 0x001f8003 +.long 0x001f9003 +.long 0x001fa003 +.long 0x001fb003 +.long 0x001fc003 +.long 0x001fd003 +.long 0x001fe003 +.long 0x001ff003 +.long 0x00200003 +.long 0x00201003 +.long 0x00202003 +.long 0x00203003 +.long 0x00204003 +.long 0x00205003 +.long 0x00206003 +.long 0x00207003 +.long 0x00208003 +.long 0x00209003 +.long 0x0020a003 +.long 0x0020b003 +.long 0x0020c003 +.long 0x0020d003 +.long 0x0020e003 +.long 0x0020f003 +.long 0x00210003 +.long 0x00211003 +.long 0x00212003 +.long 0x00213003 +.long 0x00214003 +.long 0x00215003 +.long 0x00216003 +.long 0x00217003 +.long 0x00218003 +.long 0x00219003 +.long 0x0021a003 +.long 0x0021b003 +.long 0x0021c003 +.long 0x0021d003 +.long 0x0021e003 +.long 0x0021f003 +.long 0x00220003 +.long 0x00221003 +.long 0x00222003 +.long 0x00223003 +.long 0x00224003 +.long 0x00225003 +.long 0x00226003 +.long 0x00227003 +.long 0x00228003 +.long 0x00229003 +.long 0x0022a003 +.long 0x0022b003 +.long 0x0022c003 +.long 0x0022d003 +.long 0x0022e003 +.long 0x0022f003 +.long 0x00230003 +.long 0x00231003 +.long 0x00232003 +.long 0x00233003 +.long 0x00234003 +.long 0x00235003 +.long 0x00236003 +.long 0x00237003 +.long 0x00238003 +.long 0x00239003 +.long 0x0023a003 +.long 0x0023b003 +.long 0x0023c003 +.long 0x0023d003 +.long 0x0023e003 +.long 0x0023f003 +.long 0x00240003 +.long 0x00241003 +.long 0x00242003 +.long 0x00243003 +.long 0x00244003 +.long 0x00245003 +.long 0x00246003 +.long 0x00247003 +.long 0x00248003 +.long 0x00249003 +.long 0x0024a003 +.long 0x0024b003 +.long 0x0024c003 +.long 0x0024d003 +.long 0x0024e003 +.long 0x0024f003 +.long 0x00250003 +.long 0x00251003 +.long 0x00252003 +.long 0x00253003 +.long 0x00254003 +.long 0x00255003 +.long 0x00256003 +.long 0x00257003 +.long 0x00258003 +.long 0x00259003 +.long 0x0025a003 +.long 0x0025b003 +.long 0x0025c003 +.long 0x0025d003 +.long 0x0025e003 +.long 0x0025f003 +.long 0x00260003 +.long 0x00261003 +.long 0x00262003 +.long 0x00263003 +.long 0x00264003 +.long 0x00265003 +.long 0x00266003 +.long 0x00267003 +.long 0x00268003 +.long 0x00269003 +.long 0x0026a003 +.long 0x0026b003 +.long 0x0026c003 +.long 0x0026d003 +.long 0x0026e003 +.long 0x0026f003 +.long 0x00270003 +.long 0x00271003 +.long 0x00272003 +.long 0x00273003 +.long 0x00274003 +.long 0x00275003 +.long 0x00276003 +.long 0x00277003 +.long 0x00278003 +.long 0x00279003 +.long 0x0027a003 +.long 0x0027b003 +.long 0x0027c003 +.long 0x0027d003 +.long 0x0027e003 +.long 0x0027f003 +.long 0x00280003 +.long 0x00281003 +.long 0x00282003 +.long 0x00283003 +.long 0x00284003 +.long 0x00285003 +.long 0x00286003 +.long 0x00287003 +.long 0x00288003 +.long 0x00289003 +.long 0x0028a003 +.long 0x0028b003 +.long 0x0028c003 +.long 0x0028d003 +.long 0x0028e003 +.long 0x0028f003 +.long 0x00290003 +.long 0x00291003 +.long 0x00292003 +.long 0x00293003 +.long 0x00294003 +.long 0x00295003 +.long 0x00296003 +.long 0x00297003 +.long 0x00298003 +.long 0x00299003 +.long 0x0029a003 +.long 0x0029b003 +.long 0x0029c003 +.long 0x0029d003 +.long 0x0029e003 +.long 0x0029f003 +.long 0x002a0003 +.long 0x002a1003 +.long 0x002a2003 +.long 0x002a3003 +.long 0x002a4003 +.long 0x002a5003 +.long 0x002a6003 +.long 0x002a7003 +.long 0x002a8003 +.long 0x002a9003 +.long 0x002aa003 +.long 0x002ab003 +.long 0x002ac003 +.long 0x002ad003 +.long 0x002ae003 +.long 0x002af003 +.long 0x002b0003 +.long 0x002b1003 +.long 0x002b2003 +.long 0x002b3003 +.long 0x002b4003 +.long 0x002b5003 +.long 0x002b6003 +.long 0x002b7003 +.long 0x002b8003 +.long 0x002b9003 +.long 0x002ba003 +.long 0x002bb003 +.long 0x002bc003 +.long 0x002bd003 +.long 0x002be003 +.long 0x002bf003 +.long 0x002c0003 +.long 0x002c1003 +.long 0x002c2003 +.long 0x002c3003 +.long 0x002c4003 +.long 0x002c5003 +.long 0x002c6003 +.long 0x002c7003 +.long 0x002c8003 +.long 0x002c9003 +.long 0x002ca003 +.long 0x002cb003 +.long 0x002cc003 +.long 0x002cd003 +.long 0x002ce003 +.long 0x002cf003 +.long 0x002d0003 +.long 0x002d1003 +.long 0x002d2003 +.long 0x002d3003 +.long 0x002d4003 +.long 0x002d5003 +.long 0x002d6003 +.long 0x002d7003 +.long 0x002d8003 +.long 0x002d9003 +.long 0x002da003 +.long 0x002db003 +.long 0x002dc003 +.long 0x002dd003 +.long 0x002de003 +.long 0x002df003 +.long 0x002e0003 +.long 0x002e1003 +.long 0x002e2003 +.long 0x002e3003 +.long 0x002e4003 +.long 0x002e5003 +.long 0x002e6003 +.long 0x002e7003 +.long 0x002e8003 +.long 0x002e9003 +.long 0x002ea003 +.long 0x002eb003 +.long 0x002ec003 +.long 0x002ed003 +.long 0x002ee003 +.long 0x002ef003 +.long 0x002f0003 +.long 0x002f1003 +.long 0x002f2003 +.long 0x002f3003 +.long 0x002f4003 +.long 0x002f5003 +.long 0x002f6003 +.long 0x002f7003 +.long 0x002f8003 +.long 0x002f9003 +.long 0x002fa003 +.long 0x002fb003 +.long 0x002fc003 +.long 0x002fd003 +.long 0x002fe003 +.long 0x002ff003 +.long 0x00300003 +.long 0x00301003 +.long 0x00302003 +.long 0x00303003 +.long 0x00304003 +.long 0x00305003 +.long 0x00306003 +.long 0x00307003 +.long 0x00308003 +.long 0x00309003 +.long 0x0030a003 +.long 0x0030b003 +.long 0x0030c003 +.long 0x0030d003 +.long 0x0030e003 +.long 0x0030f003 +.long 0x00310003 +.long 0x00311003 +.long 0x00312003 +.long 0x00313003 +.long 0x00314003 +.long 0x00315003 +.long 0x00316003 +.long 0x00317003 +.long 0x00318003 +.long 0x00319003 +.long 0x0031a003 +.long 0x0031b003 +.long 0x0031c003 +.long 0x0031d003 +.long 0x0031e003 +.long 0x0031f003 +.long 0x00320003 +.long 0x00321003 +.long 0x00322003 +.long 0x00323003 +.long 0x00324003 +.long 0x00325003 +.long 0x00326003 +.long 0x00327003 +.long 0x00328003 +.long 0x00329003 +.long 0x0032a003 +.long 0x0032b003 +.long 0x0032c003 +.long 0x0032d003 +.long 0x0032e003 +.long 0x0032f003 +.long 0x00330003 +.long 0x00331003 +.long 0x00332003 +.long 0x00333003 +.long 0x00334003 +.long 0x00335003 +.long 0x00336003 +.long 0x00337003 +.long 0x00338003 +.long 0x00339003 +.long 0x0033a003 +.long 0x0033b003 +.long 0x0033c003 +.long 0x0033d003 +.long 0x0033e003 +.long 0x0033f003 +.long 0x00340003 +.long 0x00341003 +.long 0x00342003 +.long 0x00343003 +.long 0x00344003 +.long 0x00345003 +.long 0x00346003 +.long 0x00347003 +.long 0x00348003 +.long 0x00349003 +.long 0x0034a003 +.long 0x0034b003 +.long 0x0034c003 +.long 0x0034d003 +.long 0x0034e003 +.long 0x0034f003 +.long 0x00350003 +.long 0x00351003 +.long 0x00352003 +.long 0x00353003 +.long 0x00354003 +.long 0x00355003 +.long 0x00356003 +.long 0x00357003 +.long 0x00358003 +.long 0x00359003 +.long 0x0035a003 +.long 0x0035b003 +.long 0x0035c003 +.long 0x0035d003 +.long 0x0035e003 +.long 0x0035f003 +.long 0x00360003 +.long 0x00361003 +.long 0x00362003 +.long 0x00363003 +.long 0x00364003 +.long 0x00365003 +.long 0x00366003 +.long 0x00367003 +.long 0x00368003 +.long 0x00369003 +.long 0x0036a003 +.long 0x0036b003 +.long 0x0036c003 +.long 0x0036d003 +.long 0x0036e003 +.long 0x0036f003 +.long 0x00370003 +.long 0x00371003 +.long 0x00372003 +.long 0x00373003 +.long 0x00374003 +.long 0x00375003 +.long 0x00376003 +.long 0x00377003 +.long 0x00378003 +.long 0x00379003 +.long 0x0037a003 +.long 0x0037b003 +.long 0x0037c003 +.long 0x0037d003 +.long 0x0037e003 +.long 0x0037f003 +.long 0x00380003 +.long 0x00381003 +.long 0x00382003 +.long 0x00383003 +.long 0x00384003 +.long 0x00385003 +.long 0x00386003 +.long 0x00387003 +.long 0x00388003 +.long 0x00389003 +.long 0x0038a003 +.long 0x0038b003 +.long 0x0038c003 +.long 0x0038d003 +.long 0x0038e003 +.long 0x0038f003 +.long 0x00390003 +.long 0x00391003 +.long 0x00392003 +.long 0x00393003 +.long 0x00394003 +.long 0x00395003 +.long 0x00396003 +.long 0x00397003 +.long 0x00398003 +.long 0x00399003 +.long 0x0039a003 +.long 0x0039b003 +.long 0x0039c003 +.long 0x0039d003 +.long 0x0039e003 +.long 0x0039f003 +.long 0x003a0003 +.long 0x003a1003 +.long 0x003a2003 +.long 0x003a3003 +.long 0x003a4003 +.long 0x003a5003 +.long 0x003a6003 +.long 0x003a7003 +.long 0x003a8003 +.long 0x003a9003 +.long 0x003aa003 +.long 0x003ab003 +.long 0x003ac003 +.long 0x003ad003 +.long 0x003ae003 +.long 0x003af003 +.long 0x003b0003 +.long 0x003b1003 +.long 0x003b2003 +.long 0x003b3003 +.long 0x003b4003 +.long 0x003b5003 +.long 0x003b6003 +.long 0x003b7003 +.long 0x003b8003 +.long 0x003b9003 +.long 0x003ba003 +.long 0x003bb003 +.long 0x003bc003 +.long 0x003bd003 +.long 0x003be003 +.long 0x003bf003 +.long 0x003c0003 +.long 0x003c1003 +.long 0x003c2003 +.long 0x003c3003 +.long 0x003c4003 +.long 0x003c5003 +.long 0x003c6003 +.long 0x003c7003 +.long 0x003c8003 +.long 0x003c9003 +.long 0x003ca003 +.long 0x003cb003 +.long 0x003cc003 +.long 0x003cd003 +.long 0x003ce003 +.long 0x003cf003 +.long 0x003d0003 +.long 0x003d1003 +.long 0x003d2003 +.long 0x003d3003 +.long 0x003d4003 +.long 0x003d5003 +.long 0x003d6003 +.long 0x003d7003 +.long 0x003d8003 +.long 0x003d9003 +.long 0x003da003 +.long 0x003db003 +.long 0x003dc003 +.long 0x003dd003 +.long 0x003de003 +.long 0x003df003 +.long 0x003e0003 +.long 0x003e1003 +.long 0x003e2003 +.long 0x003e3003 +.long 0x003e4003 +.long 0x003e5003 +.long 0x003e6003 +.long 0x003e7003 +.long 0x003e8003 +.long 0x003e9003 +.long 0x003ea003 +.long 0x003eb003 +.long 0x003ec003 +.long 0x003ed003 +.long 0x003ee003 +.long 0x003ef003 +.long 0x003f0003 +.long 0x003f1003 +.long 0x003f2003 +.long 0x003f3003 +.long 0x003f4003 +.long 0x003f5003 +.long 0x003f6003 +.long 0x003f7003 +.long 0x003f8003 +.long 0x003f9003 +.long 0x003fa003 +.long 0x003fb003 +.long 0x003fc003 +.long 0x003fd003 +.long 0x003fe003 +.long 0x003ff003 +.long 0x00400003 #pt2 +.long 0x00401003 +.long 0x00402003 +.long 0x00403003 +.long 0x00404003 +.long 0x00405003 +.long 0x00406003 +.long 0x00407003 +.long 0x00408003 +.long 0x00409003 +.long 0x0040a003 +.long 0x0040b003 +.long 0x0040c003 +.long 0x0040d003 +.long 0x0040e003 +.long 0x0040f003 +.long 0x00410003 +.long 0x00411003 +.long 0x00412003 +.long 0x00413003 +.long 0x00414003 +.long 0x00415003 +.long 0x00416003 +.long 0x00417003 +.long 0x00418003 +.long 0x00419003 +.long 0x0041a003 +.long 0x0041b003 +.long 0x0041c003 +.long 0x0041d003 +.long 0x0041e003 +.long 0x0041f003 +.long 0x00420003 +.long 0x00421003 +.long 0x00422003 +.long 0x00423003 +.long 0x00424003 +.long 0x00425003 +.long 0x00426003 +.long 0x00427003 +.long 0x00428003 +.long 0x00429003 +.long 0x0042a003 +.long 0x0042b003 +.long 0x0042c003 +.long 0x0042d003 +.long 0x0042e003 +.long 0x0042f003 +.long 0x00430003 +.long 0x00431003 +.long 0x00432003 +.long 0x00433003 +.long 0x00434003 +.long 0x00435003 +.long 0x00436003 +.long 0x00437003 +.long 0x00438003 +.long 0x00439003 +.long 0x0043a003 +.long 0x0043b003 +.long 0x0043c003 +.long 0x0043d003 +.long 0x0043e003 +.long 0x0043f003 +.long 0x00440003 +.long 0x00441003 +.long 0x00442003 +.long 0x00443003 +.long 0x00444003 +.long 0x00445003 +.long 0x00446003 +.long 0x00447003 +.long 0x00448003 +.long 0x00449003 +.long 0x0044a003 +.long 0x0044b003 +.long 0x0044c003 +.long 0x0044d003 +.long 0x0044e003 +.long 0x0044f003 +.long 0x00450003 +.long 0x00451003 +.long 0x00452003 +.long 0x00453003 +.long 0x00454003 +.long 0x00455003 +.long 0x00456003 +.long 0x00457003 +.long 0x00458003 +.long 0x00459003 +.long 0x0045a003 +.long 0x0045b003 +.long 0x0045c003 +.long 0x0045d003 +.long 0x0045e003 +.long 0x0045f003 +.long 0x00460003 +.long 0x00461003 +.long 0x00462003 +.long 0x00463003 +.long 0x00464003 +.long 0x00465003 +.long 0x00466003 +.long 0x00467003 +.long 0x00468003 +.long 0x00469003 +.long 0x0046a003 +.long 0x0046b003 +.long 0x0046c003 +.long 0x0046d003 +.long 0x0046e003 +.long 0x0046f003 +.long 0x00470003 +.long 0x00471003 +.long 0x00472003 +.long 0x00473003 +.long 0x00474003 +.long 0x00475003 +.long 0x00476003 +.long 0x00477003 +.long 0x00478003 +.long 0x00479003 +.long 0x0047a003 +.long 0x0047b003 +.long 0x0047c003 +.long 0x0047d003 +.long 0x0047e003 +.long 0x0047f003 +.long 0x00480003 +.long 0x00481003 +.long 0x00482003 +.long 0x00483003 +.long 0x00484003 +.long 0x00485003 +.long 0x00486003 +.long 0x00487003 +.long 0x00488003 +.long 0x00489003 +.long 0x0048a003 +.long 0x0048b003 +.long 0x0048c003 +.long 0x0048d003 +.long 0x0048e003 +.long 0x0048f003 +.long 0x00490003 +.long 0x00491003 +.long 0x00492003 +.long 0x00493003 +.long 0x00494003 +.long 0x00495003 +.long 0x00496003 +.long 0x00497003 +.long 0x00498003 +.long 0x00499003 +.long 0x0049a003 +.long 0x0049b003 +.long 0x0049c003 +.long 0x0049d003 +.long 0x0049e003 +.long 0x0049f003 +.long 0x004a0003 +.long 0x004a1003 +.long 0x004a2003 +.long 0x004a3003 +.long 0x004a4003 +.long 0x004a5003 +.long 0x004a6003 +.long 0x004a7003 +.long 0x004a8003 +.long 0x004a9003 +.long 0x004aa003 +.long 0x004ab003 +.long 0x004ac003 +.long 0x004ad003 +.long 0x004ae003 +.long 0x004af003 +.long 0x004b0003 +.long 0x004b1003 +.long 0x004b2003 +.long 0x004b3003 +.long 0x004b4003 +.long 0x004b5003 +.long 0x004b6003 +.long 0x004b7003 +.long 0x004b8003 +.long 0x004b9003 +.long 0x004ba003 +.long 0x004bb003 +.long 0x004bc003 +.long 0x004bd003 +.long 0x004be003 +.long 0x004bf003 +.long 0x004c0003 +.long 0x004c1003 +.long 0x004c2003 +.long 0x004c3003 +.long 0x004c4003 +.long 0x004c5003 +.long 0x004c6003 +.long 0x004c7003 +.long 0x004c8003 +.long 0x004c9003 +.long 0x004ca003 +.long 0x004cb003 +.long 0x004cc003 +.long 0x004cd003 +.long 0x004ce003 +.long 0x004cf003 +.long 0x004d0003 +.long 0x004d1003 +.long 0x004d2003 +.long 0x004d3003 +.long 0x004d4003 +.long 0x004d5003 +.long 0x004d6003 +.long 0x004d7003 +.long 0x004d8003 +.long 0x004d9003 +.long 0x004da003 +.long 0x004db003 +.long 0x004dc003 +.long 0x004dd003 +.long 0x004de003 +.long 0x004df003 +.long 0x004e0003 +.long 0x004e1003 +.long 0x004e2003 +.long 0x004e3003 +.long 0x004e4003 +.long 0x004e5003 +.long 0x004e6003 +.long 0x004e7003 +.long 0x004e8003 +.long 0x004e9003 +.long 0x004ea003 +.long 0x004eb003 +.long 0x004ec003 +.long 0x004ed003 +.long 0x004ee003 +.long 0x004ef003 +.long 0x004f0003 +.long 0x004f1003 +.long 0x004f2003 +.long 0x004f3003 +.long 0x004f4003 +.long 0x004f5003 +.long 0x004f6003 +.long 0x004f7003 +.long 0x004f8003 +.long 0x004f9003 +.long 0x004fa003 +.long 0x004fb003 +.long 0x004fc003 +.long 0x004fd003 +.long 0x004fe003 +.long 0x004ff003 +.long 0x00500003 +.long 0x00501003 +.long 0x00502003 +.long 0x00503003 +.long 0x00504003 +.long 0x00505003 +.long 0x00506003 +.long 0x00507003 +.long 0x00508003 +.long 0x00509003 +.long 0x0050a003 +.long 0x0050b003 +.long 0x0050c003 +.long 0x0050d003 +.long 0x0050e003 +.long 0x0050f003 +.long 0x00510003 +.long 0x00511003 +.long 0x00512003 +.long 0x00513003 +.long 0x00514003 +.long 0x00515003 +.long 0x00516003 +.long 0x00517003 +.long 0x00518003 +.long 0x00519003 +.long 0x0051a003 +.long 0x0051b003 +.long 0x0051c003 +.long 0x0051d003 +.long 0x0051e003 +.long 0x0051f003 +.long 0x00520003 +.long 0x00521003 +.long 0x00522003 +.long 0x00523003 +.long 0x00524003 +.long 0x00525003 +.long 0x00526003 +.long 0x00527003 +.long 0x00528003 +.long 0x00529003 +.long 0x0052a003 +.long 0x0052b003 +.long 0x0052c003 +.long 0x0052d003 +.long 0x0052e003 +.long 0x0052f003 +.long 0x00530003 +.long 0x00531003 +.long 0x00532003 +.long 0x00533003 +.long 0x00534003 +.long 0x00535003 +.long 0x00536003 +.long 0x00537003 +.long 0x00538003 +.long 0x00539003 +.long 0x0053a003 +.long 0x0053b003 +.long 0x0053c003 +.long 0x0053d003 +.long 0x0053e003 +.long 0x0053f003 +.long 0x00540003 +.long 0x00541003 +.long 0x00542003 +.long 0x00543003 +.long 0x00544003 +.long 0x00545003 +.long 0x00546003 +.long 0x00547003 +.long 0x00548003 +.long 0x00549003 +.long 0x0054a003 +.long 0x0054b003 +.long 0x0054c003 +.long 0x0054d003 +.long 0x0054e003 +.long 0x0054f003 +.long 0x00550003 +.long 0x00551003 +.long 0x00552003 +.long 0x00553003 +.long 0x00554003 +.long 0x00555003 +.long 0x00556003 +.long 0x00557003 +.long 0x00558003 +.long 0x00559003 +.long 0x0055a003 +.long 0x0055b003 +.long 0x0055c003 +.long 0x0055d003 +.long 0x0055e003 +.long 0x0055f003 +.long 0x00560003 +.long 0x00561003 +.long 0x00562003 +.long 0x00563003 +.long 0x00564003 +.long 0x00565003 +.long 0x00566003 +.long 0x00567003 +.long 0x00568003 +.long 0x00569003 +.long 0x0056a003 +.long 0x0056b003 +.long 0x0056c003 +.long 0x0056d003 +.long 0x0056e003 +.long 0x0056f003 +.long 0x00570003 +.long 0x00571003 +.long 0x00572003 +.long 0x00573003 +.long 0x00574003 +.long 0x00575003 +.long 0x00576003 +.long 0x00577003 +.long 0x00578003 +.long 0x00579003 +.long 0x0057a003 +.long 0x0057b003 +.long 0x0057c003 +.long 0x0057d003 +.long 0x0057e003 +.long 0x0057f003 +.long 0x00580003 +.long 0x00581003 +.long 0x00582003 +.long 0x00583003 +.long 0x00584003 +.long 0x00585003 +.long 0x00586003 +.long 0x00587003 +.long 0x00588003 +.long 0x00589003 +.long 0x0058a003 +.long 0x0058b003 +.long 0x0058c003 +.long 0x0058d003 +.long 0x0058e003 +.long 0x0058f003 +.long 0x00590003 +.long 0x00591003 +.long 0x00592003 +.long 0x00593003 +.long 0x00594003 +.long 0x00595003 +.long 0x00596003 +.long 0x00597003 +.long 0x00598003 +.long 0x00599003 +.long 0x0059a003 +.long 0x0059b003 +.long 0x0059c003 +.long 0x0059d003 +.long 0x0059e003 +.long 0x0059f003 +.long 0x005a0003 +.long 0x005a1003 +.long 0x005a2003 +.long 0x005a3003 +.long 0x005a4003 +.long 0x005a5003 +.long 0x005a6003 +.long 0x005a7003 +.long 0x005a8003 +.long 0x005a9003 +.long 0x005aa003 +.long 0x005ab003 +.long 0x005ac003 +.long 0x005ad003 +.long 0x005ae003 +.long 0x005af003 +.long 0x005b0003 +.long 0x005b1003 +.long 0x005b2003 +.long 0x005b3003 +.long 0x005b4003 +.long 0x005b5003 +.long 0x005b6003 +.long 0x005b7003 +.long 0x005b8003 +.long 0x005b9003 +.long 0x005ba003 +.long 0x005bb003 +.long 0x005bc003 +.long 0x005bd003 +.long 0x005be003 +.long 0x005bf003 +.long 0x005c0003 +.long 0x005c1003 +.long 0x005c2003 +.long 0x005c3003 +.long 0x005c4003 +.long 0x005c5003 +.long 0x005c6003 +.long 0x005c7003 +.long 0x005c8003 +.long 0x005c9003 +.long 0x005ca003 +.long 0x005cb003 +.long 0x005cc003 +.long 0x005cd003 +.long 0x005ce003 +.long 0x005cf003 +.long 0x005d0003 +.long 0x005d1003 +.long 0x005d2003 +.long 0x005d3003 +.long 0x005d4003 +.long 0x005d5003 +.long 0x005d6003 +.long 0x005d7003 +.long 0x005d8003 +.long 0x005d9003 +.long 0x005da003 +.long 0x005db003 +.long 0x005dc003 +.long 0x005dd003 +.long 0x005de003 +.long 0x005df003 +.long 0x005e0003 +.long 0x005e1003 +.long 0x005e2003 +.long 0x005e3003 +.long 0x005e4003 +.long 0x005e5003 +.long 0x005e6003 +.long 0x005e7003 +.long 0x005e8003 +.long 0x005e9003 +.long 0x005ea003 +.long 0x005eb003 +.long 0x005ec003 +.long 0x005ed003 +.long 0x005ee003 +.long 0x005ef003 +.long 0x005f0003 +.long 0x005f1003 +.long 0x005f2003 +.long 0x005f3003 +.long 0x005f4003 +.long 0x005f5003 +.long 0x005f6003 +.long 0x005f7003 +.long 0x005f8003 +.long 0x005f9003 +.long 0x005fa003 +.long 0x005fb003 +.long 0x005fc003 +.long 0x005fd003 +.long 0x005fe003 +.long 0x005ff003 +.long 0x00600003 +.long 0x00601003 +.long 0x00602003 +.long 0x00603003 +.long 0x00604003 +.long 0x00605003 +.long 0x00606003 +.long 0x00607003 +.long 0x00608003 +.long 0x00609003 +.long 0x0060a003 +.long 0x0060b003 +.long 0x0060c003 +.long 0x0060d003 +.long 0x0060e003 +.long 0x0060f003 +.long 0x00610003 +.long 0x00611003 +.long 0x00612003 +.long 0x00613003 +.long 0x00614003 +.long 0x00615003 +.long 0x00616003 +.long 0x00617003 +.long 0x00618003 +.long 0x00619003 +.long 0x0061a003 +.long 0x0061b003 +.long 0x0061c003 +.long 0x0061d003 +.long 0x0061e003 +.long 0x0061f003 +.long 0x00620003 +.long 0x00621003 +.long 0x00622003 +.long 0x00623003 +.long 0x00624003 +.long 0x00625003 +.long 0x00626003 +.long 0x00627003 +.long 0x00628003 +.long 0x00629003 +.long 0x0062a003 +.long 0x0062b003 +.long 0x0062c003 +.long 0x0062d003 +.long 0x0062e003 +.long 0x0062f003 +.long 0x00630003 +.long 0x00631003 +.long 0x00632003 +.long 0x00633003 +.long 0x00634003 +.long 0x00635003 +.long 0x00636003 +.long 0x00637003 +.long 0x00638003 +.long 0x00639003 +.long 0x0063a003 +.long 0x0063b003 +.long 0x0063c003 +.long 0x0063d003 +.long 0x0063e003 +.long 0x0063f003 +.long 0x00640003 +.long 0x00641003 +.long 0x00642003 +.long 0x00643003 +.long 0x00644003 +.long 0x00645003 +.long 0x00646003 +.long 0x00647003 +.long 0x00648003 +.long 0x00649003 +.long 0x0064a003 +.long 0x0064b003 +.long 0x0064c003 +.long 0x0064d003 +.long 0x0064e003 +.long 0x0064f003 +.long 0x00650003 +.long 0x00651003 +.long 0x00652003 +.long 0x00653003 +.long 0x00654003 +.long 0x00655003 +.long 0x00656003 +.long 0x00657003 +.long 0x00658003 +.long 0x00659003 +.long 0x0065a003 +.long 0x0065b003 +.long 0x0065c003 +.long 0x0065d003 +.long 0x0065e003 +.long 0x0065f003 +.long 0x00660003 +.long 0x00661003 +.long 0x00662003 +.long 0x00663003 +.long 0x00664003 +.long 0x00665003 +.long 0x00666003 +.long 0x00667003 +.long 0x00668003 +.long 0x00669003 +.long 0x0066a003 +.long 0x0066b003 +.long 0x0066c003 +.long 0x0066d003 +.long 0x0066e003 +.long 0x0066f003 +.long 0x00670003 +.long 0x00671003 +.long 0x00672003 +.long 0x00673003 +.long 0x00674003 +.long 0x00675003 +.long 0x00676003 +.long 0x00677003 +.long 0x00678003 +.long 0x00679003 +.long 0x0067a003 +.long 0x0067b003 +.long 0x0067c003 +.long 0x0067d003 +.long 0x0067e003 +.long 0x0067f003 +.long 0x00680003 +.long 0x00681003 +.long 0x00682003 +.long 0x00683003 +.long 0x00684003 +.long 0x00685003 +.long 0x00686003 +.long 0x00687003 +.long 0x00688003 +.long 0x00689003 +.long 0x0068a003 +.long 0x0068b003 +.long 0x0068c003 +.long 0x0068d003 +.long 0x0068e003 +.long 0x0068f003 +.long 0x00690003 +.long 0x00691003 +.long 0x00692003 +.long 0x00693003 +.long 0x00694003 +.long 0x00695003 +.long 0x00696003 +.long 0x00697003 +.long 0x00698003 +.long 0x00699003 +.long 0x0069a003 +.long 0x0069b003 +.long 0x0069c003 +.long 0x0069d003 +.long 0x0069e003 +.long 0x0069f003 +.long 0x006a0003 +.long 0x006a1003 +.long 0x006a2003 +.long 0x006a3003 +.long 0x006a4003 +.long 0x006a5003 +.long 0x006a6003 +.long 0x006a7003 +.long 0x006a8003 +.long 0x006a9003 +.long 0x006aa003 +.long 0x006ab003 +.long 0x006ac003 +.long 0x006ad003 +.long 0x006ae003 +.long 0x006af003 +.long 0x006b0003 +.long 0x006b1003 +.long 0x006b2003 +.long 0x006b3003 +.long 0x006b4003 +.long 0x006b5003 +.long 0x006b6003 +.long 0x006b7003 +.long 0x006b8003 +.long 0x006b9003 +.long 0x006ba003 +.long 0x006bb003 +.long 0x006bc003 +.long 0x006bd003 +.long 0x006be003 +.long 0x006bf003 +.long 0x006c0003 +.long 0x006c1003 +.long 0x006c2003 +.long 0x006c3003 +.long 0x006c4003 +.long 0x006c5003 +.long 0x006c6003 +.long 0x006c7003 +.long 0x006c8003 +.long 0x006c9003 +.long 0x006ca003 +.long 0x006cb003 +.long 0x006cc003 +.long 0x006cd003 +.long 0x006ce003 +.long 0x006cf003 +.long 0x006d0003 +.long 0x006d1003 +.long 0x006d2003 +.long 0x006d3003 +.long 0x006d4003 +.long 0x006d5003 +.long 0x006d6003 +.long 0x006d7003 +.long 0x006d8003 +.long 0x006d9003 +.long 0x006da003 +.long 0x006db003 +.long 0x006dc003 +.long 0x006dd003 +.long 0x006de003 +.long 0x006df003 +.long 0x006e0003 +.long 0x006e1003 +.long 0x006e2003 +.long 0x006e3003 +.long 0x006e4003 +.long 0x006e5003 +.long 0x006e6003 +.long 0x006e7003 +.long 0x006e8003 +.long 0x006e9003 +.long 0x006ea003 +.long 0x006eb003 +.long 0x006ec003 +.long 0x006ed003 +.long 0x006ee003 +.long 0x006ef003 +.long 0x006f0003 +.long 0x006f1003 +.long 0x006f2003 +.long 0x006f3003 +.long 0x006f4003 +.long 0x006f5003 +.long 0x006f6003 +.long 0x006f7003 +.long 0x006f8003 +.long 0x006f9003 +.long 0x006fa003 +.long 0x006fb003 +.long 0x006fc003 +.long 0x006fd003 +.long 0x006fe003 +.long 0x006ff003 +.long 0x00700003 +.long 0x00701003 +.long 0x00702003 +.long 0x00703003 +.long 0x00704003 +.long 0x00705003 +.long 0x00706003 +.long 0x00707003 +.long 0x00708003 +.long 0x00709003 +.long 0x0070a003 +.long 0x0070b003 +.long 0x0070c003 +.long 0x0070d003 +.long 0x0070e003 +.long 0x0070f003 +.long 0x00710003 +.long 0x00711003 +.long 0x00712003 +.long 0x00713003 +.long 0x00714003 +.long 0x00715003 +.long 0x00716003 +.long 0x00717003 +.long 0x00718003 +.long 0x00719003 +.long 0x0071a003 +.long 0x0071b003 +.long 0x0071c003 +.long 0x0071d003 +.long 0x0071e003 +.long 0x0071f003 +.long 0x00720003 +.long 0x00721003 +.long 0x00722003 +.long 0x00723003 +.long 0x00724003 +.long 0x00725003 +.long 0x00726003 +.long 0x00727003 +.long 0x00728003 +.long 0x00729003 +.long 0x0072a003 +.long 0x0072b003 +.long 0x0072c003 +.long 0x0072d003 +.long 0x0072e003 +.long 0x0072f003 +.long 0x00730003 +.long 0x00731003 +.long 0x00732003 +.long 0x00733003 +.long 0x00734003 +.long 0x00735003 +.long 0x00736003 +.long 0x00737003 +.long 0x00738003 +.long 0x00739003 +.long 0x0073a003 +.long 0x0073b003 +.long 0x0073c003 +.long 0x0073d003 +.long 0x0073e003 +.long 0x0073f003 +.long 0x00740003 +.long 0x00741003 +.long 0x00742003 +.long 0x00743003 +.long 0x00744003 +.long 0x00745003 +.long 0x00746003 +.long 0x00747003 +.long 0x00748003 +.long 0x00749003 +.long 0x0074a003 +.long 0x0074b003 +.long 0x0074c003 +.long 0x0074d003 +.long 0x0074e003 +.long 0x0074f003 +.long 0x00750003 +.long 0x00751003 +.long 0x00752003 +.long 0x00753003 +.long 0x00754003 +.long 0x00755003 +.long 0x00756003 +.long 0x00757003 +.long 0x00758003 +.long 0x00759003 +.long 0x0075a003 +.long 0x0075b003 +.long 0x0075c003 +.long 0x0075d003 +.long 0x0075e003 +.long 0x0075f003 +.long 0x00760003 +.long 0x00761003 +.long 0x00762003 +.long 0x00763003 +.long 0x00764003 +.long 0x00765003 +.long 0x00766003 +.long 0x00767003 +.long 0x00768003 +.long 0x00769003 +.long 0x0076a003 +.long 0x0076b003 +.long 0x0076c003 +.long 0x0076d003 +.long 0x0076e003 +.long 0x0076f003 +.long 0x00770003 +.long 0x00771003 +.long 0x00772003 +.long 0x00773003 +.long 0x00774003 +.long 0x00775003 +.long 0x00776003 +.long 0x00777003 +.long 0x00778003 +.long 0x00779003 +.long 0x0077a003 +.long 0x0077b003 +.long 0x0077c003 +.long 0x0077d003 +.long 0x0077e003 +.long 0x0077f003 +.long 0x00780003 +.long 0x00781003 +.long 0x00782003 +.long 0x00783003 +.long 0x00784003 +.long 0x00785003 +.long 0x00786003 +.long 0x00787003 +.long 0x00788003 +.long 0x00789003 +.long 0x0078a003 +.long 0x0078b003 +.long 0x0078c003 +.long 0x0078d003 +.long 0x0078e003 +.long 0x0078f003 +.long 0x00790003 +.long 0x00791003 +.long 0x00792003 +.long 0x00793003 +.long 0x00794003 +.long 0x00795003 +.long 0x00796003 +.long 0x00797003 +.long 0x00798003 +.long 0x00799003 +.long 0x0079a003 +.long 0x0079b003 +.long 0x0079c003 +.long 0x0079d003 +.long 0x0079e003 +.long 0x0079f003 +.long 0x007a0003 +.long 0x007a1003 +.long 0x007a2003 +.long 0x007a3003 +.long 0x007a4003 +.long 0x007a5003 +.long 0x007a6003 +.long 0x007a7003 +.long 0x007a8003 +.long 0x007a9003 +.long 0x007aa003 +.long 0x007ab003 +.long 0x007ac003 +.long 0x007ad003 +.long 0x007ae003 +.long 0x007af003 +.long 0x007b0003 +.long 0x007b1003 +.long 0x007b2003 +.long 0x007b3003 +.long 0x007b4003 +.long 0x007b5003 +.long 0x007b6003 +.long 0x007b7003 +.long 0x007b8003 +.long 0x007b9003 +.long 0x007ba003 +.long 0x007bb003 +.long 0x007bc003 +.long 0x007bd003 +.long 0x007be003 +.long 0x007bf003 +.long 0x007c0003 +.long 0x007c1003 +.long 0x007c2003 +.long 0x007c3003 +.long 0x007c4003 +.long 0x007c5003 +.long 0x007c6003 +.long 0x007c7003 +.long 0x007c8003 +.long 0x007c9003 +.long 0x007ca003 +.long 0x007cb003 +.long 0x007cc003 +.long 0x007cd003 +.long 0x007ce003 +.long 0x007cf003 +.long 0x007d0003 +.long 0x007d1003 +.long 0x007d2003 +.long 0x007d3003 +.long 0x007d4003 +.long 0x007d5003 +.long 0x007d6003 +.long 0x007d7003 +.long 0x007d8003 +.long 0x007d9003 +.long 0x007da003 +.long 0x007db003 +.long 0x007dc003 +.long 0x007dd003 +.long 0x007de003 +.long 0x007df003 +.long 0x007e0003 +.long 0x007e1003 +.long 0x007e2003 +.long 0x007e3003 +.long 0x007e4003 +.long 0x007e5003 +.long 0x007e6003 +.long 0x007e7003 +.long 0x007e8003 +.long 0x007e9003 +.long 0x007ea003 +.long 0x007eb003 +.long 0x007ec003 +.long 0x007ed003 +.long 0x007ee003 +.long 0x007ef003 +.long 0x007f0003 +.long 0x007f1003 +.long 0x007f2003 +.long 0x007f3003 +.long 0x007f4003 +.long 0x007f5003 +.long 0x007f6003 +.long 0x007f7003 +.long 0x007f8003 +.long 0x007f9003 +.long 0x007fa003 +.long 0x007fb003 +.long 0x007fc003 +.long 0x007fd003 +.long 0x007fe003 +.long 0x007ff003 +.long 0x00800003 # pt3 +.long 0x00801003 +.long 0x00802003 +.long 0x00803003 +.long 0x00804003 +.long 0x00805003 +.long 0x00806003 +.long 0x00807003 +.long 0x00808003 +.long 0x00809003 +.long 0x0080a003 +.long 0x0080b003 +.long 0x0080c003 +.long 0x0080d003 +.long 0x0080e003 +.long 0x0080f003 +.long 0x00810003 +.long 0x00811003 +.long 0x00812003 +.long 0x00813003 +.long 0x00814003 +.long 0x00815003 +.long 0x00816003 +.long 0x00817003 +.long 0x00818003 +.long 0x00819003 +.long 0x0081a003 +.long 0x0081b003 +.long 0x0081c003 +.long 0x0081d003 +.long 0x0081e003 +.long 0x0081f003 +.long 0x00820003 +.long 0x00821003 +.long 0x00822003 +.long 0x00823003 +.long 0x00824003 +.long 0x00825003 +.long 0x00826003 +.long 0x00827003 +.long 0x00828003 +.long 0x00829003 +.long 0x0082a003 +.long 0x0082b003 +.long 0x0082c003 +.long 0x0082d003 +.long 0x0082e003 +.long 0x0082f003 +.long 0x00830003 +.long 0x00831003 +.long 0x00832003 +.long 0x00833003 +.long 0x00834003 +.long 0x00835003 +.long 0x00836003 +.long 0x00837003 +.long 0x00838003 +.long 0x00839003 +.long 0x0083a003 +.long 0x0083b003 +.long 0x0083c003 +.long 0x0083d003 +.long 0x0083e003 +.long 0x0083f003 +.long 0x00840003 +.long 0x00841003 +.long 0x00842003 +.long 0x00843003 +.long 0x00844003 +.long 0x00845003 +.long 0x00846003 +.long 0x00847003 +.long 0x00848003 +.long 0x00849003 +.long 0x0084a003 +.long 0x0084b003 +.long 0x0084c003 +.long 0x0084d003 +.long 0x0084e003 +.long 0x0084f003 +.long 0x00850003 +.long 0x00851003 +.long 0x00852003 +.long 0x00853003 +.long 0x00854003 +.long 0x00855003 +.long 0x00856003 +.long 0x00857003 +.long 0x00858003 +.long 0x00859003 +.long 0x0085a003 +.long 0x0085b003 +.long 0x0085c003 +.long 0x0085d003 +.long 0x0085e003 +.long 0x0085f003 +.long 0x00860003 +.long 0x00861003 +.long 0x00862003 +.long 0x00863003 +.long 0x00864003 +.long 0x00865003 +.long 0x00866003 +.long 0x00867003 +.long 0x00868003 +.long 0x00869003 +.long 0x0086a003 +.long 0x0086b003 +.long 0x0086c003 +.long 0x0086d003 +.long 0x0086e003 +.long 0x0086f003 +.long 0x00870003 +.long 0x00871003 +.long 0x00872003 +.long 0x00873003 +.long 0x00874003 +.long 0x00875003 +.long 0x00876003 +.long 0x00877003 +.long 0x00878003 +.long 0x00879003 +.long 0x0087a003 +.long 0x0087b003 +.long 0x0087c003 +.long 0x0087d003 +.long 0x0087e003 +.long 0x0087f003 +.long 0x00880003 +.long 0x00881003 +.long 0x00882003 +.long 0x00883003 +.long 0x00884003 +.long 0x00885003 +.long 0x00886003 +.long 0x00887003 +.long 0x00888003 +.long 0x00889003 +.long 0x0088a003 +.long 0x0088b003 +.long 0x0088c003 +.long 0x0088d003 +.long 0x0088e003 +.long 0x0088f003 +.long 0x00890003 +.long 0x00891003 +.long 0x00892003 +.long 0x00893003 +.long 0x00894003 +.long 0x00895003 +.long 0x00896003 +.long 0x00897003 +.long 0x00898003 +.long 0x00899003 +.long 0x0089a003 +.long 0x0089b003 +.long 0x0089c003 +.long 0x0089d003 +.long 0x0089e003 +.long 0x0089f003 +.long 0x008a0003 +.long 0x008a1003 +.long 0x008a2003 +.long 0x008a3003 +.long 0x008a4003 +.long 0x008a5003 +.long 0x008a6003 +.long 0x008a7003 +.long 0x008a8003 +.long 0x008a9003 +.long 0x008aa003 +.long 0x008ab003 +.long 0x008ac003 +.long 0x008ad003 +.long 0x008ae003 +.long 0x008af003 +.long 0x008b0003 +.long 0x008b1003 +.long 0x008b2003 +.long 0x008b3003 +.long 0x008b4003 +.long 0x008b5003 +.long 0x008b6003 +.long 0x008b7003 +.long 0x008b8003 +.long 0x008b9003 +.long 0x008ba003 +.long 0x008bb003 +.long 0x008bc003 +.long 0x008bd003 +.long 0x008be003 +.long 0x008bf003 +.long 0x008c0003 +.long 0x008c1003 +.long 0x008c2003 +.long 0x008c3003 +.long 0x008c4003 +.long 0x008c5003 +.long 0x008c6003 +.long 0x008c7003 +.long 0x008c8003 +.long 0x008c9003 +.long 0x008ca003 +.long 0x008cb003 +.long 0x008cc003 +.long 0x008cd003 +.long 0x008ce003 +.long 0x008cf003 +.long 0x008d0003 +.long 0x008d1003 +.long 0x008d2003 +.long 0x008d3003 +.long 0x008d4003 +.long 0x008d5003 +.long 0x008d6003 +.long 0x008d7003 +.long 0x008d8003 +.long 0x008d9003 +.long 0x008da003 +.long 0x008db003 +.long 0x008dc003 +.long 0x008dd003 +.long 0x008de003 +.long 0x008df003 +.long 0x008e0003 +.long 0x008e1003 +.long 0x008e2003 +.long 0x008e3003 +.long 0x008e4003 +.long 0x008e5003 +.long 0x008e6003 +.long 0x008e7003 +.long 0x008e8003 +.long 0x008e9003 +.long 0x008ea003 +.long 0x008eb003 +.long 0x008ec003 +.long 0x008ed003 +.long 0x008ee003 +.long 0x008ef003 +.long 0x008f0003 +.long 0x008f1003 +.long 0x008f2003 +.long 0x008f3003 +.long 0x008f4003 +.long 0x008f5003 +.long 0x008f6003 +.long 0x008f7003 +.long 0x008f8003 +.long 0x008f9003 +.long 0x008fa003 +.long 0x008fb003 +.long 0x008fc003 +.long 0x008fd003 +.long 0x008fe003 +.long 0x008ff003 +.long 0x00900003 +.long 0x00901003 +.long 0x00902003 +.long 0x00903003 +.long 0x00904003 +.long 0x00905003 +.long 0x00906003 +.long 0x00907003 +.long 0x00908003 +.long 0x00909003 +.long 0x0090a003 +.long 0x0090b003 +.long 0x0090c003 +.long 0x0090d003 +.long 0x0090e003 +.long 0x0090f003 +.long 0x00910003 +.long 0x00911003 +.long 0x00912003 +.long 0x00913003 +.long 0x00914003 +.long 0x00915003 +.long 0x00916003 +.long 0x00917003 +.long 0x00918003 +.long 0x00919003 +.long 0x0091a003 +.long 0x0091b003 +.long 0x0091c003 +.long 0x0091d003 +.long 0x0091e003 +.long 0x0091f003 +.long 0x00920003 +.long 0x00921003 +.long 0x00922003 +.long 0x00923003 +.long 0x00924003 +.long 0x00925003 +.long 0x00926003 +.long 0x00927003 +.long 0x00928003 +.long 0x00929003 +.long 0x0092a003 +.long 0x0092b003 +.long 0x0092c003 +.long 0x0092d003 +.long 0x0092e003 +.long 0x0092f003 +.long 0x00930003 +.long 0x00931003 +.long 0x00932003 +.long 0x00933003 +.long 0x00934003 +.long 0x00935003 +.long 0x00936003 +.long 0x00937003 +.long 0x00938003 +.long 0x00939003 +.long 0x0093a003 +.long 0x0093b003 +.long 0x0093c003 +.long 0x0093d003 +.long 0x0093e003 +.long 0x0093f003 +.long 0x00940003 +.long 0x00941003 +.long 0x00942003 +.long 0x00943003 +.long 0x00944003 +.long 0x00945003 +.long 0x00946003 +.long 0x00947003 +.long 0x00948003 +.long 0x00949003 +.long 0x0094a003 +.long 0x0094b003 +.long 0x0094c003 +.long 0x0094d003 +.long 0x0094e003 +.long 0x0094f003 +.long 0x00950003 +.long 0x00951003 +.long 0x00952003 +.long 0x00953003 +.long 0x00954003 +.long 0x00955003 +.long 0x00956003 +.long 0x00957003 +.long 0x00958003 +.long 0x00959003 +.long 0x0095a003 +.long 0x0095b003 +.long 0x0095c003 +.long 0x0095d003 +.long 0x0095e003 +.long 0x0095f003 +.long 0x00960003 +.long 0x00961003 +.long 0x00962003 +.long 0x00963003 +.long 0x00964003 +.long 0x00965003 +.long 0x00966003 +.long 0x00967003 +.long 0x00968003 +.long 0x00969003 +.long 0x0096a003 +.long 0x0096b003 +.long 0x0096c003 +.long 0x0096d003 +.long 0x0096e003 +.long 0x0096f003 +.long 0x00970003 +.long 0x00971003 +.long 0x00972003 +.long 0x00973003 +.long 0x00974003 +.long 0x00975003 +.long 0x00976003 +.long 0x00977003 +.long 0x00978003 +.long 0x00979003 +.long 0x0097a003 +.long 0x0097b003 +.long 0x0097c003 +.long 0x0097d003 +.long 0x0097e003 +.long 0x0097f003 +.long 0x00980003 +.long 0x00981003 +.long 0x00982003 +.long 0x00983003 +.long 0x00984003 +.long 0x00985003 +.long 0x00986003 +.long 0x00987003 +.long 0x00988003 +.long 0x00989003 +.long 0x0098a003 +.long 0x0098b003 +.long 0x0098c003 +.long 0x0098d003 +.long 0x0098e003 +.long 0x0098f003 +.long 0x00990003 +.long 0x00991003 +.long 0x00992003 +.long 0x00993003 +.long 0x00994003 +.long 0x00995003 +.long 0x00996003 +.long 0x00997003 +.long 0x00998003 +.long 0x00999003 +.long 0x0099a003 +.long 0x0099b003 +.long 0x0099c003 +.long 0x0099d003 +.long 0x0099e003 +.long 0x0099f003 +.long 0x009a0003 +.long 0x009a1003 +.long 0x009a2003 +.long 0x009a3003 +.long 0x009a4003 +.long 0x009a5003 +.long 0x009a6003 +.long 0x009a7003 +.long 0x009a8003 +.long 0x009a9003 +.long 0x009aa003 +.long 0x009ab003 +.long 0x009ac003 +.long 0x009ad003 +.long 0x009ae003 +.long 0x009af003 +.long 0x009b0003 +.long 0x009b1003 +.long 0x009b2003 +.long 0x009b3003 +.long 0x009b4003 +.long 0x009b5003 +.long 0x009b6003 +.long 0x009b7003 +.long 0x009b8003 +.long 0x009b9003 +.long 0x009ba003 +.long 0x009bb003 +.long 0x009bc003 +.long 0x009bd003 +.long 0x009be003 +.long 0x009bf003 +.long 0x009c0003 +.long 0x009c1003 +.long 0x009c2003 +.long 0x009c3003 +.long 0x009c4003 +.long 0x009c5003 +.long 0x009c6003 +.long 0x009c7003 +.long 0x009c8003 +.long 0x009c9003 +.long 0x009ca003 +.long 0x009cb003 +.long 0x009cc003 +.long 0x009cd003 +.long 0x009ce003 +.long 0x009cf003 +.long 0x009d0003 +.long 0x009d1003 +.long 0x009d2003 +.long 0x009d3003 +.long 0x009d4003 +.long 0x009d5003 +.long 0x009d6003 +.long 0x009d7003 +.long 0x009d8003 +.long 0x009d9003 +.long 0x009da003 +.long 0x009db003 +.long 0x009dc003 +.long 0x009dd003 +.long 0x009de003 +.long 0x009df003 +.long 0x009e0003 +.long 0x009e1003 +.long 0x009e2003 +.long 0x009e3003 +.long 0x009e4003 +.long 0x009e5003 +.long 0x009e6003 +.long 0x009e7003 +.long 0x009e8003 +.long 0x009e9003 +.long 0x009ea003 +.long 0x009eb003 +.long 0x009ec003 +.long 0x009ed003 +.long 0x009ee003 +.long 0x009ef003 +.long 0x009f0003 +.long 0x009f1003 +.long 0x009f2003 +.long 0x009f3003 +.long 0x009f4003 +.long 0x009f5003 +.long 0x009f6003 +.long 0x009f7003 +.long 0x009f8003 +.long 0x009f9003 +.long 0x009fa003 +.long 0x009fb003 +.long 0x009fc003 +.long 0x009fd003 +.long 0x009fe003 +.long 0x009ff003 +.long 0x00a00003 +.long 0x00a01003 +.long 0x00a02003 +.long 0x00a03003 +.long 0x00a04003 +.long 0x00a05003 +.long 0x00a06003 +.long 0x00a07003 +.long 0x00a08003 +.long 0x00a09003 +.long 0x00a0a003 +.long 0x00a0b003 +.long 0x00a0c003 +.long 0x00a0d003 +.long 0x00a0e003 +.long 0x00a0f003 +.long 0x00a10003 +.long 0x00a11003 +.long 0x00a12003 +.long 0x00a13003 +.long 0x00a14003 +.long 0x00a15003 +.long 0x00a16003 +.long 0x00a17003 +.long 0x00a18003 +.long 0x00a19003 +.long 0x00a1a003 +.long 0x00a1b003 +.long 0x00a1c003 +.long 0x00a1d003 +.long 0x00a1e003 +.long 0x00a1f003 +.long 0x00a20003 +.long 0x00a21003 +.long 0x00a22003 +.long 0x00a23003 +.long 0x00a24003 +.long 0x00a25003 +.long 0x00a26003 +.long 0x00a27003 +.long 0x00a28003 +.long 0x00a29003 +.long 0x00a2a003 +.long 0x00a2b003 +.long 0x00a2c003 +.long 0x00a2d003 +.long 0x00a2e003 +.long 0x00a2f003 +.long 0x00a30003 +.long 0x00a31003 +.long 0x00a32003 +.long 0x00a33003 +.long 0x00a34003 +.long 0x00a35003 +.long 0x00a36003 +.long 0x00a37003 +.long 0x00a38003 +.long 0x00a39003 +.long 0x00a3a003 +.long 0x00a3b003 +.long 0x00a3c003 +.long 0x00a3d003 +.long 0x00a3e003 +.long 0x00a3f003 +.long 0x00a40003 +.long 0x00a41003 +.long 0x00a42003 +.long 0x00a43003 +.long 0x00a44003 +.long 0x00a45003 +.long 0x00a46003 +.long 0x00a47003 +.long 0x00a48003 +.long 0x00a49003 +.long 0x00a4a003 +.long 0x00a4b003 +.long 0x00a4c003 +.long 0x00a4d003 +.long 0x00a4e003 +.long 0x00a4f003 +.long 0x00a50003 +.long 0x00a51003 +.long 0x00a52003 +.long 0x00a53003 +.long 0x00a54003 +.long 0x00a55003 +.long 0x00a56003 +.long 0x00a57003 +.long 0x00a58003 +.long 0x00a59003 +.long 0x00a5a003 +.long 0x00a5b003 +.long 0x00a5c003 +.long 0x00a5d003 +.long 0x00a5e003 +.long 0x00a5f003 +.long 0x00a60003 +.long 0x00a61003 +.long 0x00a62003 +.long 0x00a63003 +.long 0x00a64003 +.long 0x00a65003 +.long 0x00a66003 +.long 0x00a67003 +.long 0x00a68003 +.long 0x00a69003 +.long 0x00a6a003 +.long 0x00a6b003 +.long 0x00a6c003 +.long 0x00a6d003 +.long 0x00a6e003 +.long 0x00a6f003 +.long 0x00a70003 +.long 0x00a71003 +.long 0x00a72003 +.long 0x00a73003 +.long 0x00a74003 +.long 0x00a75003 +.long 0x00a76003 +.long 0x00a77003 +.long 0x00a78003 +.long 0x00a79003 +.long 0x00a7a003 +.long 0x00a7b003 +.long 0x00a7c003 +.long 0x00a7d003 +.long 0x00a7e003 +.long 0x00a7f003 +.long 0x00a80003 +.long 0x00a81003 +.long 0x00a82003 +.long 0x00a83003 +.long 0x00a84003 +.long 0x00a85003 +.long 0x00a86003 +.long 0x00a87003 +.long 0x00a88003 +.long 0x00a89003 +.long 0x00a8a003 +.long 0x00a8b003 +.long 0x00a8c003 +.long 0x00a8d003 +.long 0x00a8e003 +.long 0x00a8f003 +.long 0x00a90003 +.long 0x00a91003 +.long 0x00a92003 +.long 0x00a93003 +.long 0x00a94003 +.long 0x00a95003 +.long 0x00a96003 +.long 0x00a97003 +.long 0x00a98003 +.long 0x00a99003 +.long 0x00a9a003 +.long 0x00a9b003 +.long 0x00a9c003 +.long 0x00a9d003 +.long 0x00a9e003 +.long 0x00a9f003 +.long 0x00aa0003 +.long 0x00aa1003 +.long 0x00aa2003 +.long 0x00aa3003 +.long 0x00aa4003 +.long 0x00aa5003 +.long 0x00aa6003 +.long 0x00aa7003 +.long 0x00aa8003 +.long 0x00aa9003 +.long 0x00aaa003 +.long 0x00aab003 +.long 0x00aac003 +.long 0x00aad003 +.long 0x00aae003 +.long 0x00aaf003 +.long 0x00ab0003 +.long 0x00ab1003 +.long 0x00ab2003 +.long 0x00ab3003 +.long 0x00ab4003 +.long 0x00ab5003 +.long 0x00ab6003 +.long 0x00ab7003 +.long 0x00ab8003 +.long 0x00ab9003 +.long 0x00aba003 +.long 0x00abb003 +.long 0x00abc003 +.long 0x00abd003 +.long 0x00abe003 +.long 0x00abf003 +.long 0x00ac0003 +.long 0x00ac1003 +.long 0x00ac2003 +.long 0x00ac3003 +.long 0x00ac4003 +.long 0x00ac5003 +.long 0x00ac6003 +.long 0x00ac7003 +.long 0x00ac8003 +.long 0x00ac9003 +.long 0x00aca003 +.long 0x00acb003 +.long 0x00acc003 +.long 0x00acd003 +.long 0x00ace003 +.long 0x00acf003 +.long 0x00ad0003 +.long 0x00ad1003 +.long 0x00ad2003 +.long 0x00ad3003 +.long 0x00ad4003 +.long 0x00ad5003 +.long 0x00ad6003 +.long 0x00ad7003 +.long 0x00ad8003 +.long 0x00ad9003 +.long 0x00ada003 +.long 0x00adb003 +.long 0x00adc003 +.long 0x00add003 +.long 0x00ade003 +.long 0x00adf003 +.long 0x00ae0003 +.long 0x00ae1003 +.long 0x00ae2003 +.long 0x00ae3003 +.long 0x00ae4003 +.long 0x00ae5003 +.long 0x00ae6003 +.long 0x00ae7003 +.long 0x00ae8003 +.long 0x00ae9003 +.long 0x00aea003 +.long 0x00aeb003 +.long 0x00aec003 +.long 0x00aed003 +.long 0x00aee003 +.long 0x00aef003 +.long 0x00af0003 +.long 0x00af1003 +.long 0x00af2003 +.long 0x00af3003 +.long 0x00af4003 +.long 0x00af5003 +.long 0x00af6003 +.long 0x00af7003 +.long 0x00af8003 +.long 0x00af9003 +.long 0x00afa003 +.long 0x00afb003 +.long 0x00afc003 +.long 0x00afd003 +.long 0x00afe003 +.long 0x00aff003 +.long 0x00b00003 +.long 0x00b01003 +.long 0x00b02003 +.long 0x00b03003 +.long 0x00b04003 +.long 0x00b05003 +.long 0x00b06003 +.long 0x00b07003 +.long 0x00b08003 +.long 0x00b09003 +.long 0x00b0a003 +.long 0x00b0b003 +.long 0x00b0c003 +.long 0x00b0d003 +.long 0x00b0e003 +.long 0x00b0f003 +.long 0x00b10003 +.long 0x00b11003 +.long 0x00b12003 +.long 0x00b13003 +.long 0x00b14003 +.long 0x00b15003 +.long 0x00b16003 +.long 0x00b17003 +.long 0x00b18003 +.long 0x00b19003 +.long 0x00b1a003 +.long 0x00b1b003 +.long 0x00b1c003 +.long 0x00b1d003 +.long 0x00b1e003 +.long 0x00b1f003 +.long 0x00b20003 +.long 0x00b21003 +.long 0x00b22003 +.long 0x00b23003 +.long 0x00b24003 +.long 0x00b25003 +.long 0x00b26003 +.long 0x00b27003 +.long 0x00b28003 +.long 0x00b29003 +.long 0x00b2a003 +.long 0x00b2b003 +.long 0x00b2c003 +.long 0x00b2d003 +.long 0x00b2e003 +.long 0x00b2f003 +.long 0x00b30003 +.long 0x00b31003 +.long 0x00b32003 +.long 0x00b33003 +.long 0x00b34003 +.long 0x00b35003 +.long 0x00b36003 +.long 0x00b37003 +.long 0x00b38003 +.long 0x00b39003 +.long 0x00b3a003 +.long 0x00b3b003 +.long 0x00b3c003 +.long 0x00b3d003 +.long 0x00b3e003 +.long 0x00b3f003 +.long 0x00b40003 +.long 0x00b41003 +.long 0x00b42003 +.long 0x00b43003 +.long 0x00b44003 +.long 0x00b45003 +.long 0x00b46003 +.long 0x00b47003 +.long 0x00b48003 +.long 0x00b49003 +.long 0x00b4a003 +.long 0x00b4b003 +.long 0x00b4c003 +.long 0x00b4d003 +.long 0x00b4e003 +.long 0x00b4f003 +.long 0x00b50003 +.long 0x00b51003 +.long 0x00b52003 +.long 0x00b53003 +.long 0x00b54003 +.long 0x00b55003 +.long 0x00b56003 +.long 0x00b57003 +.long 0x00b58003 +.long 0x00b59003 +.long 0x00b5a003 +.long 0x00b5b003 +.long 0x00b5c003 +.long 0x00b5d003 +.long 0x00b5e003 +.long 0x00b5f003 +.long 0x00b60003 +.long 0x00b61003 +.long 0x00b62003 +.long 0x00b63003 +.long 0x00b64003 +.long 0x00b65003 +.long 0x00b66003 +.long 0x00b67003 +.long 0x00b68003 +.long 0x00b69003 +.long 0x00b6a003 +.long 0x00b6b003 +.long 0x00b6c003 +.long 0x00b6d003 +.long 0x00b6e003 +.long 0x00b6f003 +.long 0x00b70003 +.long 0x00b71003 +.long 0x00b72003 +.long 0x00b73003 +.long 0x00b74003 +.long 0x00b75003 +.long 0x00b76003 +.long 0x00b77003 +.long 0x00b78003 +.long 0x00b79003 +.long 0x00b7a003 +.long 0x00b7b003 +.long 0x00b7c003 +.long 0x00b7d003 +.long 0x00b7e003 +.long 0x00b7f003 +.long 0x00b80003 +.long 0x00b81003 +.long 0x00b82003 +.long 0x00b83003 +.long 0x00b84003 +.long 0x00b85003 +.long 0x00b86003 +.long 0x00b87003 +.long 0x00b88003 +.long 0x00b89003 +.long 0x00b8a003 +.long 0x00b8b003 +.long 0x00b8c003 +.long 0x00b8d003 +.long 0x00b8e003 +.long 0x00b8f003 +.long 0x00b90003 +.long 0x00b91003 +.long 0x00b92003 +.long 0x00b93003 +.long 0x00b94003 +.long 0x00b95003 +.long 0x00b96003 +.long 0x00b97003 +.long 0x00b98003 +.long 0x00b99003 +.long 0x00b9a003 +.long 0x00b9b003 +.long 0x00b9c003 +.long 0x00b9d003 +.long 0x00b9e003 +.long 0x00b9f003 +.long 0x00ba0003 +.long 0x00ba1003 +.long 0x00ba2003 +.long 0x00ba3003 +.long 0x00ba4003 +.long 0x00ba5003 +.long 0x00ba6003 +.long 0x00ba7003 +.long 0x00ba8003 +.long 0x00ba9003 +.long 0x00baa003 +.long 0x00bab003 +.long 0x00bac003 +.long 0x00bad003 +.long 0x00bae003 +.long 0x00baf003 +.long 0x00bb0003 +.long 0x00bb1003 +.long 0x00bb2003 +.long 0x00bb3003 +.long 0x00bb4003 +.long 0x00bb5003 +.long 0x00bb6003 +.long 0x00bb7003 +.long 0x00bb8003 +.long 0x00bb9003 +.long 0x00bba003 +.long 0x00bbb003 +.long 0x00bbc003 +.long 0x00bbd003 +.long 0x00bbe003 +.long 0x00bbf003 +.long 0x00bc0003 +.long 0x00bc1003 +.long 0x00bc2003 +.long 0x00bc3003 +.long 0x00bc4003 +.long 0x00bc5003 +.long 0x00bc6003 +.long 0x00bc7003 +.long 0x00bc8003 +.long 0x00bc9003 +.long 0x00bca003 +.long 0x00bcb003 +.long 0x00bcc003 +.long 0x00bcd003 +.long 0x00bce003 +.long 0x00bcf003 +.long 0x00bd0003 +.long 0x00bd1003 +.long 0x00bd2003 +.long 0x00bd3003 +.long 0x00bd4003 +.long 0x00bd5003 +.long 0x00bd6003 +.long 0x00bd7003 +.long 0x00bd8003 +.long 0x00bd9003 +.long 0x00bda003 +.long 0x00bdb003 +.long 0x00bdc003 +.long 0x00bdd003 +.long 0x00bde003 +.long 0x00bdf003 +.long 0x00be0003 +.long 0x00be1003 +.long 0x00be2003 +.long 0x00be3003 +.long 0x00be4003 +.long 0x00be5003 +.long 0x00be6003 +.long 0x00be7003 +.long 0x00be8003 +.long 0x00be9003 +.long 0x00bea003 +.long 0x00beb003 +.long 0x00bec003 +.long 0x00bed003 +.long 0x00bee003 +.long 0x00bef003 +.long 0x00bf0003 +.long 0x00bf1003 +.long 0x00bf2003 +.long 0x00bf3003 +.long 0x00bf4003 +.long 0x00bf5003 +.long 0x00bf6003 +.long 0x00bf7003 +.long 0x00bf8003 +.long 0x00bf9003 +.long 0x00bfa003 +.long 0x00bfb003 +.long 0x00bfc003 +.long 0x00bfd003 +.long 0x00bfe003 +.long 0x00bff003 +.long 0x00c00003 # pt4 +.long 0x00c01003 +.long 0x00c02003 +.long 0x00c03003 +.long 0x00c04003 +.long 0x00c05003 +.long 0x00c06003 +.long 0x00c07003 +.long 0x00c08003 +.long 0x00c09003 +.long 0x00c0a003 +.long 0x00c0b003 +.long 0x00c0c003 +.long 0x00c0d003 +.long 0x00c0e003 +.long 0x00c0f003 +.long 0x00c10003 +.long 0x00c11003 +.long 0x00c12003 +.long 0x00c13003 +.long 0x00c14003 +.long 0x00c15003 +.long 0x00c16003 +.long 0x00c17003 +.long 0x00c18003 +.long 0x00c19003 +.long 0x00c1a003 +.long 0x00c1b003 +.long 0x00c1c003 +.long 0x00c1d003 +.long 0x00c1e003 +.long 0x00c1f003 +.long 0x00c20003 +.long 0x00c21003 +.long 0x00c22003 +.long 0x00c23003 +.long 0x00c24003 +.long 0x00c25003 +.long 0x00c26003 +.long 0x00c27003 +.long 0x00c28003 +.long 0x00c29003 +.long 0x00c2a003 +.long 0x00c2b003 +.long 0x00c2c003 +.long 0x00c2d003 +.long 0x00c2e003 +.long 0x00c2f003 +.long 0x00c30003 +.long 0x00c31003 +.long 0x00c32003 +.long 0x00c33003 +.long 0x00c34003 +.long 0x00c35003 +.long 0x00c36003 +.long 0x00c37003 +.long 0x00c38003 +.long 0x00c39003 +.long 0x00c3a003 +.long 0x00c3b003 +.long 0x00c3c003 +.long 0x00c3d003 +.long 0x00c3e003 +.long 0x00c3f003 +.long 0x00c40003 +.long 0x00c41003 +.long 0x00c42003 +.long 0x00c43003 +.long 0x00c44003 +.long 0x00c45003 +.long 0x00c46003 +.long 0x00c47003 +.long 0x00c48003 +.long 0x00c49003 +.long 0x00c4a003 +.long 0x00c4b003 +.long 0x00c4c003 +.long 0x00c4d003 +.long 0x00c4e003 +.long 0x00c4f003 +.long 0x00c50003 +.long 0x00c51003 +.long 0x00c52003 +.long 0x00c53003 +.long 0x00c54003 +.long 0x00c55003 +.long 0x00c56003 +.long 0x00c57003 +.long 0x00c58003 +.long 0x00c59003 +.long 0x00c5a003 +.long 0x00c5b003 +.long 0x00c5c003 +.long 0x00c5d003 +.long 0x00c5e003 +.long 0x00c5f003 +.long 0x00c60003 +.long 0x00c61003 +.long 0x00c62003 +.long 0x00c63003 +.long 0x00c64003 +.long 0x00c65003 +.long 0x00c66003 +.long 0x00c67003 +.long 0x00c68003 +.long 0x00c69003 +.long 0x00c6a003 +.long 0x00c6b003 +.long 0x00c6c003 +.long 0x00c6d003 +.long 0x00c6e003 +.long 0x00c6f003 +.long 0x00c70003 +.long 0x00c71003 +.long 0x00c72003 +.long 0x00c73003 +.long 0x00c74003 +.long 0x00c75003 +.long 0x00c76003 +.long 0x00c77003 +.long 0x00c78003 +.long 0x00c79003 +.long 0x00c7a003 +.long 0x00c7b003 +.long 0x00c7c003 +.long 0x00c7d003 +.long 0x00c7e003 +.long 0x00c7f003 +.long 0x00c80003 +.long 0x00c81003 +.long 0x00c82003 +.long 0x00c83003 +.long 0x00c84003 +.long 0x00c85003 +.long 0x00c86003 +.long 0x00c87003 +.long 0x00c88003 +.long 0x00c89003 +.long 0x00c8a003 +.long 0x00c8b003 +.long 0x00c8c003 +.long 0x00c8d003 +.long 0x00c8e003 +.long 0x00c8f003 +.long 0x00c90003 +.long 0x00c91003 +.long 0x00c92003 +.long 0x00c93003 +.long 0x00c94003 +.long 0x00c95003 +.long 0x00c96003 +.long 0x00c97003 +.long 0x00c98003 +.long 0x00c99003 +.long 0x00c9a003 +.long 0x00c9b003 +.long 0x00c9c003 +.long 0x00c9d003 +.long 0x00c9e003 +.long 0x00c9f003 +.long 0x00ca0003 +.long 0x00ca1003 +.long 0x00ca2003 +.long 0x00ca3003 +.long 0x00ca4003 +.long 0x00ca5003 +.long 0x00ca6003 +.long 0x00ca7003 +.long 0x00ca8003 +.long 0x00ca9003 +.long 0x00caa003 +.long 0x00cab003 +.long 0x00cac003 +.long 0x00cad003 +.long 0x00cae003 +.long 0x00caf003 +.long 0x00cb0003 +.long 0x00cb1003 +.long 0x00cb2003 +.long 0x00cb3003 +.long 0x00cb4003 +.long 0x00cb5003 +.long 0x00cb6003 +.long 0x00cb7003 +.long 0x00cb8003 +.long 0x00cb9003 +.long 0x00cba003 +.long 0x00cbb003 +.long 0x00cbc003 +.long 0x00cbd003 +.long 0x00cbe003 +.long 0x00cbf003 +.long 0x00cc0003 +.long 0x00cc1003 +.long 0x00cc2003 +.long 0x00cc3003 +.long 0x00cc4003 +.long 0x00cc5003 +.long 0x00cc6003 +.long 0x00cc7003 +.long 0x00cc8003 +.long 0x00cc9003 +.long 0x00cca003 +.long 0x00ccb003 +.long 0x00ccc003 +.long 0x00ccd003 +.long 0x00cce003 +.long 0x00ccf003 +.long 0x00cd0003 +.long 0x00cd1003 +.long 0x00cd2003 +.long 0x00cd3003 +.long 0x00cd4003 +.long 0x00cd5003 +.long 0x00cd6003 +.long 0x00cd7003 +.long 0x00cd8003 +.long 0x00cd9003 +.long 0x00cda003 +.long 0x00cdb003 +.long 0x00cdc003 +.long 0x00cdd003 +.long 0x00cde003 +.long 0x00cdf003 +.long 0x00ce0003 +.long 0x00ce1003 +.long 0x00ce2003 +.long 0x00ce3003 +.long 0x00ce4003 +.long 0x00ce5003 +.long 0x00ce6003 +.long 0x00ce7003 +.long 0x00ce8003 +.long 0x00ce9003 +.long 0x00cea003 +.long 0x00ceb003 +.long 0x00cec003 +.long 0x00ced003 +.long 0x00cee003 +.long 0x00cef003 +.long 0x00cf0003 +.long 0x00cf1003 +.long 0x00cf2003 +.long 0x00cf3003 +.long 0x00cf4003 +.long 0x00cf5003 +.long 0x00cf6003 +.long 0x00cf7003 +.long 0x00cf8003 +.long 0x00cf9003 +.long 0x00cfa003 +.long 0x00cfb003 +.long 0x00cfc003 +.long 0x00cfd003 +.long 0x00cfe003 +.long 0x00cff003 +.long 0x00d00003 +.long 0x00d01003 +.long 0x00d02003 +.long 0x00d03003 +.long 0x00d04003 +.long 0x00d05003 +.long 0x00d06003 +.long 0x00d07003 +.long 0x00d08003 +.long 0x00d09003 +.long 0x00d0a003 +.long 0x00d0b003 +.long 0x00d0c003 +.long 0x00d0d003 +.long 0x00d0e003 +.long 0x00d0f003 +.long 0x00d10003 +.long 0x00d11003 +.long 0x00d12003 +.long 0x00d13003 +.long 0x00d14003 +.long 0x00d15003 +.long 0x00d16003 +.long 0x00d17003 +.long 0x00d18003 +.long 0x00d19003 +.long 0x00d1a003 +.long 0x00d1b003 +.long 0x00d1c003 +.long 0x00d1d003 +.long 0x00d1e003 +.long 0x00d1f003 +.long 0x00d20003 +.long 0x00d21003 +.long 0x00d22003 +.long 0x00d23003 +.long 0x00d24003 +.long 0x00d25003 +.long 0x00d26003 +.long 0x00d27003 +.long 0x00d28003 +.long 0x00d29003 +.long 0x00d2a003 +.long 0x00d2b003 +.long 0x00d2c003 +.long 0x00d2d003 +.long 0x00d2e003 +.long 0x00d2f003 +.long 0x00d30003 +.long 0x00d31003 +.long 0x00d32003 +.long 0x00d33003 +.long 0x00d34003 +.long 0x00d35003 +.long 0x00d36003 +.long 0x00d37003 +.long 0x00d38003 +.long 0x00d39003 +.long 0x00d3a003 +.long 0x00d3b003 +.long 0x00d3c003 +.long 0x00d3d003 +.long 0x00d3e003 +.long 0x00d3f003 +.long 0x00d40003 +.long 0x00d41003 +.long 0x00d42003 +.long 0x00d43003 +.long 0x00d44003 +.long 0x00d45003 +.long 0x00d46003 +.long 0x00d47003 +.long 0x00d48003 +.long 0x00d49003 +.long 0x00d4a003 +.long 0x00d4b003 +.long 0x00d4c003 +.long 0x00d4d003 +.long 0x00d4e003 +.long 0x00d4f003 +.long 0x00d50003 +.long 0x00d51003 +.long 0x00d52003 +.long 0x00d53003 +.long 0x00d54003 +.long 0x00d55003 +.long 0x00d56003 +.long 0x00d57003 +.long 0x00d58003 +.long 0x00d59003 +.long 0x00d5a003 +.long 0x00d5b003 +.long 0x00d5c003 +.long 0x00d5d003 +.long 0x00d5e003 +.long 0x00d5f003 +.long 0x00d60003 +.long 0x00d61003 +.long 0x00d62003 +.long 0x00d63003 +.long 0x00d64003 +.long 0x00d65003 +.long 0x00d66003 +.long 0x00d67003 +.long 0x00d68003 +.long 0x00d69003 +.long 0x00d6a003 +.long 0x00d6b003 +.long 0x00d6c003 +.long 0x00d6d003 +.long 0x00d6e003 +.long 0x00d6f003 +.long 0x00d70003 +.long 0x00d71003 +.long 0x00d72003 +.long 0x00d73003 +.long 0x00d74003 +.long 0x00d75003 +.long 0x00d76003 +.long 0x00d77003 +.long 0x00d78003 +.long 0x00d79003 +.long 0x00d7a003 +.long 0x00d7b003 +.long 0x00d7c003 +.long 0x00d7d003 +.long 0x00d7e003 +.long 0x00d7f003 +.long 0x00d80003 +.long 0x00d81003 +.long 0x00d82003 +.long 0x00d83003 +.long 0x00d84003 +.long 0x00d85003 +.long 0x00d86003 +.long 0x00d87003 +.long 0x00d88003 +.long 0x00d89003 +.long 0x00d8a003 +.long 0x00d8b003 +.long 0x00d8c003 +.long 0x00d8d003 +.long 0x00d8e003 +.long 0x00d8f003 +.long 0x00d90003 +.long 0x00d91003 +.long 0x00d92003 +.long 0x00d93003 +.long 0x00d94003 +.long 0x00d95003 +.long 0x00d96003 +.long 0x00d97003 +.long 0x00d98003 +.long 0x00d99003 +.long 0x00d9a003 +.long 0x00d9b003 +.long 0x00d9c003 +.long 0x00d9d003 +.long 0x00d9e003 +.long 0x00d9f003 +.long 0x00da0003 +.long 0x00da1003 +.long 0x00da2003 +.long 0x00da3003 +.long 0x00da4003 +.long 0x00da5003 +.long 0x00da6003 +.long 0x00da7003 +.long 0x00da8003 +.long 0x00da9003 +.long 0x00daa003 +.long 0x00dab003 +.long 0x00dac003 +.long 0x00dad003 +.long 0x00dae003 +.long 0x00daf003 +.long 0x00db0003 +.long 0x00db1003 +.long 0x00db2003 +.long 0x00db3003 +.long 0x00db4003 +.long 0x00db5003 +.long 0x00db6003 +.long 0x00db7003 +.long 0x00db8003 +.long 0x00db9003 +.long 0x00dba003 +.long 0x00dbb003 +.long 0x00dbc003 +.long 0x00dbd003 +.long 0x00dbe003 +.long 0x00dbf003 +.long 0x00dc0003 +.long 0x00dc1003 +.long 0x00dc2003 +.long 0x00dc3003 +.long 0x00dc4003 +.long 0x00dc5003 +.long 0x00dc6003 +.long 0x00dc7003 +.long 0x00dc8003 +.long 0x00dc9003 +.long 0x00dca003 +.long 0x00dcb003 +.long 0x00dcc003 +.long 0x00dcd003 +.long 0x00dce003 +.long 0x00dcf003 +.long 0x00dd0003 +.long 0x00dd1003 +.long 0x00dd2003 +.long 0x00dd3003 +.long 0x00dd4003 +.long 0x00dd5003 +.long 0x00dd6003 +.long 0x00dd7003 +.long 0x00dd8003 +.long 0x00dd9003 +.long 0x00dda003 +.long 0x00ddb003 +.long 0x00ddc003 +.long 0x00ddd003 +.long 0x00dde003 +.long 0x00ddf003 +.long 0x00de0003 +.long 0x00de1003 +.long 0x00de2003 +.long 0x00de3003 +.long 0x00de4003 +.long 0x00de5003 +.long 0x00de6003 +.long 0x00de7003 +.long 0x00de8003 +.long 0x00de9003 +.long 0x00dea003 +.long 0x00deb003 +.long 0x00dec003 +.long 0x00ded003 +.long 0x00dee003 +.long 0x00def003 +.long 0x00df0003 +.long 0x00df1003 +.long 0x00df2003 +.long 0x00df3003 +.long 0x00df4003 +.long 0x00df5003 +.long 0x00df6003 +.long 0x00df7003 +.long 0x00df8003 +.long 0x00df9003 +.long 0x00dfa003 +.long 0x00dfb003 +.long 0x00dfc003 +.long 0x00dfd003 +.long 0x00dfe003 +.long 0x00dff003 +.long 0x00e00003 +.long 0x00e01003 +.long 0x00e02003 +.long 0x00e03003 +.long 0x00e04003 +.long 0x00e05003 +.long 0x00e06003 +.long 0x00e07003 +.long 0x00e08003 +.long 0x00e09003 +.long 0x00e0a003 +.long 0x00e0b003 +.long 0x00e0c003 +.long 0x00e0d003 +.long 0x00e0e003 +.long 0x00e0f003 +.long 0x00e10003 +.long 0x00e11003 +.long 0x00e12003 +.long 0x00e13003 +.long 0x00e14003 +.long 0x00e15003 +.long 0x00e16003 +.long 0x00e17003 +.long 0x00e18003 +.long 0x00e19003 +.long 0x00e1a003 +.long 0x00e1b003 +.long 0x00e1c003 +.long 0x00e1d003 +.long 0x00e1e003 +.long 0x00e1f003 +.long 0x00e20003 +.long 0x00e21003 +.long 0x00e22003 +.long 0x00e23003 +.long 0x00e24003 +.long 0x00e25003 +.long 0x00e26003 +.long 0x00e27003 +.long 0x00e28003 +.long 0x00e29003 +.long 0x00e2a003 +.long 0x00e2b003 +.long 0x00e2c003 +.long 0x00e2d003 +.long 0x00e2e003 +.long 0x00e2f003 +.long 0x00e30003 +.long 0x00e31003 +.long 0x00e32003 +.long 0x00e33003 +.long 0x00e34003 +.long 0x00e35003 +.long 0x00e36003 +.long 0x00e37003 +.long 0x00e38003 +.long 0x00e39003 +.long 0x00e3a003 +.long 0x00e3b003 +.long 0x00e3c003 +.long 0x00e3d003 +.long 0x00e3e003 +.long 0x00e3f003 +.long 0x00e40003 +.long 0x00e41003 +.long 0x00e42003 +.long 0x00e43003 +.long 0x00e44003 +.long 0x00e45003 +.long 0x00e46003 +.long 0x00e47003 +.long 0x00e48003 +.long 0x00e49003 +.long 0x00e4a003 +.long 0x00e4b003 +.long 0x00e4c003 +.long 0x00e4d003 +.long 0x00e4e003 +.long 0x00e4f003 +.long 0x00e50003 +.long 0x00e51003 +.long 0x00e52003 +.long 0x00e53003 +.long 0x00e54003 +.long 0x00e55003 +.long 0x00e56003 +.long 0x00e57003 +.long 0x00e58003 +.long 0x00e59003 +.long 0x00e5a003 +.long 0x00e5b003 +.long 0x00e5c003 +.long 0x00e5d003 +.long 0x00e5e003 +.long 0x00e5f003 +.long 0x00e60003 +.long 0x00e61003 +.long 0x00e62003 +.long 0x00e63003 +.long 0x00e64003 +.long 0x00e65003 +.long 0x00e66003 +.long 0x00e67003 +.long 0x00e68003 +.long 0x00e69003 +.long 0x00e6a003 +.long 0x00e6b003 +.long 0x00e6c003 +.long 0x00e6d003 +.long 0x00e6e003 +.long 0x00e6f003 +.long 0x00e70003 +.long 0x00e71003 +.long 0x00e72003 +.long 0x00e73003 +.long 0x00e74003 +.long 0x00e75003 +.long 0x00e76003 +.long 0x00e77003 +.long 0x00e78003 +.long 0x00e79003 +.long 0x00e7a003 +.long 0x00e7b003 +.long 0x00e7c003 +.long 0x00e7d003 +.long 0x00e7e003 +.long 0x00e7f003 +.long 0x00e80003 +.long 0x00e81003 +.long 0x00e82003 +.long 0x00e83003 +.long 0x00e84003 +.long 0x00e85003 +.long 0x00e86003 +.long 0x00e87003 +.long 0x00e88003 +.long 0x00e89003 +.long 0x00e8a003 +.long 0x00e8b003 +.long 0x00e8c003 +.long 0x00e8d003 +.long 0x00e8e003 +.long 0x00e8f003 +.long 0x00e90003 +.long 0x00e91003 +.long 0x00e92003 +.long 0x00e93003 +.long 0x00e94003 +.long 0x00e95003 +.long 0x00e96003 +.long 0x00e97003 +.long 0x00e98003 +.long 0x00e99003 +.long 0x00e9a003 +.long 0x00e9b003 +.long 0x00e9c003 +.long 0x00e9d003 +.long 0x00e9e003 +.long 0x00e9f003 +.long 0x00ea0003 +.long 0x00ea1003 +.long 0x00ea2003 +.long 0x00ea3003 +.long 0x00ea4003 +.long 0x00ea5003 +.long 0x00ea6003 +.long 0x00ea7003 +.long 0x00ea8003 +.long 0x00ea9003 +.long 0x00eaa003 +.long 0x00eab003 +.long 0x00eac003 +.long 0x00ead003 +.long 0x00eae003 +.long 0x00eaf003 +.long 0x00eb0003 +.long 0x00eb1003 +.long 0x00eb2003 +.long 0x00eb3003 +.long 0x00eb4003 +.long 0x00eb5003 +.long 0x00eb6003 +.long 0x00eb7003 +.long 0x00eb8003 +.long 0x00eb9003 +.long 0x00eba003 +.long 0x00ebb003 +.long 0x00ebc003 +.long 0x00ebd003 +.long 0x00ebe003 +.long 0x00ebf003 +.long 0x00ec0003 +.long 0x00ec1003 +.long 0x00ec2003 +.long 0x00ec3003 +.long 0x00ec4003 +.long 0x00ec5003 +.long 0x00ec6003 +.long 0x00ec7003 +.long 0x00ec8003 +.long 0x00ec9003 +.long 0x00eca003 +.long 0x00ecb003 +.long 0x00ecc003 +.long 0x00ecd003 +.long 0x00ece003 +.long 0x00ecf003 +.long 0x00ed0003 +.long 0x00ed1003 +.long 0x00ed2003 +.long 0x00ed3003 +.long 0x00ed4003 +.long 0x00ed5003 +.long 0x00ed6003 +.long 0x00ed7003 +.long 0x00ed8003 +.long 0x00ed9003 +.long 0x00eda003 +.long 0x00edb003 +.long 0x00edc003 +.long 0x00edd003 +.long 0x00ede003 +.long 0x00edf003 +.long 0x00ee0003 +.long 0x00ee1003 +.long 0x00ee2003 +.long 0x00ee3003 +.long 0x00ee4003 +.long 0x00ee5003 +.long 0x00ee6003 +.long 0x00ee7003 +.long 0x00ee8003 +.long 0x00ee9003 +.long 0x00eea003 +.long 0x00eeb003 +.long 0x00eec003 +.long 0x00eed003 +.long 0x00eee003 +.long 0x00eef003 +.long 0x00ef0003 +.long 0x00ef1003 +.long 0x00ef2003 +.long 0x00ef3003 +.long 0x00ef4003 +.long 0x00ef5003 +.long 0x00ef6003 +.long 0x00ef7003 +.long 0x00ef8003 +.long 0x00ef9003 +.long 0x00efa003 +.long 0x00efb003 +.long 0x00efc003 +.long 0x00efd003 +.long 0x00efe003 +.long 0x00eff003 +.long 0x00f00003 +.long 0x00f01003 +.long 0x00f02003 +.long 0x00f03003 +.long 0x00f04003 +.long 0x00f05003 +.long 0x00f06003 +.long 0x00f07003 +.long 0x00f08003 +.long 0x00f09003 +.long 0x00f0a003 +.long 0x00f0b003 +.long 0x00f0c003 +.long 0x00f0d003 +.long 0x00f0e003 +.long 0x00f0f003 +.long 0x00f10003 +.long 0x00f11003 +.long 0x00f12003 +.long 0x00f13003 +.long 0x00f14003 +.long 0x00f15003 +.long 0x00f16003 +.long 0x00f17003 +.long 0x00f18003 +.long 0x00f19003 +.long 0x00f1a003 +.long 0x00f1b003 +.long 0x00f1c003 +.long 0x00f1d003 +.long 0x00f1e003 +.long 0x00f1f003 +.long 0x00f20003 +.long 0x00f21003 +.long 0x00f22003 +.long 0x00f23003 +.long 0x00f24003 +.long 0x00f25003 +.long 0x00f26003 +.long 0x00f27003 +.long 0x00f28003 +.long 0x00f29003 +.long 0x00f2a003 +.long 0x00f2b003 +.long 0x00f2c003 +.long 0x00f2d003 +.long 0x00f2e003 +.long 0x00f2f003 +.long 0x00f30003 +.long 0x00f31003 +.long 0x00f32003 +.long 0x00f33003 +.long 0x00f34003 +.long 0x00f35003 +.long 0x00f36003 +.long 0x00f37003 +.long 0x00f38003 +.long 0x00f39003 +.long 0x00f3a003 +.long 0x00f3b003 +.long 0x00f3c003 +.long 0x00f3d003 +.long 0x00f3e003 +.long 0x00f3f003 +.long 0x00f40003 +.long 0x00f41003 +.long 0x00f42003 +.long 0x00f43003 +.long 0x00f44003 +.long 0x00f45003 +.long 0x00f46003 +.long 0x00f47003 +.long 0x00f48003 +.long 0x00f49003 +.long 0x00f4a003 +.long 0x00f4b003 +.long 0x00f4c003 +.long 0x00f4d003 +.long 0x00f4e003 +.long 0x00f4f003 +.long 0x00f50003 +.long 0x00f51003 +.long 0x00f52003 +.long 0x00f53003 +.long 0x00f54003 +.long 0x00f55003 +.long 0x00f56003 +.long 0x00f57003 +.long 0x00f58003 +.long 0x00f59003 +.long 0x00f5a003 +.long 0x00f5b003 +.long 0x00f5c003 +.long 0x00f5d003 +.long 0x00f5e003 +.long 0x00f5f003 +.long 0x00f60003 +.long 0x00f61003 +.long 0x00f62003 +.long 0x00f63003 +.long 0x00f64003 +.long 0x00f65003 +.long 0x00f66003 +.long 0x00f67003 +.long 0x00f68003 +.long 0x00f69003 +.long 0x00f6a003 +.long 0x00f6b003 +.long 0x00f6c003 +.long 0x00f6d003 +.long 0x00f6e003 +.long 0x00f6f003 +.long 0x00f70003 +.long 0x00f71003 +.long 0x00f72003 +.long 0x00f73003 +.long 0x00f74003 +.long 0x00f75003 +.long 0x00f76003 +.long 0x00f77003 +.long 0x00f78003 +.long 0x00f79003 +.long 0x00f7a003 +.long 0x00f7b003 +.long 0x00f7c003 +.long 0x00f7d003 +.long 0x00f7e003 +.long 0x00f7f003 +.long 0x00f80003 +.long 0x00f81003 +.long 0x00f82003 +.long 0x00f83003 +.long 0x00f84003 +.long 0x00f85003 +.long 0x00f86003 +.long 0x00f87003 +.long 0x00f88003 +.long 0x00f89003 +.long 0x00f8a003 +.long 0x00f8b003 +.long 0x00f8c003 +.long 0x00f8d003 +.long 0x00f8e003 +.long 0x00f8f003 +.long 0x00f90003 +.long 0x00f91003 +.long 0x00f92003 +.long 0x00f93003 +.long 0x00f94003 +.long 0x00f95003 +.long 0x00f96003 +.long 0x00f97003 +.long 0x00f98003 +.long 0x00f99003 +.long 0x00f9a003 +.long 0x00f9b003 +.long 0x00f9c003 +.long 0x00f9d003 +.long 0x00f9e003 +.long 0x00f9f003 +.long 0x00fa0003 +.long 0x00fa1003 +.long 0x00fa2003 +.long 0x00fa3003 +.long 0x00fa4003 +.long 0x00fa5003 +.long 0x00fa6003 +.long 0x00fa7003 +.long 0x00fa8003 +.long 0x00fa9003 +.long 0x00faa003 +.long 0x00fab003 +.long 0x00fac003 +.long 0x00fad003 +.long 0x00fae003 +.long 0x00faf003 +.long 0x00fb0003 +.long 0x00fb1003 +.long 0x00fb2003 +.long 0x00fb3003 +.long 0x00fb4003 +.long 0x00fb5003 +.long 0x00fb6003 +.long 0x00fb7003 +.long 0x00fb8003 +.long 0x00fb9003 +.long 0x00fba003 +.long 0x00fbb003 +.long 0x00fbc003 +.long 0x00fbd003 +.long 0x00fbe003 +.long 0x00fbf003 +.long 0x00fc0003 +.long 0x00fc1003 +.long 0x00fc2003 +.long 0x00fc3003 +.long 0x00fc4003 +.long 0x00fc5003 +.long 0x00fc6003 +.long 0x00fc7003 +.long 0x00fc8003 +.long 0x00fc9003 +.long 0x00fca003 +.long 0x00fcb003 +.long 0x00fcc003 +.long 0x00fcd003 +.long 0x00fce003 +.long 0x00fcf003 +.long 0x00fd0003 +.long 0x00fd1003 +.long 0x00fd2003 +.long 0x00fd3003 +.long 0x00fd4003 +.long 0x00fd5003 +.long 0x00fd6003 +.long 0x00fd7003 +.long 0x00fd8003 +.long 0x00fd9003 +.long 0x00fda003 +.long 0x00fdb003 +.long 0x00fdc003 +.long 0x00fdd003 +.long 0x00fde003 +.long 0x00fdf003 +.long 0x00fe0003 +.long 0x00fe1003 +.long 0x00fe2003 +.long 0x00fe3003 +.long 0x00fe4003 +.long 0x00fe5003 +.long 0x00fe6003 +.long 0x00fe7003 +.long 0x00fe8003 +.long 0x00fe9003 +.long 0x00fea003 +.long 0x00feb003 +.long 0x00fec003 +.long 0x00fed003 +.long 0x00fee003 +.long 0x00fef003 +.long 0x00ff0003 +.long 0x00ff1003 +.long 0x00ff2003 +.long 0x00ff3003 +.long 0x00ff4003 +.long 0x00ff5003 +.long 0x00ff6003 +.long 0x00ff7003 +.long 0x00ff8003 +.long 0x00ff9003 +.long 0x00ffa003 +.long 0x00ffb003 +.long 0x00ffc003 +.long 0x00ffd003 +.long 0x00ffe003 +.long 0x00fff003 +# Here's our indirect mapping. It maps virtual address 0x010000000 to the entry +# provided. +.long 0x0100f003 +.fill 1023, 4, 0 diff --git a/410kern/RNG/kernel.mk b/410kern/RNG/kernel.mk new file mode 100644 index 0000000..8fe7b4f --- /dev/null +++ b/410kern/RNG/kernel.mk @@ -0,0 +1,6 @@ +410KLIB_RNG_OBJS = $(410KDIR)/RNG/mt19937int.o + +ALL_410KOBJS += $(410KLIB_RNG_OBJS) +410KCLEANS += $(410KDIR)/libRNG.a + +$(410KDIR)/libRNG.a: $(410KLIB_RNG_OBJS) diff --git a/410kern/RNG/mt19937int.c b/410kern/RNG/mt19937int.c new file mode 100644 index 0000000..809bc01 --- /dev/null +++ b/410kern/RNG/mt19937int.c @@ -0,0 +1,97 @@ +/* A C-program for MT19937: Integer version */ +/* genrand() generates one pseudorandom unsigned integer (32bit) */ +/* which is uniformly distributed among 0 to 2^32-1 for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* 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., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* Any feedback is very welcome. For any question, comments, */ +/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ +/* matumoto@math.keio.ac.jp */ + +/* modified for 15-410 at CMU by Zachary Anderson(zra) */ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0df /* constant vector a */ +#define UPPER_MASK 0x80000000 /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffff /* least significant r bits */ + +/* Tempering parameters */ +#define TEMPERING_MASK_B 0x9d2c5680 +#define TEMPERING_MASK_C 0xefc60000 +#define TEMPERING_SHIFT_U(y) (y >> 11) +#define TEMPERING_SHIFT_S(y) (y << 7) +#define TEMPERING_SHIFT_T(y) (y << 15) +#define TEMPERING_SHIFT_L(y) (y >> 18) + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializing the array with a NONZERO seed */ +void +sgenrand(seed) +unsigned long seed; +{ + /* setting initial seeds to mt[N] using */ + /* the generator Line 25 of Table 1 in */ + /* [KNUTH 1981, The Art of Computer Programming */ + /* Vol. 2 (2nd Ed.), pp102] */ + mt[0]= seed & 0xffffffff; + for (mti=1; mti= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if sgenrand() has not been called, */ + sgenrand(4357); /* a default initial seed is used */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1]; + } + for (;kk> 1) ^ mag01[y & 0x1]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]; + + mti = 0; + } + + y = mt[mti++]; + y ^= TEMPERING_SHIFT_U(y); + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; + y ^= TEMPERING_SHIFT_L(y); + + return y; +} diff --git a/410kern/RNG/mt19937int.h b/410kern/RNG/mt19937int.h new file mode 100644 index 0000000..f97619a --- /dev/null +++ b/410kern/RNG/mt19937int.h @@ -0,0 +1,35 @@ +/* A C-program for MT19937: Integer version */ +/* genrand() generates one pseudorandom unsigned integer (32bit) */ +/* which is uniformly distributed among 0 to 2^32-1 for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* 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., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* Any feedback is very welcome. For any question, comments, */ +/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ +/* matumoto@math.keio.ac.jp */ + +#ifndef _RAND_H +#define _RAND_H + +void sgenrand( unsigned long ); +unsigned long genrand(); + +#endif /* _RAND_H */ diff --git a/410kern/boot/head.S b/410kern/boot/head.S new file mode 100644 index 0000000..d0ecdf2 --- /dev/null +++ b/410kern/boot/head.S @@ -0,0 +1,200 @@ +/** + * @file boot/head.S + * @author matthewj + * @author de0u + */ + +/* N.B. This is NOT to be construed as style guidance!! */ +/* N.B. This is NOT to be construed as style guidance!! */ +/* N.B. This is NOT to be construed as style guidance!! */ + +#include +#include +#include + +/** @brief Entry point from the bootloader */ +.global _start +/** @brief Start of the kernel image */ +.global __kimg_start +/** @brief Start of the init GDT */ +.global init_gdt +/** @brief Start of the init IDT */ +.global init_idt +/** @brief Start of the init TSS */ +.global init_tss +.global init_tss_size + +.text + +__kimg_start: + +mb_header: + /* Not a complete Multiboot header, but GRUB can live with it. */ + .long 0x1BADB002 /**< Multiboot magic word */ + .long 0x00000000 /**< Flags field */ + .long (0 - 0x1BADB002 - 0x00000000) /**< Checksum */ + .space 244 + +init_idt: /* 0x100100 */ + .space 64 + .long 0x001009b8 + .long 0x00108e00 + .space 1976 +init_gdt: /* 0x100900 */ + .long 0x00000000 + .long 0x00000000 + /* Next two lines need to be kept in sync with smp/smp.c */ + .long 0x09500067 + .long 0x00008910 + .long 0x0000ffff + .long 0x00cf9b00 + .long 0x0000ffff + .long 0x00cf9300 + .long 0x0000ffff + .long 0x00cffb00 + .long 0x0000ffff + .long 0x00cff200 + /* Spare segment descriptors follow, see x86/seg.h */ + .long 0x00000000 /**< SEGSEL_SPARE0 word 0 */ + .long 0x00000000 + .long 0x00000000 /**< SEGSEL_SPARE1 word 0 */ + .long 0x00000000 + .long 0x00000000 /**< SEGSEL_SPARE2 word 0 */ + .long 0x00000000 + .long 0x00000000 /**< SEGSEL_SPARE3 word 0 */ + .long 0x00000000 +init_tss: /* 0x100950 */ + .space 8 + .word 0x0018 + .space 92 /* fills with 0's */ + .word 0x0068 +init_tss_end: + +df_handler: /* 0x1009b8 */ + cli + /* Get something "out there" first thing */ + leal fmsg, %ecx + movl $SIM_PUTS, %ebx + xchg %ebx, %ebx + /* We got here because we were in trouble, so be conservative */ + movl $SEGSEL_KERNEL_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + leal istack, %esp + subl $2048, %esp /* try to avoid wiping state */ + /* Now we probably have a runtime environment */ + leal fbytes, %eax + pushl %eax + call blat +df_handler_loop: + jmp df_handler_loop + +_start: + cmpl $0x15410DE0, %eax + je _guest_start + cli /* I sure HOPE this is superfluous */ + leal istack, %esp /* Load initial stack pointer */ + + movl $init_tss, %eax + subl $init_gdt, %eax + subl $1, %eax + pushl %eax /* gdt limit == sizeof(gdt)-1 */ + pushl $init_gdt + call lgdt + addl $8, %esp + + movl $init_gdt, %eax + subl $init_idt, %eax + subl $1, %eax + pushl %eax /* idt limit == sizeof(idt)-1 */ + pushl $init_idt + call lidt + addl $8, %esp + + movl $SEGSEL_TSS, %eax + ltr %ax + + pushl %esp /* Pass in the top of the initial stack */ + pushl %ebx /* Pass in the multiboot structure */ + call mb_entry /* Call the C entry point */ + + /* "should not get here" */ + pushl $pbytes + call blat +stuck: + jmp stuck + +_guest_start: + leal istack, %esp /* Load initial stack pointer */ + pushl %ecx /* Max legal vaddr */ + pushl %ebx /* Number of max legal vframe */ + call hv_guest_entry + addl $8,%esp /* In case anybody's keeping score */ + jmp stuck + +# void blat(uint8_t *bytes) +blat: + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %esi + pushl %edi + + movl 8(%ebp), %eax # bytes + pushl %eax + call strlen + movl %eax, %edx # EDX: strlen(bytes) + add $4, %esp + + movl $CONSOLE_MEM_BASE, %edi # EDI: dest + + movl $CONSOLE_WIDTH, %ebx + imull $CONSOLE_HEIGHT, %ebx + sall $1, %ebx # 2*width*height + addl %edi, %ebx # EBX: limit + subl %edx, %ebx # EBX: limit (round down) + + movl %es, %eax + pushl %eax # save ES + movl %ds, %eax + movl %eax, %es # force ES to match DS + +movs: + movl %edx, %ecx # ECX: count + movl 8(%ebp), %esi # ESI: source + rep movsb # ECX bytes from DS:ESI to ES:EDI + cmpl %edi, %ebx + jg movs + + popl %eax + movl %eax, %es # restore ES + + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + +init_tss_size: + .long (init_tss_end - init_tss) + +.data + + +fmsg: + .asciz "\n***** Double fault!\n" +fbytes: + .asciz "D\ro\ru\rb\rl\re\r \rf\ra\ru\rl\rt\r!\r \r" + +pmsg: + .asciz "Kernel cannot return()!" +pbytes: + .asciz "K\re\rr\rn\re\rl\r \rc\ra\rn\rn\ro\rt\r \rr\re\rt\ru\rr\rn\r(\r)\r!\r \r" + +/* Initial stack */ +.align 4 +.space 4096 +istack: diff --git a/410kern/boot/kernel.mk b/410kern/boot/kernel.mk new file mode 100644 index 0000000..ba4d1fe --- /dev/null +++ b/410kern/boot/kernel.mk @@ -0,0 +1,13 @@ +410K_BOOT_OBJS := \ + util_lmm.o \ + util_cmdline.o \ + +410K_BOOT_OBJS := $(410K_BOOT_OBJS:%=$(410KDIR)/boot/%) + +ALL_410KOBJS += $(410K_BOOT_OBJS) +410KCLEANS += $(410KDIR)/libboot.a + +$(410KDIR)/libboot.a: $(410K_BOOT_OBJS) + +KERNEL_BOOT_HEAD += $(410KDIR)/boot/head.o +410KCLEANS += $(KERNEL_BOOT_HEAD) diff --git a/410kern/boot/multiboot.h b/410kern/boot/multiboot.h new file mode 100644 index 0000000..15f2e04 --- /dev/null +++ b/410kern/boot/multiboot.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_X86_MULTIBOOT_H_ +#define _FLUX_X86_MULTIBOOT_H_ + +#include + +/* For a.out kernel boot images, the following header must appear + somewhere in the first 8192 bytes of the kernel image file. */ +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC */ + unsigned magic; + + /* Feature flags - see below. */ + unsigned flags; + + /* Checksum: magic + flags + checksum == 0 */ + unsigned checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + vm_offset_t header_addr; + vm_offset_t load_addr; + vm_offset_t load_end_addr; + vm_offset_t bss_end_addr; + vm_offset_t entry; +}; + +/* The entire multiboot_header must be contained + within the first MULTIBOOT_SEARCH bytes of the kernel image. */ +#define MULTIBOOT_SEARCH 8192 + +/* Magic value identifying the multiboot_header. */ +#define MULTIBOOT_MAGIC 0x1badb002 + +/* Features flags for 'flags'. + If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set + and it doesn't understand it, it must fail. */ +#define MULTIBOOT_MUSTKNOW 0x0000ffff + +/* Align all boot modules on page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must be provided memory information in multiboot_info structure */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Use the load address fields above instead of the ones in the a.out header + to figure out what to load where, and what to do afterwards. + This should only be needed for a.out kernel images + (ELF and other formats can generally provide the needed information). */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* The boot loader passes this value in register EAX to signal the kernel + that the multiboot method is being used */ +#define MULTIBOOT_VALID 0x2badb002 + +/* The boot loader passes this data structure to the kernel in + register EBX on entry. */ +struct multiboot_info +{ + /* These flags indicate which parts of the multiboot_info are valid; + see below for the actual flag bit definitions. */ + unsigned flags; + + /* Lower/Upper memory installed in the machine. + Valid only if MULTIBOOT_MEMORY is set in flags word above. */ + vm_size_t mem_lower; + vm_size_t mem_upper; + + /* BIOS disk device the kernel was loaded from. + Valid only if MULTIBOOT_BOOT_DEVICE is set in flags word above. */ + unsigned char boot_device[4]; + + /* Command-line for the OS kernel: a null-terminated ASCII string. + Valid only if MULTIBOOT_CMDLINE is set in flags word above. */ + vm_offset_t cmdline; + + /* List of boot modules loaded with the kernel. + Valid only if MULTIBOOT_MODS is set in flags word above. */ + unsigned mods_count; + vm_offset_t mods_addr; + + /* Symbol information for a.out or ELF executables. */ + union + { + struct + { + /* a.out symbol information valid only if MULTIBOOT_AOUT_SYMS + is set in flags word above. */ + vm_size_t tabsize; + vm_size_t strsize; + vm_offset_t addr; + unsigned reserved; + } a; + + struct + { + /* ELF section header information valid only if + MULTIBOOT_ELF_SHDR is set in flags word above. */ + unsigned num; + vm_size_t size; + vm_offset_t addr; + unsigned shndx; + } e; + } syms; + + /* Memory map buffer. + Valid only if MULTIBOOT_MEM_MAP is set in flags word above. */ + vm_size_t mmap_count; + vm_offset_t mmap_addr; +}; + +typedef struct multiboot_info mbinfo_t; + +#define MULTIBOOT_MEMORY (1L<<0) +#define MULTIBOOT_BOOT_DEVICE (1L<<1) +#define MULTIBOOT_CMDLINE (1L<<2) +#define MULTIBOOT_MODS (1L<<3) +#define MULTIBOOT_AOUT_SYMS (1L<<4) +#define MULTIBOOT_ELF_SHDR (1L<<5) +#define MULTIBOOT_MEM_MAP (1L<<6) + +/* For use with printf's %b format. */ +#define MULTIBOOT_FLAGS_FORMAT \ + "\20\1MEMORY\2BOOT_DEVICE\3CMDLINE\4MODS\5AOUT_SYMS\6ELF_SHDR\7MEM_MAP" + +/* The mods_addr field above contains the physical address of the first + of 'mods_count' multiboot_module structures. */ +struct multiboot_module +{ + /* Physical start and end addresses of the module data itself. */ + vm_offset_t mod_start; + vm_offset_t mod_end; + + /* Arbitrary ASCII string associated with the module. */ + vm_offset_t string; + + /* Boot loader must set to 0; OS must ignore. */ + unsigned reserved; +}; + + +/* The mmap_addr field above contains the physical address of the first + of the AddrRangeDesc structure. "size" represents the size of the + rest of the structure and optional padding. The offset to the beginning + of the next structure is therefore "size + 4". */ +struct AddrRangeDesc +{ + unsigned long size; + unsigned long BaseAddrLow; + unsigned long BaseAddrHigh; + unsigned long LengthLow; + unsigned long LengthHigh; + unsigned long Type; + + /* unspecified optional padding... */ +}; + +/* usable memory "Type", all others are reserved. */ +#define MB_ARD_MEMORY 1 + + +#endif /* _FLUX_X86_MULTIBOOT_H_ */ diff --git a/410kern/boot/util.h b/410kern/boot/util.h new file mode 100644 index 0000000..b8f283e --- /dev/null +++ b/410kern/boot/util.h @@ -0,0 +1,10 @@ +#ifndef _410KERN_MULTIBOOT_UTILS_H_ +#define _410KERN_MULTIBOOT_UTILS_H_ + +#include +#include + +void mb_util_cmdline(mbinfo_t *, int *, char ***, char ***); +void mb_util_lmm(mbinfo_t *, lmm_t *); + +#endif diff --git a/410kern/boot/util_cmdline.c b/410kern/boot/util_cmdline.c new file mode 100644 index 0000000..5fef70e --- /dev/null +++ b/410kern/boot/util_cmdline.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include +#include +#include +#include +#include + + /* Note that this system uses _malloc to grab memory before the whole + * environment is up and running. + * + * Requires that malloc_lmm is initialized somehow (see mb_util_lmm). + */ + +static char prog_name[] = "kernel"; +static char *null_args[2] = {prog_name, 0}; + +static const char delim[] = " \f\n\r\t\v"; + +void mb_util_cmdline(mbinfo_t *mbi, int *argc, char ***argv, char ***envp) +{ + + if (mbi->flags & MULTIBOOT_CMDLINE) + { + char *cl = (char*)phystokv(mbi->cmdline); + unsigned cllen = strlen(cl); + char *targ[1 + cllen], *tvar[cllen]; + unsigned narg = 0, nvar = 0; + char *tok; + + /* Parse out the tokens in the command line. + XXX Might be good to handle quotes. */ + for (tok = strtok(cl, delim); tok; tok = strtok(0, delim)) + { + if (strchr(tok, '=')) + tvar[nvar++] = tok; + else + targ[narg++] = tok; + } + + /* Copy the pointer arrays to permanent heap memory. */ + *argv = _malloc(sizeof(char*) * (narg + nvar + 2)); + if (!*argv) panic("No memory to parse command line"); + + memcpy(*argv, targ, sizeof(char*) * narg); + (*argv)[narg] = 0; + *argc = narg; + + *envp = &((*argv)[narg+1]); + memcpy(*envp, tvar, sizeof(char*) * nvar); + (*envp)[nvar] = 0; + } + else + { + /* No command line. */ + *argc = 1; + *argv = null_args; + *envp = null_args + 1; + } +} + diff --git a/410kern/boot/util_lmm.c b/410kern/boot/util_lmm.c new file mode 100644 index 0000000..7a304bd --- /dev/null +++ b/410kern/boot/util_lmm.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include +#include +#include + +/* The 410 world does not care about memory in this much detail. If we + * ever start caring this much, these definitions should move back + * to their own header file so that other users of LMM can see them + * too. + * + * At the momemnt, though, given only malloc, these are somewhat silly. + */ + +/* + * <1MB memory is most precious, then <16MB memory, then high memory. + * Assign priorities to each region accordingly + * so that high memory will be used first when possible, + * then 16MB memory, then 1MB memory. + */ +#define LMM_PRI_1MB -2 +#define LMM_PRI_16MB -1 +#define LMM_PRI_HIGH 0 + +/* + * For memory <1MB, both LMMF_1MB and LMMF_16MB will be set. + * For memory from 1MB to 16MB, only LMMF_16MB will be set. + * For all memory higher than that, neither will be set. + */ +#define LMMF_1MB 0x01 +#define LMMF_16MB 0x02 + +static struct lmm_region reg1mb, reg16mb, reghigh; + +#define skip(hole_min, hole_max) \ + if ((max > (hole_min)) && (min < (hole_max))) \ + { \ + if (min < (hole_min)) max = (hole_min); \ + else { min = (hole_max); goto retry; } \ + } + +void mb_util_lmm (mbinfo_t *mbi, lmm_t *lmm) +{ + vm_offset_t min; + extern char _start[], end[]; + + /* Memory regions to skip. */ + vm_offset_t cmdline_start_pa = mbi->flags & MULTIBOOT_CMDLINE + ? mbi->cmdline : 0; + vm_offset_t cmdline_end_pa = cmdline_start_pa + ? cmdline_start_pa+strlen((char*)phystokv(cmdline_start_pa))+1 + : 0; + + /* Initialize the base memory allocator + according to the PC's physical memory regions. */ + lmm_init(lmm); + + /* Do the x86 init dance to build our initial regions */ + lmm_add_region(&malloc_lmm, ®1mb, + (void*)phystokv(0x00000000), 0x00100000, + LMMF_1MB | LMMF_16MB, LMM_PRI_1MB); + lmm_add_region(&malloc_lmm, ®16mb, + (void*)phystokv(0x00100000), 0x00f00000, + LMMF_16MB, LMM_PRI_16MB); + lmm_add_region(&malloc_lmm, ®high, + (void*)phystokv(0x01000000), 0xfeffffff, + 0, LMM_PRI_HIGH); + + /* Add to the free list all the memory the boot loader told us about, + carefully avoiding the areas occupied by boot information. + as well as our own executable code, data, and bss. + Start at the end of the BIOS data area. */ + min = 0x500; + do + { + vm_offset_t max = 0xffffffff; + + /* Skip the I/O and ROM area. */ + skip(mbi->mem_lower * 1024, 0x100000); + + /* Stop at the end of upper memory. */ + skip(0x100000 + mbi->mem_upper * 1024, 0xffffffff); + + /* Skip our own text, data, and bss. */ + skip(kvtophys(_start), kvtophys(end)); + + /* FIXME: temporary state of affairs */ + extern char __kimg_start[]; + skip(kvtophys(__kimg_start), kvtophys(end)); + + /* Skip the important stuff the bootloader passed to us. */ + skip(cmdline_start_pa, cmdline_end_pa); + if ((mbi->flags & MULTIBOOT_MODS) + && (mbi->mods_count > 0)) + { + struct multiboot_module *m = (struct multiboot_module*) + phystokv(mbi->mods_addr); + unsigned i; + + skip(mbi->mods_addr, + mbi->mods_addr + + mbi->mods_count * sizeof(*m)); + for (i = 0; i < mbi->mods_count; i++) + { + if (m[i].string != 0) + { + char *s = (char*)phystokv(m[i].string); + unsigned len = strlen(s); + skip(m[i].string, m[i].string+len+1); + } + skip(m[i].mod_start, m[i].mod_end); + } + } + + /* We actually found a contiguous memory block + that doesn't conflict with anything else! Whew! + Add it to the free list. */ + lmm_add_free(&malloc_lmm, (void *) min, max - min); + + /* Continue searching just past the end of this region. */ + min = max; + + /* The skip() macro jumps to this label + to restart with a different (higher) min address. */ + retry:; + } + while (min < 0xffffffff); +} + diff --git a/410kern/bootfd.img.gz b/410kern/bootfd.img.gz new file mode 100644 index 0000000..f597dc5 Binary files /dev/null and b/410kern/bootfd.img.gz differ diff --git a/410kern/elf/elf32.h b/410kern/elf/elf32.h new file mode 100644 index 0000000..55507c4 --- /dev/null +++ b/410kern/elf/elf32.h @@ -0,0 +1,245 @@ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.2 2007/12/03 21:30:36 marius Exp $ + */ + +#ifndef _SYS_ELF32_H_ +#define _SYS_ELF32_H_ 1 + +#include + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint64_t Elf32_Lword; + +typedef Elf32_Word Elf32_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Sword Elf32_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Word sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Word sh_addralign; /* Alignment in bytes. */ + Elf32_Word sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Word p_filesz; /* Size of contents in file. */ + Elf32_Word p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Word p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Note entry header + */ +typedef Elf_Note Elf32_Nhdr; + +/* + * Move entry + */ +typedef struct { + Elf32_Lword m_value; /* symbol value */ + Elf32_Word m_info; /* size + index */ + Elf32_Word m_poffset; /* symbol offset */ + Elf32_Half m_repeat; /* repeat count */ + Elf32_Half m_stride; /* stride info */ +} Elf32_Move; + +/* + * The macros compose and decompose values for Move.r_info + * + * sym = ELF32_M_SYM(M.m_info) + * size = ELF32_M_SIZE(M.m_info) + * M.m_info = ELF32_M_INFO(sym, size) + */ +#define ELF32_M_SYM(info) ((info)>>8) +#define ELF32_M_SIZE(info) ((unsigned char)(info)) +#define ELF32_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size)) + +/* + * Hardware/Software capabilities entry + */ +typedef struct { + Elf32_Word c_tag; /* how to interpret value */ + union { + Elf32_Word c_val; + Elf32_Addr c_ptr; + } c_un; +} Elf32_Cap; + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* Structures used by Sun & GNU symbol versioning. */ +typedef struct +{ + Elf32_Half vd_version; + Elf32_Half vd_flags; + Elf32_Half vd_ndx; + Elf32_Half vd_cnt; + Elf32_Word vd_hash; + Elf32_Word vd_aux; + Elf32_Word vd_next; +} Elf32_Verdef; + +typedef struct +{ + Elf32_Word vda_name; + Elf32_Word vda_next; +} Elf32_Verdaux; + +typedef struct +{ + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct +{ + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef Elf32_Half Elf32_Versym; + +typedef struct { + Elf32_Half si_boundto; /* direct bindings - symbol bound to */ + Elf32_Half si_flags; /* per symbol flags */ +} Elf32_Syminfo; + +#endif /* !_SYS_ELF32_H_ */ diff --git a/410kern/elf/elf_410.h b/410kern/elf/elf_410.h new file mode 100644 index 0000000..6fa13f4 --- /dev/null +++ b/410kern/elf/elf_410.h @@ -0,0 +1,39 @@ +/* The authorship of the 410 simplified ELF structure seems to be lost to time + * immemorial. This file has been rescued and broken out to stand on its own. + */ + +#ifndef _ELF_ELF_410_H_ +#define _ELF_ELF_410_H_ + +#include + +/* --- Simplified ELF header --- */ +typedef struct simple_elf { + const char * e_fname; /* filename of binary */ + unsigned long e_entry; /* entry point virtual address */ + unsigned long e_txtoff; /* offset of text segment in file */ + unsigned long e_txtlen; /* length of text segment in bytes */ + unsigned long e_txtstart; /* start of text segment virtual address */ + unsigned long e_datoff; /* offset of data segment in file */ + unsigned long e_datlen; /* length of data segment in bytes */ + unsigned long e_datstart; /* start of data segment in virtual memory */ + unsigned long e_rodatoff; /* offset of rodata segment in file */ + unsigned long e_rodatlen; /* length of rodata segment in bytes */ + unsigned long e_rodatstart; /* start of rodata segment in virtual memory*/ + unsigned long e_bsslen; /* length of bss segment in bytes */ + unsigned long e_bssstart; /* start of bss segment in virtual memory */ +} simple_elf_t; + + /* --- Defines --- */ +#define ELF_NOTELF -1 +#define ELF_SUCCESS 0 +#define NOT_PRESENT -2 + +/* + * elf function prototypes + */ +extern int getbytes( const char *filename, int offset, int size, char *buf); +extern int elf_load_helper( simple_elf_t *se_hdr, const char *fname ); +extern int elf_check_header( const char *fname ); + +#endif diff --git a/410kern/elf/elf_common.h b/410kern/elf/elf_common.h new file mode 100644 index 0000000..5249234 --- /dev/null +++ b/410kern/elf/elf_common.h @@ -0,0 +1,866 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf_common.h,v 1.24 2008/08/02 01:20:10 imp Exp $ + */ + +#ifndef _SYS_ELF_COMMON_H_ +#define _SYS_ELF_COMMON_H_ 1 + +#include + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32_t n_namesz; /* Length of name. */ + uint32_t n_descsz; /* Length of descriptor. */ + uint32_t n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developers/gabi/latest/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* Open VMS */ +#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ +#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ +#define ET_LOOS 0xfe00 /* First operating system specific. */ +#define ET_HIOS 0xfeff /* Last operating system-specific. */ +#define ET_LOPROC 0xff00 /* First processor-specific. */ +#define ET_HIPROC 0xffff /* Last processor-specific. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ +#define EM_S370 9 /* IBM System/370. */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ +#define EM_PARISC 15 /* HP PA-RISC. */ +#define EM_VPP500 17 /* Fujitsu VPP500. */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus. */ +#define EM_960 19 /* Intel 80960. */ +#define EM_PPC 20 /* PowerPC 32-bit. */ +#define EM_PPC64 21 /* PowerPC 64-bit. */ +#define EM_S390 22 /* IBM System/390. */ +#define EM_V800 36 /* NEC V800. */ +#define EM_FR20 37 /* Fujitsu FR20. */ +#define EM_RH32 38 /* TRW RH-32. */ +#define EM_RCE 39 /* Motorola RCE. */ +#define EM_ARM 40 /* ARM. */ +#define EM_SH 42 /* Hitachi SH. */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit. */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ +#define EM_ARC 45 /* Argonaut RISC Core. */ +#define EM_H8_300 46 /* Hitachi H8/300. */ +#define EM_H8_300H 47 /* Hitachi H8/300H. */ +#define EM_H8S 48 /* Hitachi H8S. */ +#define EM_H8_500 49 /* Hitachi H8/500. */ +#define EM_IA_64 50 /* Intel IA-64 Processor. */ +#define EM_MIPS_X 51 /* Stanford MIPS-X. */ +#define EM_COLDFIRE 52 /* Motorola ColdFire. */ +#define EM_68HC12 53 /* Motorola M68HC12. */ +#define EM_MMA 54 /* Fujitsu MMA. */ +#define EM_PCP 55 /* Siemens PCP. */ +#define EM_NCPU 56 /* Sony nCPU. */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor. */ +#define EM_STARCORE 58 /* Motorola Star*Core processor. */ +#define EM_ME16 59 /* Toyota ME16 processor. */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor. */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ + +/* Non-standard or deprecated. */ +#define EM_486 6 /* Intel i486. */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_LOOS 0xff20 /* First operating system-specific. */ +#define SHN_HIOS 0xff3f /* Last operating system-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers. */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ +#define SHT_GROUP 17 /* Section group. */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_LOSUNW 0x6ffffff4 +#define SHT_SUNW_dof 0x6ffffff4 +#define SHT_SUNW_cap 0x6ffffff5 +#define SHT_SUNW_SIGNATURE 0x6ffffff6 +#define SHT_SUNW_ANNOTATE 0x6ffffff7 +#define SHT_SUNW_DEBUGSTR 0x6ffffff8 +#define SHT_SUNW_DEBUG 0x6ffffff9 +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_SUNW_verdef 0x6ffffffd +#define SHT_GNU_verdef 0x6ffffffd /* Symbol versions provided */ +#define SHT_SUNW_verneed 0x6ffffffe +#define SHT_GNU_verneed 0x6ffffffe /* Symbol versions required */ +#define SHT_SUNW_versym 0x6fffffff +#define SHT_GNU_versym 0x6fffffff /* Symbol version table */ +#define SHT_HISUNW 0x6fffffff +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_AMD64_UNWIND 0x70000001 /* unwind information */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_MERGE 0x10 /* Section may be merged. */ +#define SHF_STRINGS 0x20 /* Section contains strings. */ +#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ +#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ +#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ +#define SHF_GROUP 0x200 /* Member of section group. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* First OS-specific. */ +#define PT_SUNW_UNWIND 0x6464e550 /* amd64 UNWIND program header */ +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* describes the stack segment */ +#define PT_SUNWDTRACE 0x6ffffffc /* private */ +#define PT_SUNWCAP 0x6ffffffd /* hard/soft capabilities segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* Last OS-specific. */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ +#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific. */ + +/* Extended program header index. */ +#define PN_XNUM 0xffff + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ +#define DT_MAXPOSTAGS 34 /* number of positive tags */ +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_SUNW_AUXILIARY 0x6000000d /* symbol auxiliary name */ +#define DT_SUNW_RTLDINF 0x6000000e /* ld.so.1 info (private) */ +#define DT_SUNW_FILTER 0x6000000f /* symbol filter name */ +#define DT_SUNW_CAP 0x60000010 /* hardware/software */ +#define DT_HIOS 0x6ffff000 /* Last OS-specific */ + +/* + * DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + * Dyn.d_un.d_val field of the Elf*_Dyn structure. + */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_CHECKSUM 0x6ffffdf8 /* elf checksum */ +#define DT_PLTPADSZ 0x6ffffdf9 /* pltpadding size */ +#define DT_MOVEENT 0x6ffffdfa /* move table entry size */ +#define DT_MOVESZ 0x6ffffdfb /* move table size */ +#define DT_FEATURE_1 0x6ffffdfc /* feature holder */ +#define DT_POSFLAG_1 0x6ffffdfd /* flags for DT_* entries, effecting */ + /* the following DT_* entry. */ + /* See DF_P1_* definitions */ +#define DT_SYMINSZ 0x6ffffdfe /* syminfo table size (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* syminfo entry size (in bytes) */ +#define DT_VALRNGHI 0x6ffffdff + +/* + * DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + * Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + * + * If any adjustment is made to the ELF object after it has been + * built, these entries will need to be adjusted. + */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_CONFIG 0x6ffffefa /* configuration information */ +#define DT_DEPAUDIT 0x6ffffefb /* dependency auditing */ +#define DT_AUDIT 0x6ffffefc /* object auditing */ +#define DT_PLTPAD 0x6ffffefd /* pltpadding (sparcv9) */ +#define DT_MOVETAB 0x6ffffefe /* move table */ +#define DT_SYMINFO 0x6ffffeff /* syminfo table */ +#define DT_ADDRRNGHI 0x6ffffeff + +#define DT_VERSYM 0x6ffffff0 /* Address of versym section. */ +#define DT_RELACOUNT 0x6ffffff9 /* number of RELATIVE relocations */ +#define DT_RELCOUNT 0x6ffffffa /* number of RELATIVE relocations */ +#define DT_FLAGS_1 0x6ffffffb /* state flags - see DF_1_* defs */ +#define DT_VERDEF 0x6ffffffc /* Address of verdef section. */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of elems in verdef section */ +#define DT_VERNEED 0x6ffffffe /* Address of verneed section. */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of elems in verneed section */ + +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_DEPRECATED_SPARC_REGISTER 0x7000001 +#define DT_AUXILIARY 0x7ffffffd /* shared library auxiliary name */ +#define DT_USED 0x7ffffffe /* ignored - same as needed */ +#define DT_FILTER 0x7fffffff /* shared library filter name */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOOS 10 /* Reserved range for operating system */ +#define STB_HIOS 12 /* specific semantics. */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific semantics. */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_COMMON 5 /* Uninitialized common block. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_NUM 7 +#define STT_LOOS 10 /* Reserved range for operating system */ +#define STT_HIOS 12 /* specific semantics. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific semantics. */ + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0x0 /* Default visibility (see binding). */ +#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ +#define STV_HIDDEN 0x2 /* Not visible. */ +#define STV_PROTECTED 0x3 /* Visible but not preemptible. */ +#define STV_EXPORTED 0x4 +#define STV_SINGLETON 0x5 +#define STV_ELIMINATE 0x6 + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +/* Symbol versioning flags. */ +#define VER_DEF_CURRENT 1 +#define VER_DEF_IDX(x) VER_NDX(x) + +#define VER_FLG_BASE 0x01 +#define VER_FLG_WEAK 0x02 + +#define VER_NEED_CURRENT 1 +#define VER_NEED_WEAK (1u << 15) +#define VER_NEED_HIDDEN VER_NDX_HIDDEN +#define VER_NEED_IDX(x) VER_NDX(x) + +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 +#define VER_NDX_GIVEN 2 + +#define VER_NDX_HIDDEN (1u << 15) +#define VER_NDX(x) ((x) & ~(1u << 15)) + +#define CA_SUNW_NULL 0 +#define CA_SUNW_HW_1 1 /* first hardware capabilities entry */ +#define CA_SUNW_SF_1 2 /* first software capabilities entry */ + +/* + * Syminfo flag values + */ +#define SYMINFO_FLG_DIRECT 0x0001 /* symbol ref has direct association */ + /* to object containing defn. */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* ignored - see SYMINFO_FLG_FILTER */ +#define SYMINFO_FLG_COPY 0x0004 /* symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* object containing defn should be */ + /* lazily-loaded */ +#define SYMINFO_FLG_DIRECTBIND 0x0010 /* ref should be bound directly to */ + /* object containing defn. */ +#define SYMINFO_FLG_NOEXTDIRECT 0x0020 /* don't let an external reference */ + /* directly bind to this symbol */ +#define SYMINFO_FLG_FILTER 0x0002 /* symbol ref is associated to a */ +#define SYMINFO_FLG_AUXILIARY 0x0040 /* standard or auxiliary filter */ + +/* + * Syminfo.si_boundto values. + */ +#define SYMINFO_BT_SELF 0xffff /* symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* symbol bound to parent */ +#define SYMINFO_BT_NONE 0xfffd /* no special symbol binding */ +#define SYMINFO_BT_EXTERN 0xfffc /* symbol defined as external */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* beginning of reserved entries */ + +/* + * Syminfo version values. + */ +#define SYMINFO_NONE 0 /* Syminfo version */ +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* + * Relocation types. + * + * All machine architectures are defined here to allow tools on one to + * handle others. + */ + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +/* Name Value Field Calculation */ +#define R_IA_64_NONE 0 /* None */ +#define R_IA_64_IMM14 0x21 /* immediate14 S + A */ +#define R_IA_64_IMM22 0x22 /* immediate22 S + A */ +#define R_IA_64_IMM64 0x23 /* immediate64 S + A */ +#define R_IA_64_DIR32MSB 0x24 /* word32 MSB S + A */ +#define R_IA_64_DIR32LSB 0x25 /* word32 LSB S + A */ +#define R_IA_64_DIR64MSB 0x26 /* word64 MSB S + A */ +#define R_IA_64_DIR64LSB 0x27 /* word64 LSB S + A */ +#define R_IA_64_GPREL22 0x2a /* immediate22 @gprel(S + A) */ +#define R_IA_64_GPREL64I 0x2b /* immediate64 @gprel(S + A) */ +#define R_IA_64_GPREL32MSB 0x2c /* word32 MSB @gprel(S + A) */ +#define R_IA_64_GPREL32LSB 0x2d /* word32 LSB @gprel(S + A) */ +#define R_IA_64_GPREL64MSB 0x2e /* word64 MSB @gprel(S + A) */ +#define R_IA_64_GPREL64LSB 0x2f /* word64 LSB @gprel(S + A) */ +#define R_IA_64_LTOFF22 0x32 /* immediate22 @ltoff(S + A) */ +#define R_IA_64_LTOFF64I 0x33 /* immediate64 @ltoff(S + A) */ +#define R_IA_64_PLTOFF22 0x3a /* immediate22 @pltoff(S + A) */ +#define R_IA_64_PLTOFF64I 0x3b /* immediate64 @pltoff(S + A) */ +#define R_IA_64_PLTOFF64MSB 0x3e /* word64 MSB @pltoff(S + A) */ +#define R_IA_64_PLTOFF64LSB 0x3f /* word64 LSB @pltoff(S + A) */ +#define R_IA_64_FPTR64I 0x43 /* immediate64 @fptr(S + A) */ +#define R_IA_64_FPTR32MSB 0x44 /* word32 MSB @fptr(S + A) */ +#define R_IA_64_FPTR32LSB 0x45 /* word32 LSB @fptr(S + A) */ +#define R_IA_64_FPTR64MSB 0x46 /* word64 MSB @fptr(S + A) */ +#define R_IA_64_FPTR64LSB 0x47 /* word64 LSB @fptr(S + A) */ +#define R_IA_64_PCREL60B 0x48 /* immediate60 form1 S + A - P */ +#define R_IA_64_PCREL21B 0x49 /* immediate21 form1 S + A - P */ +#define R_IA_64_PCREL21M 0x4a /* immediate21 form2 S + A - P */ +#define R_IA_64_PCREL21F 0x4b /* immediate21 form3 S + A - P */ +#define R_IA_64_PCREL32MSB 0x4c /* word32 MSB S + A - P */ +#define R_IA_64_PCREL32LSB 0x4d /* word32 LSB S + A - P */ +#define R_IA_64_PCREL64MSB 0x4e /* word64 MSB S + A - P */ +#define R_IA_64_PCREL64LSB 0x4f /* word64 LSB S + A - P */ +#define R_IA_64_LTOFF_FPTR22 0x52 /* immediate22 @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR64I 0x53 /* immediate64 @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR32MSB 0x54 /* word32 MSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR32LSB 0x55 /* word32 LSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR64MSB 0x56 /* word64 MSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR64LSB 0x57 /* word64 LSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_SEGREL32MSB 0x5c /* word32 MSB @segrel(S + A) */ +#define R_IA_64_SEGREL32LSB 0x5d /* word32 LSB @segrel(S + A) */ +#define R_IA_64_SEGREL64MSB 0x5e /* word64 MSB @segrel(S + A) */ +#define R_IA_64_SEGREL64LSB 0x5f /* word64 LSB @segrel(S + A) */ +#define R_IA_64_SECREL32MSB 0x64 /* word32 MSB @secrel(S + A) */ +#define R_IA_64_SECREL32LSB 0x65 /* word32 LSB @secrel(S + A) */ +#define R_IA_64_SECREL64MSB 0x66 /* word64 MSB @secrel(S + A) */ +#define R_IA_64_SECREL64LSB 0x67 /* word64 LSB @secrel(S + A) */ +#define R_IA_64_REL32MSB 0x6c /* word32 MSB BD + A */ +#define R_IA_64_REL32LSB 0x6d /* word32 LSB BD + A */ +#define R_IA_64_REL64MSB 0x6e /* word64 MSB BD + A */ +#define R_IA_64_REL64LSB 0x6f /* word64 LSB BD + A */ +#define R_IA_64_LTV32MSB 0x74 /* word32 MSB S + A */ +#define R_IA_64_LTV32LSB 0x75 /* word32 LSB S + A */ +#define R_IA_64_LTV64MSB 0x76 /* word64 MSB S + A */ +#define R_IA_64_LTV64LSB 0x77 /* word64 LSB S + A */ +#define R_IA_64_PCREL21BI 0x79 /* immediate21 form1 S + A - P */ +#define R_IA_64_PCREL22 0x7a /* immediate22 S + A - P */ +#define R_IA_64_PCREL64I 0x7b /* immediate64 S + A - P */ +#define R_IA_64_IPLTMSB 0x80 /* function descriptor MSB special */ +#define R_IA_64_IPLTLSB 0x81 /* function descriptor LSB speciaal */ +#define R_IA_64_SUB 0x85 /* immediate64 A - S */ +#define R_IA_64_LTOFF22X 0x86 /* immediate22 special */ +#define R_IA_64_LDXMOV 0x87 /* immediate22 special */ +#define R_IA_64_TPREL14 0x91 /* imm14 @tprel(S + A) */ +#define R_IA_64_TPREL22 0x92 /* imm22 @tprel(S + A) */ +#define R_IA_64_TPREL64I 0x93 /* imm64 @tprel(S + A) */ +#define R_IA_64_TPREL64MSB 0x96 /* word64 MSB @tprel(S + A) */ +#define R_IA_64_TPREL64LSB 0x97 /* word64 LSB @tprel(S + A) */ +#define R_IA_64_LTOFF_TPREL22 0x9a /* imm22 @ltoff(@tprel(S+A)) */ +#define R_IA_64_DTPMOD64MSB 0xa6 /* word64 MSB @dtpmod(S + A) */ +#define R_IA_64_DTPMOD64LSB 0xa7 /* word64 LSB @dtpmod(S + A) */ +#define R_IA_64_LTOFF_DTPMOD22 0xaa /* imm22 @ltoff(@dtpmod(S+A)) */ +#define R_IA_64_DTPREL14 0xb1 /* imm14 @dtprel(S + A) */ +#define R_IA_64_DTPREL22 0xb2 /* imm22 @dtprel(S + A) */ +#define R_IA_64_DTPREL64I 0xb3 /* imm64 @dtprel(S + A) */ +#define R_IA_64_DTPREL32MSB 0xb4 /* word32 MSB @dtprel(S + A) */ +#define R_IA_64_DTPREL32LSB 0xb5 /* word32 LSB @dtprel(S + A) */ +#define R_IA_64_DTPREL64MSB 0xb6 /* word64 MSB @dtprel(S + A) */ +#define R_IA_64_DTPREL64LSB 0xb7 /* word64 LSB @dtprel(S + A) */ +#define R_IA_64_LTOFF_DTPREL22 0xba /* imm22 @ltoff(@dtprel(S+A)) */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ +#define R_MIPS_GOTHI16 21 /* GOT HI 16 bit */ +#define R_MIPS_GOTLO16 22 /* GOT LO 16 bit */ +#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ +#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ + +#define R_PPC_NONE 0 /* No relocation. */ +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* + * TLS relocations + */ +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 + +/* + * The remaining relocs are from the Embedded ELF ABI, and are not in the + * SVR4 ELF ABI. + */ + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ + + +#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/410kern/elf/kernel.mk b/410kern/elf/kernel.mk new file mode 100644 index 0000000..23494f0 --- /dev/null +++ b/410kern/elf/kernel.mk @@ -0,0 +1,9 @@ +410K_ELF_OBJS := \ + load_helper.o + +410K_ELF_OBJS := $(410K_ELF_OBJS:%=$(410KDIR)/elf/%) + +ALL_410KOBJS += $(410K_ELF_OBJS) +410KCLEANS += $(410KDIR)/libelf.a + +$(410KDIR)/libelf.a: $(410K_ELF_OBJS) diff --git a/410kern/elf/load_helper.c b/410kern/elf/load_helper.c new file mode 100644 index 0000000..f234391 --- /dev/null +++ b/410kern/elf/load_helper.c @@ -0,0 +1,212 @@ +/** + * The 15-410 kernel project. + * @name 410loader.c + * + * Functions for the loading + * of user programs from binary + * files should be written in + * this file. The function + * elf_load_helper() is provided + * for your use. + */ +/*@{*/ + +/* --- Includes --- */ +#include +#include + /** FIXME: Should probably use something other than lprintf? */ +#include +#include +#include + +#define MAX_SECTION_NAME_LEN 10 /* longer than any we care about */ + +/** + * Checks to see if file with name fname is an elf + * executable binary. If so, fills in se_hdr struct + * and returns ELF_SUCCESS. If not, returns ELF_NOTELF. + * Assumes that the magic numbers in the header have been + * verified. + * + * @param se_hdr pointer to simple_elf_t struct to be + * filled in. Memory for it has been + * allocated. + * + * @param fname name of file to use. + * + * @return ELF_SUCCESS if se_hdr was successfully filled in. + * ELF_NOTELF if the file is not the kind of binary + * we are using in 15-410. + */ +int +elf_load_helper(simple_elf_t *se_hdr, const char *fname) +{ + Elf32_Ehdr elf_hdr; /* elf header */ + Elf32_Shdr elf_sec_hdr; /* section header */ + int ret; /* various return values */ + unsigned int i; /* loop index */ + + memset(se_hdr, 0, sizeof(simple_elf_t)); + + /* + * Grab the elf header + */ + ret = getbytes(fname, 0, sizeof(Elf32_Ehdr), (char *)&elf_hdr); + if (ret != sizeof(Elf32_Ehdr)) { + lprintf("Loader: Couldn't read elf header: %d, %s", ret, fname); + return ELF_NOTELF; + } + + /* + * grab the entry point and file name. + */ + se_hdr->e_entry = elf_hdr.e_entry; + se_hdr->e_fname = fname; + + + /* + * I want the section header string table first + * so I know what other entries are. + */ + ret = getbytes(fname, + elf_hdr.e_shoff + elf_hdr.e_shstrndx*sizeof(Elf32_Shdr), + sizeof(Elf32_Shdr), + (char *)&elf_sec_hdr); + if (ret != sizeof(Elf32_Shdr)) { + lprintf("Loader: could not read section header"); + return ELF_NOTELF; + } + + unsigned int string_offset = elf_sec_hdr.sh_offset; + + /* + * loop to find .text .rodata .data .bss section headers. + */ + for (i = 0; i < elf_hdr.e_shnum; i++) { + /* Read in the section */ + ret = getbytes(fname, + elf_hdr.e_shoff + i*sizeof(Elf32_Shdr), + sizeof(Elf32_Shdr), + (char *)&elf_sec_hdr); + if (ret != sizeof(Elf32_Shdr)) { + lprintf("Loader: could not read section header"); + return ELF_NOTELF; + } + + if (elf_sec_hdr.sh_name == SHN_UNDEF) { + continue; + } + + unsigned int str_idx = elf_sec_hdr.sh_name; + + /* Some annoying contortions to handle the unlikely case that + * the string table is at the very end of the file and so the + * read comes up short. + * We zero the section_name to make sure we don't compare + * against bogus data when this happens. */ + char section_name[MAX_SECTION_NAME_LEN]; + memset(section_name, 0, sizeof(section_name)); + ret = getbytes(fname, string_offset+str_idx, sizeof(section_name), + section_name); + if (ret < 0) { + lprintf("Loader: could not read section name"); + return ELF_NOTELF; + } + + if (strcmp(".text", section_name) == 0) { + /* + * This section header is for the text segment + */ + se_hdr->e_txtoff = elf_sec_hdr.sh_offset; + se_hdr->e_txtlen = elf_sec_hdr.sh_size; + se_hdr->e_txtstart = elf_sec_hdr.sh_addr; + } + else if (strcmp(".rodata", section_name) == 0) { + /* + * This section header is for the rodata segment + */ + se_hdr->e_rodatoff = elf_sec_hdr.sh_offset; + se_hdr->e_rodatlen = elf_sec_hdr.sh_size; + se_hdr->e_rodatstart = elf_sec_hdr.sh_addr; + } + else if (strcmp(".data", section_name) == 0) { + /* + * This section header is for the data segment + */ + se_hdr->e_datoff = elf_sec_hdr.sh_offset; + se_hdr->e_datlen = elf_sec_hdr.sh_size; + se_hdr->e_datstart = elf_sec_hdr.sh_addr; + } + else if (strcmp(".bss", section_name) == 0) { + /* + * This section header is for the bss segment + */ + se_hdr->e_bsslen = elf_sec_hdr.sh_size; + se_hdr->e_bssstart = elf_sec_hdr.sh_addr; + } + else if (strcmp(".symtab", section_name) != 0 && + strcmp(".strtab", section_name) != 0 && + strcmp(".shstrtab", section_name) != 0 && + strcmp(".stab", section_name) != 0 && + strcmp(".stabstr", section_name) != 0 && + strcmp(".comment", section_name) != 0 && + strcmp(".note", section_name) != 0 && + strcmp(".eh_frame", section_name) != 0 && + strncmp(".debug", section_name, sizeof(".debug")-1) != 0) { + lprintf("Loader: unknown header: \"%s\"", + section_name); + } + + } + + return ELF_SUCCESS; +} + +/** + * Checks fields in the potential ELF header to + * make sure that is actually and ELF header. + * + * @param fname file name of potential ELF binary + * + * @return ELF_SUCCESS if it is an ELF header. + * ELF_NOTELF if it isn't. + */ +int +elf_check_header(const char *fname) +{ + Elf32_Ehdr elf_hdr; + unsigned int ret; + + /* + * read the elf header from the file. + */ + ret = getbytes(fname, 0, sizeof(Elf32_Ehdr), (char *)&elf_hdr); + if (ret != sizeof(Elf32_Ehdr)) { + lprintf("Loader: Couldn't read elf header: %d, %s", ret, fname); + return ELF_NOTELF; + } + + if (memcmp(elf_hdr.e_ident, ELFMAG, SELFMAG) != 0) { + lprintf("Loader: bad magic"); + return ELF_NOTELF; + } + + if (elf_hdr.e_type != ET_EXEC) { + lprintf("Loader: bad structure"); + return ELF_NOTELF; + } + + if (elf_hdr.e_machine != EM_386) { + lprintf("Loader: bad target"); + return ELF_NOTELF; + } + + if (elf_hdr.e_version != EV_CURRENT) { + lprintf("Loader: bad version"); + return ELF_NOTELF; + } + + return ELF_SUCCESS; +} + +/*@}*/ diff --git a/410kern/entry.c b/410kern/entry.c new file mode 100644 index 0000000..cd9ed48 --- /dev/null +++ b/410kern/entry.c @@ -0,0 +1,111 @@ +/** @file boot/entry.c + * @brief Entry point for the C part of the kernel + * @author matthewj S2008 + * @author elly1 S2010 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* For FLUX compatibility; see lib/kvmphys.h */ +vm_offset_t phys_mem_va = 0; + +/* 410 interface compatibility */ +static int n_phys_frames = 0; + +/** @brief C entry point */ +void mb_entry(mbinfo_t *info, void *istack) { + int argc; + char **argv; + char **envp; + + /* Make sure mem_upper has been set by boot loader */ + assert(info->flags & MULTIBOOT_MEMORY); + + /* Want (kilobytes*1024)/PAGE_SIZE, but definitely avoid overflow */ + n_phys_frames = (info->mem_upper+1024)/(PAGE_SIZE/1024); + assert(n_phys_frames > (USER_MEM_START/PAGE_SIZE)); + + // LMM: init malloc_lmm and reserve memory holding this executable + mb_util_lmm(info, &malloc_lmm); + // LMM: don't give out memory under 1 megabyte + lmm_remove_free(&malloc_lmm, (void*)0, 0x100000); + // LMM: don't give out memory between USER_MEM_START and infinity + lmm_remove_free(&malloc_lmm, (void*)USER_MEM_START, -8 - USER_MEM_START); + + // lmm_dump(&malloc_lmm); + + mb_util_cmdline(info, &argc, &argv, &envp); + + // Having done that, let's tell Simics we've booted. + sim_booted(argv[0]); + + /* Disable floating-point unit: + * inadvisable for kernel, requires context-switch code for users + */ + set_cr0(get_cr0() | CR0_EM); + + /* Initialize the PIC so that IRQs use different IDT slots than + * CPU-defined exceptions. + */ + interrupt_setup(); + + kernel_main(info, argc, argv, envp); +} + +#include + +static int hv_guest_mode = 0; + +static unsigned int hv_max_vaddr = 0; + +/** @brief guest-mode C entry point */ +void hv_guest_entry(unsigned int maxframe, unsigned int maxvaddr) { + char *argv[] = { "kernel", "-guest", 0} ; + + n_phys_frames = maxframe - 4 + 1; /* XXX */ + assert(n_phys_frames > (USER_MEM_START/PAGE_SIZE)); + + // LMM init, short form + static struct lmm_region region; + extern char end[]; + lmm_init(&malloc_lmm); + lmm_add_region(&malloc_lmm, ®ion, 0, USER_MEM_START, 0, 1); // kvm + lmm_add_free(&malloc_lmm, end, (char *)USER_MEM_START - end); // available kvm + + hv_max_vaddr = maxvaddr; + + hv_guest_mode = 1; + + kernel_main(0, 2, argv, 0); +} + +int hv_isguest(void) +{ + return (hv_guest_mode); +} + +void * +hv_maxvaddr(void) +{ + if (!hv_guest_mode) + panic("hv_maxvaddr() called in host mode"); + + return ((void *)hv_max_vaddr); +} + +int +machine_phys_frames(void) +{ + return (n_phys_frames); +} diff --git a/410kern/inc/asm_style.h b/410kern/inc/asm_style.h new file mode 100644 index 0000000..6af13da --- /dev/null +++ b/410kern/inc/asm_style.h @@ -0,0 +1,126 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +#ifndef _ASM_STYLE_H_ +#define _ASM_STYLE_H_ + +/* 15-410 */ +#ifndef HAVE_P2ALIGN +#define HAVE_P2ALIGN +#endif +#ifndef __ELF__ +#define __ELF__ +#endif +/* 15-410 */ + +/* This is a more reliable delay than a few short jmps. */ +#define IODELAY pushl %eax; inb $0x80,%al; inb $0x80,%al; popl %eax + +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#ifdef i486 +#define TEXT_ALIGN 4 +#else +#define TEXT_ALIGN 2 +#endif +#define DATA_ALIGN 2 +#define ALIGN TEXT_ALIGN + +/* + * The .align directive has different meaning on the x86 when using ELF + * than when using a.out. + * Newer GNU as remedies this problem by providing .p2align and .balign. + */ +#if defined(HAVE_P2ALIGN) +# define P2ALIGN(p2) .p2align p2 +#elif defined(__ELF__) +# define P2ALIGN(p2) .align (1<<(p2)) +#else +# define P2ALIGN(p2) .align p2 +#endif + +#define LCL(x) x + +#define LB(x,n) n +#ifndef __ELF__ +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : +#define SEXT(x) "_"#x +#else +#define EXT(x) x +#define LEXT(x) x ## : +#define SEXT(x) #x +#endif +#define GLEXT(x) .globl EXT(x); LEXT(x) +#define LCLL(x) x ## : +#define gLB(n) n ## : +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f + + +/* Symbol types */ +#ifdef __ELF__ +#define FUNCSYM(x) .type x,@function +#else +#define FUNCSYM(x) /* nothing */ +#endif + + +#ifdef GPROF + +#define MCOUNT .data; gLB(9) .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); P2ALIGN(TEXT_ALIGN); LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + P2ALIGN(TEXT_ALIGN); LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; P2ALIGN(TEXT_ALIGN); gLB(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#else /* ndef GPROF */ + +#define MCOUNT +#define ENTRY(x) FUNCSYM(x); .globl EXT(x); P2ALIGN(TEXT_ALIGN); LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + P2ALIGN(TEXT_ALIGN); LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; P2ALIGN(TEXT_ALIGN); gLB(x) + +#endif /* ndef GPROF */ + + +#define Entry(x) P2ALIGN(TEXT_ALIGN); GLEXT(x) +#define DATA(x) P2ALIGN(DATA_ALIGN); GLEXT(x) + +#endif /* _ASM_STYLE_H_ */ diff --git a/410kern/inc/assert.h b/410kern/inc/assert.h new file mode 100644 index 0000000..0d989a8 --- /dev/null +++ b/410kern/inc/assert.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + * + * Author: Bryan Ford, University of Utah CSL + */ +#ifndef _ASSERT_H_ +#define _ASSERT_H_ + +extern void panic(const char *format, ...); + +#ifndef NDEBUG +#define assert(expression) do { \ + if(!(expression)) { \ + panic("%s:%u: failed assertion `%s'", __FILE__, __LINE__, #expression);\ + } \ +} while(0) +#else +#define assert(expression) ((void)0) +#endif + +/* Extended for 15-410 at Carnegie Mellon. + * + * The following conditions are checked even if NDEBUG is defined: + * affirm(3 > 0); + * affirm_msg(3 > 0, "arithmetic broken around %d and %d", 3, 0); + * reject(0 > 3); + * reject_msg(0 > 3, "arithmetic broken around %d and %d", 0, 3); + */ + +#define affirm(expression) do { \ + if(!(expression)) { \ + panic("%s:%u: failed affirmation `%s'", \ + __FILE__, __LINE__, #expression); \ + } \ +} while(0) + +#define reject(expression) do { \ + if(expression) { \ + panic("%s:%u: rejecting result `%s'", __FILE__, __LINE__, #expression);\ + } \ +} while(0) + +#define affirm_msg(expression, ...) do { \ + if(!(expression)) { \ + panic(__VA_ARGS__); \ + } \ +} while(0) + +#define reject_msg(expression, ...) \ + affirm_msg(!(expression), __VA_ARGS__) + +#endif /* _ASSERT_H_ */ diff --git a/410kern/inc/exec2obj.h b/410kern/inc/exec2obj.h new file mode 100644 index 0000000..2229c29 --- /dev/null +++ b/410kern/inc/exec2obj.h @@ -0,0 +1,29 @@ +/* + Name: exec2obj.h + Date: February 24th 2003 + Author: Steve Muckle + + Provides the interface to access user programs compiled as const char + arrays. +*/ + +#ifndef _EXEC2OBJ_H +#define _EXEC2OBJ_H + +#define MAX_EXECNAME_LEN 256 +#define MAX_NUM_APP_ENTRIES 256 + +/* Format of entries in the table of contents. */ +typedef struct { + const char execname[MAX_EXECNAME_LEN]; + const char* execbytes; + int execlen; +} exec2obj_userapp_TOC_entry; + +/* The number of user executables in the table of contents. */ +extern const int exec2obj_userapp_count; + +/* The table of contents. */ +extern const exec2obj_userapp_TOC_entry exec2obj_userapp_TOC[MAX_NUM_APP_ENTRIES]; + +#endif /* _EXEC2OBJ_H */ diff --git a/410kern/inc/kvmphys.h b/410kern/inc/kvmphys.h new file mode 100644 index 0000000..5554a90 --- /dev/null +++ b/410kern/inc/kvmphys.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +/* + * Definitions for the base VM environment provided by the OS toolkit: + * how to change pointers between physical, virtual, and linear addresses, etc. + */ +#ifndef _FLUX_X86_BASE_VM_H_ +#define _FLUX_X86_BASE_VM_H_ + +#include + +/** This variable is expected always to contain + * the kernel virtual address at which physical memory is mapped. + * It may change as paging is turned on or off. + * + * @note Provided by 410kern/entry.c, defaults to 0 as expected of the CS410 + * environment. + */ +extern vm_offset_t phys_mem_va; + +/* Calculate a kernel virtual address from a physical address. */ +#define phystokv(pa) ((vm_offset_t)(pa) + phys_mem_va) + +/* Same, but in reverse. + This only works for the region of kernel virtual addresses + that directly map physical addresses. */ +#define kvtophys(va) ((vm_offset_t)(va) - phys_mem_va) + +#endif /* _FLUX_X86_BASE_VM_H_ */ diff --git a/410kern/inc/malloc.h b/410kern/inc/malloc.h new file mode 100644 index 0000000..4a12e25 --- /dev/null +++ b/410kern/inc/malloc.h @@ -0,0 +1,16 @@ +#include +#include + +#ifndef _MALLOC_WRAPPERS_H_ +#define _MALLOC_WRAPPERS_H_ + +void *malloc(size_t size); +void *memalign(size_t alignment, size_t size); +void *calloc(size_t nelt, size_t eltsize); +void *realloc(void *buf, size_t new_size); +void free(void *buf); +void *smalloc(size_t size); +void *smemalign(size_t alignment, size_t size); +void sfree(void *buf, size_t size); + +#endif /* _MALLOC_WRAPPERS_H_ */ diff --git a/410kern/inc/stdarg.h b/410kern/inc/stdarg.h new file mode 100644 index 0000000..ba9add0 --- /dev/null +++ b/410kern/inc/stdarg.h @@ -0,0 +1,18 @@ +#ifndef _STDARG_H_ +#define _STDARG_H_ + +/* This is awful, but really these are compiler intrinsics, so we use the + * GNU compiler intrinsics. + */ + +#ifdef __GNUC__ +typedef __builtin_va_list va_list; +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) +#else +#error "Don't know how to use varargs not on GNUC, sorry." +#endif + +#endif diff --git a/410kern/inc/stdbool.h b/410kern/inc/stdbool.h new file mode 100644 index 0000000..5060f36 --- /dev/null +++ b/410kern/inc/stdbool.h @@ -0,0 +1,15 @@ +/** @file stdbool.h + * @author John Gallagher (gallaghe) + */ + +#ifndef _STDBOOL_H_ +#define _STDBOOL_H_ + +#define bool _Bool + +#define false 0 +#define true 1 + +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H_ */ diff --git a/410kern/inc/stddef.h b/410kern/inc/stddef.h new file mode 100644 index 0000000..b321b53 --- /dev/null +++ b/410kern/inc/stddef.h @@ -0,0 +1,12 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#include /* for size_t, ptrdiff_t */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define offsetof(stype,field) ((size_t)(&((stype*)NULL)->field)) + +#endif /* _STDDEF_H_ */ diff --git a/410kern/inc/stdint.h b/410kern/inc/stdint.h new file mode 100644 index 0000000..9bdf21c --- /dev/null +++ b/410kern/inc/stdint.h @@ -0,0 +1,114 @@ +/** @file lib/stdint.h + * + * @brief Standard integer type definitions + * + * @bug The standard integer state of our library is a little questionable. + * I think types.h has become a dumping ground for things that don't fit well, + * and some of that should move here/be deleted. + * It's missing a few things that it probably should have (wchar, ptrdiff + * sizing), but I think it should be fine until students actually use those + * features. + * + * @author matthewj S2008 + @author Matt Bryant (mbryant) S'16 + */ + +#ifndef LIB_STDINT_H +#define LIB_STDINT_H + +#ifndef ASSEMBLER + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long int32_t; +typedef signed long long int64_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; + +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; + +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +#endif /* !ASSEMBLER */ + +#define UINT8_C(x) (x) +#define UINT16_C(x) (x) +#define UINT32_C(x) (x ## U) +#define UINT64_C(x) (x ## ULL) + +#define INT8_C(x) (x) +#define INT16_C(x) (x) +#define INT32_C(x) (x) +#define INT64_C(x) (x ## LL) + +#define INTMAX_C(x) (x ## LL) +#define UINTMAX_C(x) (x ## ULL) + +#define INT8_MIN (-128) +#define INT8_MAX (127) +#define INT16_MIN (-32768) +#define INT16_MAX (32767) +#define INT32_MIN (0x80000000) +#define INT32_MAX (0x7FFFFFFF) +#define INT64_MIN (0x8000000000000000LL) +#define INT64_MAX (0x7FFFFFFFFFFFFFFFLL) + +#define UINT8_MAX (255) +#define UINT16_MAX (65535) +#define UINT32_MAX (0xFFFFFFFF) +#define UINT64_MAX (0xFFFFFFFFFFFFFFFFULL) + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#endif /* !LIB_STDINT_H */ diff --git a/410kern/inc/types.h b/410kern/inc/types.h new file mode 100644 index 0000000..eef2003 --- /dev/null +++ b/410kern/inc/types.h @@ -0,0 +1,23 @@ +/** @file lib/types.h + * @brief Defines some C standard types as well as + * wrapper types for some of the imported FLUX library code. + * @author matthewj S2008 + */ + +#ifndef LIB_TYPES_H +#define LIB_TYPES_H + +typedef unsigned int size_t; +typedef unsigned long ptrdiff_t; + +/* WRAPPERS */ + +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_t; + +typedef enum { + FALSE = 0, + TRUE +} boolean_t; + +#endif /* !LIB_TYPES_H */ diff --git a/410kern/kernel.lds b/410kern/kernel.lds new file mode 100644 index 0000000..3a2db5d --- /dev/null +++ b/410kern/kernel.lds @@ -0,0 +1,191 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +PHDRS { text PT_LOAD; } +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x08048000); . = 0x08058000; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } :text =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1)); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } + PROVIDE (__fini_array_end = .); + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker wold: kernel: Not enough room for program headers (allocated 3, need 4) +ld: final link failed: Bad value +n't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) } + . = DATA_SEGMENT_RELRO_END (12, .); + .got.plt : { *(.got.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .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) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* 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) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/410kern/kernel.mk b/410kern/kernel.mk new file mode 100644 index 0000000..35c18a9 --- /dev/null +++ b/410kern/kernel.mk @@ -0,0 +1,32 @@ +###################### LOCAL BUILD TARGETS ############################ +410KERNEL_OBJS = entry.o + +410KOBJS = $(410KERNEL_OBJS:%=$(410KDIR)/%) +ALL_410KOBJS += $(410KOBJS) + +410KLIBS = $(410KERNEL_LIBS:%=$(410KDIR)/%) +410KCLEANS += $(410KDIR)/partial_kernel.o + +$(410KDIR)/partial_kernel.o : $(410KOBJS) + $(LD) -r $(LDFLAGS) -o $@ $^ + +########################### LIBRARY INCLUSIONS ################################ +ifneq (,$(410KERNEL_LIBS)) +include $(patsubst lib%.a,$(410KDIR)/%/kernel.mk,$(410KERNEL_LIBS)) +endif + + +########################## STUDENT KERNEL BUILD ############################### + +STUKOBJS = $(KERNEL_OBJS:%=$(STUKDIR)/%) +ALL_STUKOBJS += $(STUKOBJS) + +STUKCLEANS += $(STUKDIR)/partial_kernel.o + +ifeq ($(STUKOBJS),) +$(STUKDIR)/partial_kernel.o : + touch $@ +else +$(STUKDIR)/partial_kernel.o : $(STUKOBJS) + $(LD) -r $(LDFLAGS) -o $@ $^ +endif diff --git a/410kern/lmm/README b/410kern/lmm/README new file mode 100644 index 0000000..80d277b --- /dev/null +++ b/410kern/lmm/README @@ -0,0 +1,50 @@ + + List-based Memory Manager (LMM) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is a flexible memory allocation/management module +designed along the lines of the Amiga's low level memory management system. +It differs from typical Unix malloc packages +in that it does not assume a Unix-like virtual memory environment, +where the heap comes in one big contiguous region that can be expanded arbitrarily on demand, +and where memory can be "wasted" freely because untouched pages are never paged in. +As such it is intended primarily for use in OS kernels and other system-level software. + +The LMM has the following main features: + +* Very efficient use of memory. + At most fourteen bytes are wasted in a given allocation + (because of alignment restrictions); + there is _no_ memory overhead for 8-byte aligned allocations. + +* Support for allocating memory with specific alignment properties. + Memory can be allocated at any given power-of-two boundary, + or at an arbitrary offset beyond a specified power-of-two boundary. + +* Support for allocations that must come from a specific address range. + For example, sometimes memory needs to be allocated specifically + from the first 16MB of physical memory, or from the first 1MB of memory. + +Its (potential) disadvantages are: + +* It requires the caller to remember the size of each allocated block, + and pass its size back as a parameter to lmm_free(). + Thus, a malloc() implemented on top of this memory manager + would have to remember the size of each block somewhere. + +* Since it uses a sequential search through what amounts to a single linked list, + allocations are not as blazingly fast + as in packages that maintain separate free lists for different sizes of blocks. + +* It does not know how to "grow" the free list automatically + (e.g. by calling sbrk() or some equivalent); + if it runs out of memory, the allocation simply fails. + +* It is not thread-safe - i.e. it does not contain any internal serialization code. + +If high-speed conventional memory allocation is needed, +conventional zone allocation techniques can be implemented on top of the LMM. + + +XXX make an "LMM pool" an ADT so there can be more than one in a program? + diff --git a/410kern/lmm/kernel.mk b/410kern/lmm/kernel.mk new file mode 100644 index 0000000..fa5d58c --- /dev/null +++ b/410kern/lmm/kernel.mk @@ -0,0 +1,21 @@ +410K_LMM_OBJS := \ + lmm_add_free.o \ + lmm_add_region.o \ + lmm_alloc.o \ + lmm_alloc_aligned.o \ + lmm_alloc_gen.o \ + lmm_alloc_page.o \ + lmm_avail.o \ + lmm_dump.o \ + lmm_find_free.o \ + lmm_free.o \ + lmm_free_page.o \ + lmm_init.o \ + lmm_remove_free.o \ + +410K_LMM_OBJS := $(410K_LMM_OBJS:%=$(410KDIR)/lmm/%) + +ALL_410KOBJS += $(410K_LMM_OBJS) +410KCLEANS += $(410KDIR)/liblmm.a + +$(410KDIR)/liblmm.a: $(410K_LMM_OBJS) diff --git a/410kern/lmm/lmm.h b/410kern/lmm/lmm.h new file mode 100644 index 0000000..0ad9a93 --- /dev/null +++ b/410kern/lmm/lmm.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + * + * Author: Bryan Ford, University of Utah CSL + */ +/* + * Public header file for the List Memory Manager. + */ +#ifndef _MACH_LMM_H_ +#define _MACH_LMM_H_ + +#include + +/* The contents of this structure is opaque to users. */ +typedef struct lmm +{ + struct lmm_region *regions; +} lmm_t; + +typedef struct lmm_region lmm_region_t; + +#define LMM_INITIALIZER { 0 } + +typedef unsigned int lmm_flags_t; +typedef unsigned int lmm_pri_t; + +void lmm_init(lmm_t *lmm); +void lmm_add_region(lmm_t *lmm, lmm_region_t *lmm_region, + void *addr, vm_size_t size, + lmm_flags_t flags, lmm_pri_t pri); +void lmm_add_free(lmm_t *lmm, void *block, vm_size_t size); +void lmm_remove_free(lmm_t *lmm, void *block, vm_size_t size); +void *lmm_alloc(lmm_t *lmm, vm_size_t size, lmm_flags_t flags); +void *lmm_alloc_aligned(lmm_t *lmm, vm_size_t size, lmm_flags_t flags, + int align_bits, vm_offset_t align_ofs); +void *lmm_alloc_page(lmm_t *lmm, lmm_flags_t flags); +void *lmm_alloc_gen(lmm_t *lmm, vm_size_t size, lmm_flags_t flags, + int align_bits, vm_offset_t align_ofs, + vm_offset_t bounds_min, vm_offset_t bounds_max); +vm_size_t lmm_avail(lmm_t *lmm, lmm_flags_t flags); +void lmm_find_free(lmm_t *lmm, vm_offset_t *inout_addr, + vm_size_t *out_size, lmm_flags_t *out_flags); +void lmm_free(lmm_t *lmm, void *block, vm_size_t size); +void lmm_free_page(lmm_t *lmm, void *block); + +void lmm_dump(lmm_t *lmm); + +#endif /* _MACH_LMM_H_ */ diff --git a/410kern/lmm/lmm_add_free.c b/410kern/lmm/lmm_add_free.c new file mode 100644 index 0000000..8292431 --- /dev/null +++ b/410kern/lmm/lmm_add_free.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +/* Tiny blocks are not worth the space/time cost to track. */ +#define LMM_MIN_USEFUL (2 * 1024) + +void lmm_add_free(lmm_t *lmm, void *block, vm_size_t size) +{ + struct lmm_region *reg; + vm_offset_t min = (vm_offset_t)block; + vm_offset_t max = min + size; + + if (max - min < LMM_MIN_USEFUL) + { + return; + } + + /* Restrict the min and max further to be properly aligned. + Note that this is the opposite of what lmm_free() does, + because lmm_free() assumes the block was allocated with lmm_alloc() + and thus would be a subset of a larger, already-aligned free block. + Here we can assume no such thing. */ + min = (min + ALIGN_MASK) & ~ALIGN_MASK; + max &= ~ALIGN_MASK; + assert(max >= min); + + /* If after alignment we have nothing left, we're done. */ + if (max == min) + return; + + /* Add the block to the free list(s) of whatever region(s) it overlaps. + If some or all of the block doesn't fall into any existing region, + then that memory is simply dropped on the floor. */ + for (reg = lmm->regions; reg; reg = reg->next) + { + assert(reg->min < reg->max); + assert((reg->min & ALIGN_MASK) == 0); + assert((reg->max & ALIGN_MASK) == 0); + + if ((max > reg->min) && (min < reg->max)) + { + vm_offset_t new_min = min, new_max = max; + + /* Only add the part of the block + that actually falls within this region. */ + if (new_min < reg->min) + new_min = reg->min; + if (new_max > reg->max) + new_max = reg->max; + assert(new_max > new_min); + + /* Add the block. */ + lmm_free(lmm, (void*)new_min, new_max - new_min); + } + } +} + diff --git a/410kern/lmm/lmm_add_region.c b/410kern/lmm/lmm_add_region.c new file mode 100644 index 0000000..9b6e4af --- /dev/null +++ b/410kern/lmm/lmm_add_region.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +void lmm_add_region(lmm_t *lmm, lmm_region_t *reg, + void *addr, vm_size_t size, + lmm_flags_t flags, lmm_pri_t pri) +{ + vm_offset_t min = (vm_offset_t)addr; + vm_offset_t max = min + size; + struct lmm_region **rp, *r; + + /* Align the start and end addresses appropriately. */ + min = (min + ALIGN_MASK) & ~ALIGN_MASK; + max &= ~ALIGN_MASK; + + /* If there's not enough memory to do anything with, + then just drop the region on the floor. + Since we haven't put it on the lmm's list, + we'll never see it again. */ + if (max <= min) + return; + + /* Initialize the new region header. */ + reg->nodes = 0; + reg->min = min; + reg->max = max; + reg->flags = flags; + reg->pri = pri; + reg->free = 0; + + /* Add the region to the lmm's region list in descending priority order. + For regions with the same priority, sort from largest to smallest + to reduce the average amount of list traversing we need to do. */ + for (rp = &lmm->regions; + (r = *rp) && ((r->pri > pri) || + ((r->pri == pri) && + (r->max - r->min > reg->max - reg->min))); + rp = &r->next) + { + assert(r != reg); + /* Bugfix by nwf, also in later versions of LMM; regions are + * allowed to abut, so these should include equality as acceptable + * outcomes. + */ + assert((reg->max <= r->min) || (reg->min >= r->max)); + } + reg->next = r; + *rp = reg; +} + diff --git a/410kern/lmm/lmm_alloc.c b/410kern/lmm/lmm_alloc.c new file mode 100644 index 0000000..249bc5e --- /dev/null +++ b/410kern/lmm/lmm_alloc.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +void *lmm_alloc(lmm_t *lmm, vm_size_t size, lmm_flags_t flags) +{ + struct lmm_region *reg; + + assert(lmm != 0); + assert(size > 0); + + size = (size + ALIGN_MASK) & ~ALIGN_MASK; + + for (reg = lmm->regions; reg; reg = reg->next) + { + struct lmm_node **nodep, *node; + + assert((reg->nodes == 0 && reg->free == 0) + || ((vm_offset_t)reg->nodes >= reg->min)); + assert(reg->free >= 0); + assert(reg->free <= reg->max - reg->min); + + if (flags & ~reg->flags) + continue; + + for (nodep = ®->nodes; + (node = *nodep) != 0; + nodep = &node->next) + { + assert(((vm_offset_t)node & ALIGN_MASK) == 0); + assert(((vm_offset_t)node->size & ALIGN_MASK) == 0); + assert((node->next == 0) || (node->next > node)); + assert((vm_offset_t)node < reg->max); + + if (node->size >= size) + { + if (node->size > size) + { + struct lmm_node *newnode; + + /* Split the node and return its head */ + newnode = (struct lmm_node*) + ((void*)node + size); + newnode->next = node->next; + newnode->size = node->size - size; + *nodep = newnode; + } + else + { + /* Remove and return the entire node. */ + *nodep = node->next; + } + + /* Adjust the region's free memory counter. */ + assert(reg->free >= size); + reg->free -= size; + + return (void*)node; + } + } + } + + return 0; +} + diff --git a/410kern/lmm/lmm_alloc_aligned.c b/410kern/lmm/lmm_alloc_aligned.c new file mode 100644 index 0000000..8a04d38 --- /dev/null +++ b/410kern/lmm/lmm_alloc_aligned.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +void *lmm_alloc_aligned(lmm_t *lmm, vm_size_t size, lmm_flags_t flags, + int align_bits, vm_offset_t align_ofs) +{ + return lmm_alloc_gen(lmm, size, flags, + align_bits, align_ofs, + (vm_offset_t)0, (vm_size_t)-1); +} + diff --git a/410kern/lmm/lmm_alloc_gen.c b/410kern/lmm/lmm_alloc_gen.c new file mode 100644 index 0000000..a2fdb9c --- /dev/null +++ b/410kern/lmm/lmm_alloc_gen.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +void *lmm_alloc_gen(lmm_t *lmm, vm_size_t size, unsigned flags, + int align_bits, vm_offset_t align_ofs, + vm_offset_t in_min, vm_size_t in_size) +{ + vm_offset_t in_max = in_min + in_size; + struct lmm_region *reg; + +#if 0 + printf("lmm_alloc_gen %08x\n", size); + lmm_dump(lmm); +#endif + + assert(lmm != 0); + assert(size > 0); + + for (reg = lmm->regions; reg; reg = reg->next) + { + struct lmm_node **nodep, *node; + + assert((reg->nodes == 0 && reg->free == 0) + || ((vm_offset_t)reg->nodes >= reg->min)); + assert(reg->free >= 0); + assert(reg->free <= reg->max - reg->min); + + /* First trivially reject the entire region if possible. */ + if ((flags & ~reg->flags) + || (reg->min >= in_max) + || (reg->max <= in_min)) + continue; + + for (nodep = ®->nodes; + (node = *nodep) != 0; + nodep = &node->next) + { + vm_offset_t addr; + struct lmm_node *anode; + int i; + + assert(((vm_offset_t)node & ALIGN_MASK) == 0); + assert(((vm_offset_t)node->size & ALIGN_MASK) == 0); + assert((node->next == 0) || (node->next > node)); + assert((vm_offset_t)node < reg->max); + + /* Now make a first-cut trivial elimination check + to skip chunks that are _definitely_ too small. */ + if (node->size < size) + continue; + + /* Now compute the address at which + the allocated chunk would have to start. */ + addr = (vm_offset_t)node; + if (addr < in_min) + addr = in_min; + for (i = 0; i < align_bits; i++) + { + vm_offset_t bit = (vm_offset_t)1 << i; + if ((addr ^ align_ofs) & bit) + addr += bit; + } + + /* See if the block at the adjusted address + is still entirely within the node. */ + if ((addr - (vm_offset_t)node + size) > node->size) + continue; + + /* If the block extends past the range constraint, + then all of the rest of the nodes in this region + will extend past it too, so stop here. */ + if (addr + size > in_max) + break; + + /* OK, we can allocate the block from this node. */ + + /* If the allocation leaves at least ALIGN_SIZE + space before it, then split the node. */ + anode = (struct lmm_node*)(addr & ~ALIGN_MASK); + assert(anode >= node); + if (anode > node) + { + vm_size_t split_size = (vm_offset_t)anode + - (vm_offset_t)node; + assert((split_size & ALIGN_MASK) == 0); + anode->next = node->next; + anode->size = node->size - split_size; + node->size = split_size; + nodep = &node->next; + } + + /* Now use the first part of the anode + to satisfy the allocation, + splitting off the tail end if necessary. */ + size = ((addr & ALIGN_MASK) + size + ALIGN_MASK) + & ~ALIGN_MASK; + if (anode->size > size) + { + struct lmm_node *newnode; + + /* Split the node and return its head. */ + newnode = (struct lmm_node*) + ((void*)anode + size); + newnode->next = anode->next; + newnode->size = anode->size - size; + *nodep = newnode; + } + else + { + /* Remove and return the entire node. */ + *nodep = anode->next; + } + + /* Adjust the region's free memory counter. */ + assert(reg->free >= size); + reg->free -= size; + +#if 0 + printf("lmm_alloc_gen returning %08x\n", addr); + lmm_dump(lmm); +#endif + + return (void*)addr; + } + } + +#if 0 + printf("lmm_alloc_gen failed\n"); +#endif + + return 0; +} + diff --git a/410kern/lmm/lmm_alloc_page.c b/410kern/lmm/lmm_alloc_page.c new file mode 100644 index 0000000..cdba115 --- /dev/null +++ b/410kern/lmm/lmm_alloc_page.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +void *lmm_alloc_page(lmm_t *lmm, lmm_flags_t flags) +{ + return lmm_alloc_gen(lmm, PAGE_SIZE, flags, PAGE_SHIFT, 0, + (vm_offset_t)0, (vm_size_t)-1); +} + diff --git a/410kern/lmm/lmm_avail.c b/410kern/lmm/lmm_avail.c new file mode 100644 index 0000000..ee3b528 --- /dev/null +++ b/410kern/lmm/lmm_avail.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +vm_size_t lmm_avail(lmm_t *lmm, lmm_flags_t flags) +{ + struct lmm_region *reg; + vm_size_t count; + + count = 0; + for (reg = lmm->regions; reg; reg = reg->next) + { + assert((reg->nodes == 0) == (reg->free == 0)); + if (reg->nodes == 0) + continue; + assert((vm_offset_t)reg->nodes >= reg->min); + assert((vm_offset_t)reg->nodes < reg->max); + assert(reg->free >= 0); + assert(reg->free <= reg->max - reg->min); + + /* Don't count inapplicable regions. */ + if (flags & ~reg->flags) + continue; + + count += reg->free; + } + return count; +} + diff --git a/410kern/lmm/lmm_dump.c b/410kern/lmm/lmm_dump.c new file mode 100644 index 0000000..606c54f --- /dev/null +++ b/410kern/lmm/lmm_dump.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +/* + * Debugging routine: + * dump an LMM memory pool and do a thorough sanity check on it. + */ + +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +#include +#include + +void lmm_dump(lmm_t *lmm) +{ + struct lmm_region *reg; + + printf("lmm_dump(lmm=%p)\n", lmm); + + for (reg = lmm->regions; reg; reg = reg->next) + { + struct lmm_node *node; + vm_size_t free_check; + + printf(" region %08lx-%08lx size=%08lx flags=%08x pri=%d free=%08lx\n", + reg->min, reg->max, reg->max - reg->min, + reg->flags, reg->pri, reg->free); + + assert((reg->nodes == 0) + || (vm_offset_t)reg->nodes >= reg->min); + assert((reg->nodes ==0) || (vm_offset_t)reg->nodes < reg->max); + assert(reg->free >= 0); + assert(reg->free <= reg->max - reg->min); + + free_check = 0; + for (node = reg->nodes; node; node = node->next) + { + printf(" node %p-%08lx size=%08lx next=%p\n", + node, (vm_offset_t)node + node->size, node->size, node->next); + + assert(((vm_offset_t)node & ALIGN_MASK) == 0); + assert((node->size & ALIGN_MASK) == 0); + assert(node->size >= sizeof(*node)); + assert((node->next == 0) || (node->next > node)); + assert((vm_offset_t)node < reg->max); + + free_check += node->size; + } + + printf(" free_check=%08lx\n", free_check); + assert(reg->free == free_check); + } + + printf("lmm_dump done\n"); +} + diff --git a/410kern/lmm/lmm_find_free.c b/410kern/lmm/lmm_find_free.c new file mode 100644 index 0000000..f8ecf1d --- /dev/null +++ b/410kern/lmm/lmm_find_free.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#undef NDEBUG // LMM assert()s are O(1) and vital +#include +#include +#include + +void lmm_find_free(lmm_t *lmm, vm_offset_t *inout_addr, + vm_size_t *out_size, lmm_flags_t *out_flags) +{ + struct lmm_region *reg; + vm_offset_t start_addr = (*inout_addr + ALIGN_MASK) & ~ALIGN_MASK; + vm_offset_t lowest_addr = (vm_offset_t)-1; + vm_size_t lowest_size = 0; + unsigned lowest_flags = 0; + + for (reg = lmm->regions; reg; reg = reg->next) + { + struct lmm_node *node; + + if ((reg->nodes == 0) + || (reg->max <= start_addr) + || (reg->min > lowest_addr)) + continue; + + for (node = reg->nodes; node; node = node->next) + { + assert((vm_offset_t)node >= reg->min); + assert((vm_offset_t)node < reg->max); + + if ((vm_offset_t)node >= lowest_addr) + break; + if ((vm_offset_t)node + node->size > start_addr) + { + if ((vm_offset_t)node > start_addr) + { + lowest_addr = (vm_offset_t)node; + lowest_size = node->size; + } + else + { + lowest_addr = start_addr; + lowest_size = node->size + - (lowest_addr - (vm_offset_t)node); + } + lowest_flags = reg->flags; + break; + } + } + } + + *inout_addr = lowest_addr; + *out_size = lowest_size; + *out_flags = lowest_flags; +} + diff --git a/410kern/lmm/lmm_free.c b/410kern/lmm/lmm_free.c new file mode 100644 index 0000000..1483ee6 --- /dev/null +++ b/410kern/lmm/lmm_free.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#undef NDEBUG // LMM assert()s are O(1) and vital +#include +#include +#include + +void lmm_free(lmm_t *lmm, void *block, vm_size_t size) +{ + struct lmm_region *reg; + struct lmm_node *node = (struct lmm_node*) + ((vm_offset_t)block & ~ALIGN_MASK); + struct lmm_node *prevnode, *nextnode; + + assert(lmm != 0); + assert(block != 0); + assert(size > 0); + + size = (((vm_offset_t)block & ALIGN_MASK) + size + ALIGN_MASK) + & ~ALIGN_MASK; + + /* First find the region to add this block to. */ + for (reg = lmm->regions; ; reg = reg->next) + { + assert(reg != 0); + assert((reg->nodes == 0 && reg->free == 0) + || ((vm_offset_t)reg->nodes >= reg->min)); + + if (((vm_offset_t)node >= reg->min) + && ((vm_offset_t)node < reg->max)) + break; + } + + /* Record the newly freed space in the region's free space counter. */ + reg->free += size; + assert(reg->free <= reg->max - reg->min); + + /* Now find the location in that region's free list + at which to add the node. */ + for (prevnode = 0, nextnode = reg->nodes; + (nextnode != 0) && (nextnode < node); + prevnode = nextnode, nextnode = nextnode->next); + + /* Coalesce the new free chunk into the previous chunk if possible. */ + if ((prevnode) && + ((vm_offset_t)prevnode + prevnode->size >= (vm_offset_t)node)) + { + assert((vm_offset_t)prevnode + prevnode->size + == (vm_offset_t)node); + + /* Coalesce prevnode with nextnode if possible. */ + if (((vm_offset_t)nextnode) + && ((vm_offset_t)node + size >= (vm_offset_t)nextnode)) + { + assert((vm_offset_t)node + size + == (vm_offset_t)nextnode); + + prevnode->size += size + nextnode->size; + prevnode->next = nextnode->next; + } + else + { + /* Not possible - + just grow prevnode around newly freed memory. */ + prevnode->size += size; + } + } + else + { + /* Insert the new node into the free list. */ + if (prevnode) + prevnode->next = node; + else + reg->nodes = node; + + /* Try coalescing the new node with the nextnode. */ + if ((nextnode) && + (vm_offset_t)node + size >= (vm_offset_t)nextnode) + { + node->size = size + nextnode->size; + node->next = nextnode->next; + } + else + { + node->size = size; + node->next = nextnode; + } + } +} + diff --git a/410kern/lmm/lmm_free_page.c b/410kern/lmm/lmm_free_page.c new file mode 100644 index 0000000..169bffc --- /dev/null +++ b/410kern/lmm/lmm_free_page.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +void lmm_free_page(lmm_t *lmm, void *page) +{ + return lmm_free(lmm, page, PAGE_SIZE); +} + diff --git a/410kern/lmm/lmm_init.c b/410kern/lmm/lmm_init.c new file mode 100644 index 0000000..0b29779 --- /dev/null +++ b/410kern/lmm/lmm_init.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +void lmm_init(lmm_t *lmm) +{ + lmm->regions = 0; +} + diff --git a/410kern/lmm/lmm_remove_free.c b/410kern/lmm/lmm_remove_free.c new file mode 100644 index 0000000..8da33f6 --- /dev/null +++ b/410kern/lmm/lmm_remove_free.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#undef NDEBUG // LMM assert()s are O(1) and vital +#include + +void lmm_remove_free(lmm_t *lmm, void *block, vm_size_t block_size) +{ + vm_offset_t rstart = (vm_offset_t)block; + vm_offset_t rend = rstart + block_size; + assert(rend > rstart); + + while (rstart < rend) + { + vm_offset_t size; + lmm_flags_t flags; + void *ptr; + + lmm_find_free(lmm, &rstart, &size, &flags); + assert(rstart >= (vm_offset_t)block); + if ((size == 0) || (rstart >= rend)) + break; + if (rstart + size > rend) + size = rend - rstart; + ptr = lmm_alloc_gen(lmm, size, flags, 0, 0, + rstart, size); + assert((vm_offset_t)ptr == rstart); + } +} + diff --git a/410kern/lmm/lmm_types.h b/410kern/lmm/lmm_types.h new file mode 100644 index 0000000..2b6e82f --- /dev/null +++ b/410kern/lmm/lmm_types.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + * + * Author: Bryan Ford, University of Utah CSL + */ + +#ifndef _LMM_TYPES_H_ +#define _LMM_TYPES_H_ + +/* The contents of these structures are opaque to users. */ +struct lmm_region +{ + struct lmm_region *next; + + /* List of free memory blocks in this region. */ + struct lmm_node *nodes; + + /* Virtual addresses of the start and end of the memory region. */ + vm_offset_t min; + vm_offset_t max; + + /* Attributes of this memory. */ + lmm_flags_t flags; + + /* Allocation priority of this region with respect to other regions. */ + lmm_pri_t pri; + + /* Current amount of free space in this region in bytes. */ + vm_size_t free; +}; + +struct lmm_node +{ + struct lmm_node *next; + vm_size_t size; +}; + +#define ALIGN_SIZE sizeof(struct lmm_node) +#define ALIGN_MASK (ALIGN_SIZE - 1) + +#endif /* _LMM_TYPES_H_ */ diff --git a/410kern/malloc/calloc.c b/410kern/malloc/calloc.c new file mode 100644 index 0000000..507f079 --- /dev/null +++ b/410kern/malloc/calloc.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +void * +_calloc(size_t nelt, size_t eltsize) +{ + size_t allocsize = nelt * eltsize; + + void *ptr = _malloc(allocsize); + if (!ptr) + return NULL; + + memset(ptr, 0, allocsize); + + return ptr; +} diff --git a/410kern/malloc/free.c b/410kern/malloc/free.c new file mode 100644 index 0000000..c984d40 --- /dev/null +++ b/410kern/malloc/free.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include "malloc_internal.h" + +void _free(void *chunk_ptr) +{ + size_t *chunk = (size_t*)chunk_ptr - 1; + malloc_lmm_begin(); + lmm_free(&malloc_lmm, chunk, *chunk); + malloc_lmm_end(); +} + diff --git a/410kern/malloc/kernel.mk b/410kern/malloc/kernel.mk new file mode 100644 index 0000000..62b37ba --- /dev/null +++ b/410kern/malloc/kernel.mk @@ -0,0 +1,18 @@ +410KLIB_MALLOC_OBJS:= \ + calloc.o \ + free.o \ + malloc.o \ + malloc_lmm.o \ + memalign.o \ + realloc.o \ + sfree.o \ + smalloc.o \ + smemalign.o + + +410KLIB_MALLOC_OBJS:= $(410KLIB_MALLOC_OBJS:%=$(410KDIR)/malloc/%) + +ALL_410KOBJS += $(410KLIB_MALLOC_OBJS) +410KCLEANS += $(410KDIR)/libmalloc.a + +$(410KDIR)/libmalloc.a: $(410KLIB_MALLOC_OBJS) diff --git a/410kern/malloc/malloc.c b/410kern/malloc/malloc.c new file mode 100644 index 0000000..4f4a2fc --- /dev/null +++ b/410kern/malloc/malloc.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include "malloc_internal.h" + +void *_malloc(size_t size) +{ + size_t *chunk; + + size += sizeof(size_t); + + malloc_lmm_begin(); + chunk = lmm_alloc(&malloc_lmm, size, 0); + malloc_lmm_end(); + + if (!chunk) + return 0; + + *chunk = size; + return chunk+1; +} diff --git a/410kern/malloc/malloc_internal.h b/410kern/malloc/malloc_internal.h new file mode 100644 index 0000000..e8f0f39 --- /dev/null +++ b/410kern/malloc/malloc_internal.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef _410KERN_MALLOC_INTERNALS_H_ +#define _410KERN_MALLOC_INTERNALS_H_ + +#include +#include + +extern lmm_t malloc_lmm; + +void *_malloc(size_t size); +void *_memalign(size_t alignment, size_t size); +void *_calloc(size_t nelt, size_t eltsize); +void *_realloc(void *buf, size_t new_size); +void _free(void *buf); + +/* Alternate version of the standard malloc functions that expect the + caller to keep track of the size of allocated chunks. These + versions are _much_ more memory-efficient when allocating many + chunks naturally aligned to their (natural) size (e.g. allocating + naturally-aligned pages or superpages), because normal memalign + requires a prefix between each chunk which will create horrendous + fragmentation and memory loss. Chunks allocated with these + functions must be freed with sfree() rather than the ordinary + free(). */ +void *_smalloc(size_t size); +void *_smemalign(size_t alignment, size_t size); +void _sfree(void *buf, size_t size); + +// internal helpers which check for re-entering +void malloc_lmm_begin(void); +void malloc_lmm_end(void); + +#endif /* _410KERN_MALLOC_H_ */ diff --git a/410kern/malloc/malloc_lmm.c b/410kern/malloc/malloc_lmm.c new file mode 100644 index 0000000..808a00b --- /dev/null +++ b/410kern/malloc/malloc_lmm.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include "malloc_internal.h" + +#include // panic(), affirm() + +lmm_t malloc_lmm = LMM_INITIALIZER; + +static int malloc_lmm_in_use = 0; + +void malloc_lmm_begin(void) { + if (malloc_lmm_in_use) + panic("A _malloc()-related function has been called while another one is already running!"); + malloc_lmm_in_use = 1; +} + +void malloc_lmm_end(void) { + affirm(malloc_lmm_in_use); + malloc_lmm_in_use = 0; +} diff --git a/410kern/malloc/memalign.c b/410kern/malloc/memalign.c new file mode 100644 index 0000000..a3f1ad3 --- /dev/null +++ b/410kern/malloc/memalign.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include "malloc_internal.h" + +void *_memalign(size_t alignment, size_t size) +{ + unsigned shift; + size_t *chunk; + + /* Find the alignment shift in bits. XXX use proc_ops.h */ + for (shift = 0; (1 << shift) < alignment; shift++); + + /* + * Allocate a chunk of LMM memory with the specified alignment shift + * and an offset such that the memory block we return will be aligned + * after we add our size field to the beginning of it. + */ + size += sizeof(size_t); + + malloc_lmm_begin(); + chunk = lmm_alloc_aligned(&malloc_lmm, size, 0, shift, + (1 << shift) - sizeof(size_t)); + malloc_lmm_end(); + + if (!chunk) + return NULL; + + *chunk = size; + return chunk+1; +} + diff --git a/410kern/malloc/realloc.c b/410kern/malloc/realloc.c new file mode 100644 index 0000000..6175723 --- /dev/null +++ b/410kern/malloc/realloc.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +#include "malloc_internal.h" + +/* XX could be made smarter, so it doesn't always copy to a new block. */ +void *_realloc(void *buf, size_t new_size) +{ + vm_size_t *op; + vm_size_t old_size; + vm_size_t *np; + + if (buf == 0) + return _malloc(new_size); + + op = (vm_size_t*)buf; + old_size = *--op; + + new_size += sizeof(vm_size_t); + malloc_lmm_begin(); + np = lmm_alloc(&malloc_lmm, new_size, 0); + malloc_lmm_end(); + if (!np) + return NULL; + + memcpy(np, op, old_size < new_size ? old_size : new_size); + + malloc_lmm_begin(); + lmm_free(&malloc_lmm, op, old_size); + malloc_lmm_end(); + + *np++ = new_size; + return np; +} + diff --git a/410kern/malloc/sfree.c b/410kern/malloc/sfree.c new file mode 100644 index 0000000..9af5725 --- /dev/null +++ b/410kern/malloc/sfree.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +/* + * Routine to free memory blocks allocated with smalloc(), smemalign(), etc. + */ + +#include "malloc_internal.h" + +void _sfree(void *chunk, size_t size) +{ + malloc_lmm_begin(); + lmm_free(&malloc_lmm, chunk, size); + malloc_lmm_end(); +} + diff --git a/410kern/malloc/smalloc.c b/410kern/malloc/smalloc.c new file mode 100644 index 0000000..a0efabc --- /dev/null +++ b/410kern/malloc/smalloc.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +/* + * Alternate version of malloc + * that expects the caller to keep track of the size of the chunk. + * Allocated chunks must be freed with sfree() rather than free(). + */ + +#include +#include "malloc_internal.h" + +void *_smalloc(size_t size) +{ + void *chunk; + + malloc_lmm_begin(); + chunk = lmm_alloc(&malloc_lmm, size, 0); + malloc_lmm_end(); + + return chunk; +} + diff --git a/410kern/malloc/smemalign.c b/410kern/malloc/smemalign.c new file mode 100644 index 0000000..6686630 --- /dev/null +++ b/410kern/malloc/smemalign.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +/* + * Alternate version of memalign + * that expects the caller to keep track of the size of allocated chunks. + * This version is _much_ more memory-efficient + * when allocating many chunks naturally aligned to their (natural) size + * (e.g. allocating naturally-aligned pages or superpages), + * because normal memalign requires a prefix between each chunk + * which will create horrendous fragmentation and memory loss. + * Chunks allocated with this function must be freed with sfree(). + */ + +#include +#include "malloc_internal.h" + +void *_smemalign(size_t alignment, size_t size) +{ + unsigned shift; + void *chunk; + + /* Find the alignment shift in bits. XXX use proc_ops.h */ + for (shift = 0; (1 << shift) < alignment; shift++); + + /* + * Allocate a chunk of LMM memory with the specified alignment shift + * and an offset such that the memory block we return will be aligned. + */ + malloc_lmm_begin(); + chunk = lmm_alloc_aligned(&malloc_lmm, size, 0, shift, 0); + malloc_lmm_end(); + + return chunk; +} + diff --git a/410kern/menu.lst b/410kern/menu.lst new file mode 100644 index 0000000..eadaf04 --- /dev/null +++ b/410kern/menu.lst @@ -0,0 +1,4 @@ +default=0 +timeout=0 +title Pebbles + kernel (fd0)/boot/kernel.gz diff --git a/410kern/misc/gccisms.c b/410kern/misc/gccisms.c new file mode 100644 index 0000000..fea7c5b --- /dev/null +++ b/410kern/misc/gccisms.c @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ------------ + * + * Lovingly ripped, slashed, mangled, and mutilated into one file by nwf@, + * 20080814 to fit inside the CS410 universe; in some places this has resulted + * in very carefully constructed, portable code becoming x86 specific. Sorry. + * + * Taken from ftp://ftp.openbsd.org/pub/OpenBSD/3.9/sys.tar.gz + */ + +#define HALF_BITS (sizeof(int)*8/2) +#define B ((int)1 << HALF_BITS) /* digit base */ +#define H 1 /* Endianness matters */ +#define L 0 + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((quad_t)(x) << (number_of_bits_in_int/2)). (`x' must actually be u_int.) + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a quad_t, shifted left + * (sizeof(int)*CHAR_BIT/2). + */ +#define HHALF(x) ((u_int)(x) >> HALF_BITS) +#define LHALF(x) ((u_int)(x) & (((int)1 << HALF_BITS) - 1)) + +typedef unsigned int u_int; + +typedef u_int digit; +typedef long long quad_t; /* 64 bits, signed */ +typedef unsigned long long u_quad_t; /* 64 bits, unsigned */ + +/* + * Depending on the desired operation, we view a `long long' (aka quad_t) in + * one or more of the following formats. + */ +union uu { + quad_t q; /* as a (signed) quad */ + u_quad_t uq; /* as an unsigned quad */ + int sl[2]; /* as two signed ints */ + u_int ul[2]; /* as two unsigned ints */ +}; + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b)) + + +static void shl(digit *p, int len, int sh); + +/* + * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate products + * fit within u_int. As a consequence, the maximum length dividend and + * divisor are 4 `digits' in this base (they are shorter if they have + * leading zeros). + */ +u_quad_t +__qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq) +{ + union uu tmp; + digit *u, *v, *q; + digit v1, v2; + u_int qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vq == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ul[H] = tmp.ul[L] = 1 / zero; + if (arq) + *arq = uq; + return (tmp.q); + } + if (uq < vq) { + if (arq) + *arq = uq; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.uq = uq; + u[0] = 0; + u[1] = (digit)HHALF(tmp.ul[H]); + u[2] = (digit)LHALF(tmp.ul[H]); + u[3] = (digit)HHALF(tmp.ul[L]); + u[4] = (digit)LHALF(tmp.ul[L]); + tmp.uq = vq; + v[1] = (digit)HHALF(tmp.ul[H]); + v[2] = (digit)LHALF(tmp.ul[H]); + v[3] = (digit)HHALF(tmp.ul[L]); + v[4] = (digit)LHALF(tmp.ul[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + u_int rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = (digit)(u[1] / t); + rbj = COMBINE(u[1] % t, u[2]); + q2 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[3]); + q3 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[4]); + q4 = (digit)(rbj / t); + if (arq) + *arq = rbj % t; + tmp.ul[H] = COMBINE(q1, q2); + tmp.ul[L] = COMBINE(q3, q4); + return (tmp.q); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + shl(&u[0], m + n, d); /* u <<= d */ + shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + u_int nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = (digit)LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = (digit)LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = (digit)LHALF(t); + t = HHALF(t); + } + u[j] = (digit)LHALF(u[j] + t); + } + q[j] = (digit)qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (digit)(((u_int)u[i] >> d) | + LHALF((u_int)u[i - 1] << (HALF_BITS - d))); + u[i] = 0; + } + tmp.ul[H] = COMBINE(uspace[1], uspace[2]); + tmp.ul[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.q; + } + + tmp.ul[H] = COMBINE(qspace[1], qspace[2]); + tmp.ul[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.q); +} + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +shl(digit *p, int len, int sh) +{ + int i; + + for (i = 0; i < len; i++) + p[i] = (digit)(LHALF((u_int)p[i] << sh) | + ((u_int)p[i + 1] >> (HALF_BITS - sh))); + p[i] = (digit)(LHALF((u_int)p[i] << sh)); +} + + +/* + * Return remainder after dividing two unsigned quads. + */ +u_quad_t +__umoddi3(u_quad_t a, u_quad_t b) +{ + u_quad_t r; + + (void)__qdivrem(a, b, &r); + return (r); +} + +/* + * Divide two unsigned quads. + */ +u_quad_t +__udivdi3(u_quad_t a, u_quad_t b) +{ + + return (__qdivrem(a, b, (u_quad_t *)0)); +} + +/* + * Divide two signed quads. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +quad_t +__divdi3(quad_t a, quad_t b) +{ + u_quad_t ua, ub, uq; + int neg = 0; + + ua = a; + ub = b; + + if (a < 0) + ua = -ua, neg ^= 1; + if (b < 0) + ub = -ub, neg ^= 1; + + uq = __qdivrem(ua, ub, (u_quad_t *)0); + if (neg) + uq = - uq; + return uq; +} diff --git a/410kern/misc/kernel.mk b/410kern/misc/kernel.mk new file mode 100644 index 0000000..a481bd8 --- /dev/null +++ b/410kern/misc/kernel.mk @@ -0,0 +1,9 @@ +410K_MISC_OBJS := \ + gccisms.o \ + +410K_MISC_OBJS := $(410K_MISC_OBJS:%=$(410KDIR)/misc/%) + +ALL_410KOBJS += $(410K_MISC_OBJS) +410KCLEANS += $(410KDIR)/libmisc.a + +$(410KDIR)/libmisc.a: $(410K_MISC_OBJS) diff --git a/410kern/simics/kernel.mk b/410kern/simics/kernel.mk new file mode 100644 index 0000000..b06071d --- /dev/null +++ b/410kern/simics/kernel.mk @@ -0,0 +1,10 @@ +410K_SIMICS_OBJS := \ + simics.o \ + simics_c.o + +410K_SIMICS_OBJS := $(410K_SIMICS_OBJS:%=$(410KDIR)/simics/%) + +ALL_410KOBJS += $(410K_SIMICS_OBJS) +410KCLEANS += $(410KDIR)/libsimics.a + +$(410KDIR)/libsimics.a: $(410K_SIMICS_OBJS) diff --git a/410kern/simics/simics.S b/410kern/simics/simics.S new file mode 100644 index 0000000..9f4ef41 --- /dev/null +++ b/410kern/simics/simics.S @@ -0,0 +1,13 @@ +/* simics.S - Simics interface (kernel side) */ + +/* sim_call(ebx, ecx, edx) */ +.global sim_call +sim_call: + push %ebx + mov 0x8(%esp), %ebx + mov 0xC(%esp), %ecx + mov 0x10(%esp), %edx + mov $0, %eax + xchg %ebx, %ebx + pop %ebx + ret diff --git a/410kern/simics/simics.h b/410kern/simics/simics.h new file mode 100644 index 0000000..67cf955 --- /dev/null +++ b/410kern/simics/simics.h @@ -0,0 +1,75 @@ +/** @file lib/simics.h + * @brief Simics interface (kernel side) + * @author matthewj S2008 + */ + +#ifndef LIB_SIMICS_H +#define LIB_SIMICS_H + +#define SIM_IN_SIMICS 0x04100000 +#define SIM_MEMSIZE 0x04100001 +#define SIM_PUTS 0x04100002 +#define SIM_BREAKPOINT 0x04100003 +#define SIM_HALT 0x04100004 +#define SIM_REG_PROCESS 0x04100005 +#define SIM_UNREG_PROCESS 0x04100006 +#define SIM_REG_CHILD 0x04100007 +#define SIM_BOOTED 0x04100008 +#define SIM_TID_SET 0x04100009 +#define SIM_TID_DEL 0x0410000A + +#ifdef ASSEMBLER + +#define lprintf sim_printf + +#else /* !ASSEMBLER */ + +#include + +/** @brief Calls Simics. Arguments are ebx, ecx, edx. */ +extern int sim_call(int ebx, ...); + +/** @brief Returns whether we are in simics */ +extern int sim_in_simics(void); + +/** @brief Returns machine memory size, from simics */ +extern int sim_memsize(void); + +/** @brief Prints a string to the simics console */ +extern void sim_puts(const char *arg); + +/** @brief Breakpoint */ +extern void sim_breakpoint(void); + +/** @brief Halt the simulation */ +extern void sim_halt(void); + +/** @brief Register a user process with the CS410 simics debugging code */ +extern void sim_reg_process(void *cr3, const char *fname); + +/** @brief Register a user process as a fork of another. + * + * Handy if fork() is oblivious of the program's name. + */ +extern void sim_reg_child(void *child_cr3, void *parent_cr3); + +/** @brief Unregister a user process from the CS410 simics debugging code */ +extern void sim_unreg_process(void *cr3); + +/** @brief Convenience wrappers around sim_puts(). */ +extern void sim_vprintf(const char* fmt, va_list ap); +extern void sim_printf(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); + +/** @brief Notify simics that we have booted. + * + * This is done for you in 410kern/entry.c + */ +extern void sim_booted(const char *kern); + +/* "Compatibility mode" for old code */ +#define MAGIC_BREAK sim_breakpoint() +#define lprintf(...) sim_printf(__VA_ARGS__) + +#endif /* !ASSEMBLER */ + +#endif /* !LIB_SIMICS_H */ diff --git a/410kern/simics/simics_c.c b/410kern/simics/simics_c.c new file mode 100644 index 0000000..32248d5 --- /dev/null +++ b/410kern/simics/simics_c.c @@ -0,0 +1,60 @@ +/** @file simics_c.c + * @author elly1 U2009 + * @brief Simics calls. + */ + +#include +#include +#include + +int sim_in_simics(void) { + return sim_call(SIM_IN_SIMICS); +} + +int sim_memsize(void) { + return sim_call(SIM_MEMSIZE); +} + +void sim_puts(const char *str) { + sim_call(SIM_PUTS, str); +} + +void sim_breakpoint(void) { + sim_call(SIM_BREAKPOINT); +} + +void sim_halt(void) { + sim_call(SIM_HALT); +} + +void sim_reg_process(void *cr3, const char *prog) { + sim_call(SIM_REG_PROCESS, cr3, prog); +} + +void sim_reg_child(void *cr3, void *pcr3) { + sim_call(SIM_REG_CHILD, cr3, pcr3); +} + +void sim_unreg_process(void *cr3) { + sim_call(SIM_UNREG_PROCESS, cr3); +} + +void sim_booted(const char *kern) { + sim_call(SIM_BOOTED, kern); +} + +void sim_vprintf(const char* fmt, va_list vl) +{ + char str[256]; + vsnprintf(str, sizeof(str)-1, fmt, vl); + sim_puts(str); +} + +void sim_printf(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sim_vprintf(fmt, ap); + va_end(ap); +} diff --git a/410kern/smp/L36_P4.pdf b/410kern/smp/L36_P4.pdf new file mode 100644 index 0000000..829639d Binary files /dev/null and b/410kern/smp/L36_P4.pdf differ diff --git a/410kern/smp/README b/410kern/smp/README new file mode 100644 index 0000000..b9d2aaa --- /dev/null +++ b/410kern/smp/README @@ -0,0 +1,17 @@ +If you are reading this file, you probably don't need to. + +This directory contains code which enables a Pebbles kernel +to boot multiple processors and communicate among them by +using inter-processor interrupts (IPIs). This code is +provided for the curious or ambitious reader, but you should +be VERY CAREFUL that it doesn't distract you from accomplishing +what you need to get done to pass the kernel project, i.e. write +a complete and robust kernel. + +Notes: + +1. We expect you to consult "L36_P4.pdf" and "smp4.pdf" in +this directory. + +2. It might be useful to refer to Intel's "MultiProcessor +Specification, Version 1.4 (May 1997)". diff --git a/410kern/smp/apic.c b/410kern/smp/apic.c new file mode 100644 index 0000000..3a14e36 --- /dev/null +++ b/410kern/smp/apic.c @@ -0,0 +1,104 @@ +/** @file apic.c + * @brief Code for manipulating the local apic + * + * @author Ryan Pearl (rpearl) + */ + +#include +#include +#include +#include + +extern int cpu2apic[MAX_CPUS]; +extern int apic2cpu[MAX_CPUS]; + +/** @brief Read from a local APIC register + * + * @param reg The register offset to read from. + * @return The value of the register. + */ +uint32_t lapic_read(int reg) { + return *(volatile uint32_t *)(LAPIC_VIRT_BASE + reg); +} + +/** @brief Write to a local APIC register + * + * @param reg The register offset to write to. + * @param data The data to write + * @return unit + */ +void lapic_write(int reg, uint32_t data) { + *(volatile uint32_t *)(LAPIC_VIRT_BASE + reg) = data; +} + +/** @brief Read from the local APIC before it is mapped into virtual memory. + * (It is almost certainly not necessary to call this function) + * + * @param reg The register offset to write to. + * @return The data at that register. + */ +uint32_t lapic_phys_read(int reg) { + return *(volatile uint32_t *)(smp_lapic_base() + reg); +} + +/** @brief Write to the local APIC before it is mapped into virtual memory. + * (It is almost certainly not necessary to call this function) + * + * @param reg The register offset to write to. + * @param data The data to write + * @return unit + */ +void lapic_phys_write(int reg, uint32_t data) { + *(volatile uint32_t *)(smp_lapic_base() + reg) = data; +} + +/** @brief Initialize the APIC. + * + * @return unit + */ +void apic_init(void) { + lapic_write(LAPIC_SVR, lapic_read(LAPIC_SVR) | LAPIC_ENABLE); +} + + +/** @brief Return this core's APIC ID. + * + * @return The APIC's ID. + */ +int get_apic_id(void) { + return lapic_read(LAPIC_ID) >> LAPIC_ID_SHIFT; +} + +/** @brief Sends an APIC end-of-interrupt command. + * + * @return unit + */ +void apic_eoi(void) { + lapic_write(LAPIC_EOI, 0); +} + +/** @brief Send an interprocessor interrupt to a particular target CPU. + * + * @param cpuno The CPU to target + * @param vector The interrupt to send. + * + * @return unit + */ +void apic_ipi_cpu(int cpuno, uint8_t vector) { + assert(cpuno >= 0 && cpuno < MAX_CPUS); + int apic_id = cpu2apic[cpuno]; + + lapic_write(LAPIC_ICRHI, apic_id << LAPIC_ID_SHIFT); + lapic_write(LAPIC_ICRLO, vector | LAPIC_ASSERT | LAPIC_FIELD); +} + +/** @brief Send an interprocessor interrupt to all other CPUs + * + * @param vector The interrupt to send. + * + * @return unit + */ +void apic_ipi_others(uint8_t vector) { + uint32_t val = vector | LAPIC_FIXED | LAPIC_ALLEXC | LAPIC_ASSERT; + lapic_write(LAPIC_ICRLO, val); +} diff --git a/410kern/smp/apic.h b/410kern/smp/apic.h new file mode 100644 index 0000000..3850bce --- /dev/null +++ b/410kern/smp/apic.h @@ -0,0 +1,139 @@ +/** + * @file apic.h + * @brief apic related definitions and stuff + * + * @author Ryan Pearl (rpearl) + * @author Michael Sullivan (mjsulliv) + */ + +#ifndef APIC_H +#define APIC_H + +#define LAPIC_DEFAULT_BASE 0xfee00000 +#define IOAPIC_DEFAULT_BASE 0xfec00000 + +#define LAPIC_VIRT_BASE 0x1000 + +#define LAPIC_ID_SHIFT 24 + + +/* Local APIC registers */ +#define LAPIC_ID 0x020 /* ID */ +#define LAPIC_VER 0x030 /* Version */ +#define LAPIC_TPR 0x080 /* Task Priority */ +#define LAPIC_APR 0x090 /* Arbitration Priority */ +#define LAPIC_PPR 0x0A0 /* Processor Priority */ +#define LAPIC_EOI 0x0B0 /* EOI */ +#define LAPIC_LDR 0x0D0 /* Logical Destination */ +#define LAPIC_DFR 0x0E0 /* Destination Format */ +#define LAPIC_SVR 0x0F0 /* Spurious Interrupt Vector */ +#define LAPIC_ISR 0x100 /* Interrupt Status (8 registers) */ +#define LAPIC_TMR 0x180 /* Trigger Mode (8 registers) */ +#define LAPIC_IRR 0x200 /* Interrupt Request (8 registers) */ +#define LAPIC_ESR 0x280 /* Error Status */ +#define LAPIC_ICRLO 0x300 /* Interrupt Command */ +#define LAPIC_ICRHI 0x310 /* Interrupt Command [63:32] */ +#define LAPIC_LVT_TIMER 0x320 /* Local Vector Table 0 (TIMER) */ +#define LAPIC_PCINT 0x340 /* Performance Counter LVT */ +#define LAPIC_LINT0 0x350 /* Local Vector Table 1 (LINT0) */ +#define LAPIC_LINT1 0x360 /* Local Vector Table 2 (LINT1) */ +#define LAPIC_ERROR 0x370 /* Local Vector Table 3 (ERROR) */ +#define LAPIC_TIMER_INIT 0x380 /* Timer Initial Count */ +#define LAPIC_TIMER_CUR 0x390 /* Timer Current Count */ +#define LAPIC_TIMER_DIV 0x3E0 /* Timer Divide Configuration */ + +/* + * Common bits for + * I/O APIC Redirection Table Entry; + * Local APIC Local Interrupt Vector Table; + * Local APIC Inter-Processor Interrupt; + * Local APIC Timer Vector Table. + */ +#define LAPIC_FIXED 0x00000000 /* [10:8] Delivery Mode */ +#define LAPIC_LOWEST 0x00000100 /* Lowest priority */ +#define LAPIC_SMI 0x00000200 /* System Management Interrupt */ +#define LAPIC_RR 0x00000300 /* Remote Read */ +#define LAPIC_NMI 0x00000400 +#define LAPIC_INIT 0x00000500 /* INIT/RESET */ +#define LAPIC_STARTUP 0x00000600 /* Startup IPI */ +#define LAPIC_EXT_INT 0x00000700 + +#define LAPIC_PHYSICAL 0x00000000 /* [11] Destination Mode (RW) */ +#define LAPIC_LOGICAL 0x00000800 + +#define LAPIC_DELIVS 0x00001000 /* [12] Delivery Status (RO) */ +#define LAPIC_HIGH 0x00000000 /* [13] Interrupt Input Pin Polarity (RW) */ +#define LAPIC_LOW 0x00002000 +#define LAPIC_REMOTE_IRR 0x00004000 /* [14] Remote IRR (RO) */ +#define LAPIC_EDGE 0x00000000 /* [15] Trigger Mode (RW) */ +#define LAPIC_LEVEL 0x00008000 +#define LAPIC_IMASK 0x00010000 /* [16] Interrupt Mask */ + +/* Defines for LAPIC_SVR */ +#define LAPIC_ENABLE 0x00000100 /* Unit Enable */ +#define LAPIC_FOCUS 0x00000200 /* Focus Processor Checking Disable */ + +/* Defines for LAPIC_IRCLO */ +/* [14] IPI Trigger Mode Level (RW) */ +#define LAPIC_DEASSERT 0x00000000 /* Deassert level-sensitive interrupt */ +#define LAPIC_ASSERT 0x00004000 /* Assert level-sensitive interrupt */ + +/* [17:16] Remote Read Status */ +#define LAPIC_INVALID 0x00000000 /* Invalid */ +#define LAPIC_WAIT 0x00010000 /* In-Progress */ +#define LAPIC_VALID 0x00020000 /* Valid */ + +/* [19:18] Destination Shorthand */ +#define LAPIC_FIELD 0x00000000 /* No shorthand */ +#define LAPIC_SELF 0x00040000 /* Self is single destination */ +#define LAPIC_ALLINC 0x00080000 /* All including self */ +#define LAPIC_ALLEXC 0x000C0000 /* All Excluding self */ + +/* Defines for LAPIC_ESR */ +#define LAPIC_SENDCS 0x00000001 /* Send CS Error */ +#define LAPIC_RCVCS 0x00000002 /* Receive CS Error */ +#define LAPIC_SENDACCEPT 0x00000004 /* Send Accept Error */ +#define LAPIC_RCVACCEPT 0x00000008 /* Receive Accept Error */ +#define LAPIC_SENDVECTOR 0x00000020 /* Send Illegal Vector */ +#define LAPIC_RCVVECTOR 0x00000040 /* Receive Illegal Vector */ +#define LAPIC_REGISTER 0x00000080 /* Illegal Register Address */ + +/* Defines for LAPIC_TIMER */ +/* [17] Timer Mode (RW) */ +#define LAPIC_ONESHOT 0x00000000 /* One-shot */ +#define LAPIC_PERIODIC 0x00020000 /* Periodic */ + +/* [19:18] Timer Base (RW) */ +#define LAPIC_CLKIN 0x00000000 /* use CLKIN as input */ +#define LAPIC_TMBASE 0x00040000 /* use TMBASE */ +#define LAPIC_DIVIDER 0x00080000 /* use output of the divider */ + +/* Defines for LAPIC_TIMER_DIV */ +#define LAPIC_X2 0x00000000 /* divide by 2 */ +#define LAPIC_X4 0x00000001 /* divide by 4 */ +#define LAPIC_X8 0x00000002 /* divide by 8 */ +#define LAPIC_X16 0x00000003 /* divide by 16 */ +#define LAPIC_X32 0x00000008 /* divide by 32 */ +#define LAPIC_X64 0x00000009 /* divide by 64 */ +#define LAPIC_X128 0x0000000A /* divide by 128 */ +#define LAPIC_X1 0x0000000B /* divide by 1 */ + +#ifndef ASSEMBLER +#include + +void lapic_eoi(void); +uint32_t lapic_read(int reg); +uint32_t lapic_phys_read(int reg); +void lapic_write(int reg, uint32_t data); +void lapic_phys_write(int reg, uint32_t data); + +int get_apic_id(void); + +void apic_init(void); + +void apic_eoi(void); +void apic_ipi_cpu(int cpuno, uint8_t vector); +void apic_ipi_others(uint8_t vector); + +#endif +#endif diff --git a/410kern/smp/kernel.mk b/410kern/smp/kernel.mk new file mode 100644 index 0000000..96c6cd4 --- /dev/null +++ b/410kern/smp/kernel.mk @@ -0,0 +1,12 @@ +410K_SMP_OBJS := \ + smp.o \ + apic.o \ + mptable.o \ +smp_start.o + +410K_SMP_OBJS := $(410K_SMP_OBJS:%=$(410KDIR)/smp/%) + +ALL_410KOBJS += $(410K_SMP_OBJS) +410KCLEANS += $(410KDIR)/libsmp.a + +$(410KDIR)/libsmp.a: $(410K_SMP_OBJS) diff --git a/410kern/smp/mptable.c b/410kern/smp/mptable.c new file mode 100644 index 0000000..cb0a5c9 --- /dev/null +++ b/410kern/smp/mptable.c @@ -0,0 +1,246 @@ +/** @file mptable.c + * + * @brief Code to parse the MP table and determine information + * about the APIC. + * + * @author Ryan Pearl (rpearl) + * + * This code is directly based on FreeBSD's MP table parsing code. License and + * copyright information repeated below. + */ + +/*- + * Copyright (c) 2003 John Baldwin + * Copyright (c) 1996, by Steve Passe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the developer may NOT be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + + +#include + +#include +#include +#include + +#include + +static int num_cpus = 1; /**< The number of CPUs */ +static int bsp_id; /**< The cpu number for the BSP */ +static int bsp_apic; /**< The APIC id for the BSP */ +static void *lapic_base = NULL; /**< Location in physical memory of the Local + APIC base */ +static void *ioapic_addr = NULL; /**< Location in physical memory of the I/O + APIC base */ + +extern int cpu2apic[MAX_CPUS]; +extern int apic2cpu[MAX_CPUS]; + +/** @brief Reset state to uniprocessor + * + * @return unit + */ +static void mp_set_uniprocessor() { + num_cpus = 1; + ioapic_addr = NULL; + lapic_base = NULL; +} + +/** @brief Fills in the book-keeping information for a CPU + * + * @param apic_id The local APIC ID for this CPU + * @param bsp Wether this CPU is the BSP + * + * @return unit + */ +static void mp_cpu_create(int apic_id, int bsp) { + + if (num_cpus >= MAX_CPUS || apic_id >= MAX_CPUS) + return; // out of range; ignore it. + + cpu2apic[num_cpus] = apic_id; + apic2cpu[apic_id] = num_cpus; + if (bsp) { + bsp_apic = apic_id; + bsp_id = num_cpus; + } + num_cpus++; +} + +/** @brief Perform a checksum on an MP structure. + * + * @param addr The base of the structure + * @param len The length of the structure + * @return nonzero if sucessful, 0 otherwise. + */ +static int checksum(char *addr, int len) { + int i; + uint8_t sum = 0; + for (i = 0; i < len; i++) { + sum += addr[i]; + } + return (sum == 0); +} + +/** + * @brief Search for the MP floating pointer signature. + * + * @param addr The address to start searching at + * @param len The number of bytes to search. + * + * @return A pointer to the structure + */ +static struct mpfps *mp_scan_sig(uintptr_t addr, int len) { + + char *ptr; + char *end = (char *)addr + len; + + for (ptr = (char *)addr; ptr < end; ptr += sizeof(struct mpfps)) { + uint32_t sig = *(uint32_t *)ptr; + if (sig == MP_FPS_SIG && checksum(ptr, sizeof(struct mpfps))) + return (struct mpfps *)ptr; + } + return NULL; +} + +/** @brief Walk the MP configuration table and gather data. + * + * @param cfg The configuration table to read. + * @return unit + */ +static void mptable_walk(struct mptable *cfg) { + num_cpus = 0; // mp_cpu_create() will count the BSP + STATIC_ASSERT(sizeof(struct mp_cpu) == 20); + STATIC_ASSERT(sizeof(struct mp_ioapic) == 8); + uint8_t *ptr = (uint8_t *)(cfg + 1); + int smp = 1; + uint16_t i; + for (i = 0; i < cfg->entries; i++) { + switch (*ptr) { + case MP_PROC: { + struct mp_cpu *cpu = (struct mp_cpu *)ptr; + if (cpu->flags & MP_PROC_EN) { + mp_cpu_create(cpu->apic_id, cpu->flags & MP_PROC_BSP); + } + ptr += sizeof(struct mp_cpu); + break; + } + case MP_IOAPIC: { + if (ioapic_addr != NULL) { + /* More complete code is needed to handle multiple I/O + * APICS. But, we don't even use the one we find. */ + smp = 0; + } else { + struct mp_ioapic *ioapic = (struct mp_ioapic *)ptr; + ioapic_addr = ioapic->phys_addr; + } + ptr += sizeof(struct mp_ioapic); + break; + } + case MP_BUS: + case MP_IOINTR: + case MP_LINTR: + /* On a more complete system with actual devices, we need to + * care about these things. + */ + ptr += 8; + break; + default: + panic("Unknown MP configuration entry: %x", *ptr); + } + } + if (!smp) { + mp_set_uniprocessor(); + } +} + +/** @brief Find the EBDA from the BIOS. + * + * @return The EBDA base. + */ +static inline uint32_t get_ebda(void) { + uint32_t ebda_seg = (uint32_t)*(uint16_t *)MP_BIOS_EBDA; + return ebda_seg << 4; +} + +/** @brief Reads MP Table Configuration and determines whether the system has + * multiple processors. + * + * @param info The multiboot info provided by the boatloader + * @return zero if multiprocessor, negative error code if not. + */ +int smp_init(mbinfo_t *info) { + struct mpfps *fp; + struct mptable *cfg; + uint32_t ebda = get_ebda(); + if (ebda) { + if ((fp = mp_scan_sig(ebda, 1024)) != NULL) + goto found; + } + + if ((fp = mp_scan_sig(info->mem_lower * 1024, 1024)) != NULL) + goto found; + + if ((fp = mp_scan_sig(MP_BIOS_START, MP_BIOS_LEN)) != NULL) + goto found; + + return -1; + + found: + if (fp->type != 0) { + // These are default configurations. + if (fp->type != 5 && fp->type != 6) + return -1; // Unsupported configuration (old hardware) + + lapic_base = (void *)LAPIC_DEFAULT_BASE; + ioapic_addr = (void *)IOAPIC_DEFAULT_BASE; + mp_cpu_create(0, 1); + mp_cpu_create(1, 0); + } else { + cfg = (struct mptable *)fp->phys_addr; + + if (!checksum((char *)cfg, cfg->length) || cfg->sig != MP_CFG_SIG) + return -1; + + lapic_base = (void *)cfg->lapic_addr; + mptable_walk(cfg); + } + + return 0; +} + +/** @brief Returns the number of CPUs in the system. + */ +int smp_num_cpus(void) { + return num_cpus; +} + +/** @brief Return the base of the local APIC in physical memory. + */ +void *smp_lapic_base(void) { + return lapic_base; +} diff --git a/410kern/smp/mptable.h b/410kern/smp/mptable.h new file mode 100644 index 0000000..c0ee90c --- /dev/null +++ b/410kern/smp/mptable.h @@ -0,0 +1,119 @@ +/** @file mptable.h + * + * @brief Code to parse the MP table and determine information + * about the APIC. + * + * @author Ryan Pearl (rpearl) + * + * This code is directly based on FreeBSD's MP table parsing code. License and + * copyright information repeated below. + */ + +/*- + * Copyright (c) 2003 John Baldwin + * Copyright (c) 1996, by Steve Passe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the developer may NOT be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _MPTABLE_H_ +#define _MPTABLE_H_ + +#include // mbinfo_t +#include + +#define MP_FPS_SIG 0x5f504d5f /**< The MP floating pointer signature */ +#define MP_CFG_SIG 0x504d4350 /**< MP Table signature */ + +/** @brief Memory layout defines */ +#define MP_BIOS_START 0xf0000 /**< the start of the BIOS ROM area */ +#define MP_BIOS_LEN 0x10000 /**< the length of the BIOS ROM area */ +#define MP_BIOS_EBDA 0x40e /**< the location within the BIOS data area of + the EBDA base */ + + +/** @brief MP table defines */ +#define MP_PROC 0x0 /**< a processor entry in the MP table */ +#define MP_BUS 0x1 /**< a bus entry in the MP table (unused in 15-410) */ +#define MP_IOAPIC 0x2 /**< an I/O APIC entry in the MP table */ +#define MP_IOINTR 0x3 /**< an I/O interrupt entry in the MP table + (unused in 15-410) */ +#define MP_LINTR 0x4 /**< a local interrupt entry in the MP table + (unused in 15-410) */ + +/** @brief Processor flag defines */ +#define MP_PROC_EN 0x1 /**< Processor is enabled */ +#define MP_PROC_BSP 0x2 /**< Processor is the bootstrap processor */ + + +/** @brief Layout of the MP Floating Pointer structure */ +struct mpfps { + uint8_t sig[4]; + void *phys_addr; + uint8_t length; + uint8_t specrev; + uint8_t checksum; + uint8_t type; + uint8_t imcrp; + uint8_t reserved[3]; +}; + +/** @brief Layout of the MP Configuration Table */ +struct mptable { + uint32_t sig; + uint16_t length; + uint8_t version; + uint8_t checksum; + uint8_t product[20]; + uint32_t *oem_table; + uint16_t oem_length; + uint16_t entries; + void *lapic_addr; + uint16_t ext_length; + uint8_t ext_checksum; + uint8_t reserved; +}; + +/** @brief Layout of a processor entry in the MP Configuration Table */ +struct mp_cpu { + uint8_t type; + uint8_t apic_id; + uint8_t version; + uint8_t flags; + uint8_t sig[4]; + uint32_t features; + uint8_t reserved[8]; +}; + +/** @brief Layout of an I/O APIC entry in the MP Configuration Table */ +struct mp_ioapic { + uint8_t type; + uint8_t apic_id; + uint8_t version; + uint8_t flags; + void *phys_addr; +}; + +int smp_init(mbinfo_t *info); +int smp_num_cpus(void); +void *smp_lapic_base(void); + +#endif diff --git a/410kern/smp/smp.c b/410kern/smp/smp.c new file mode 100644 index 0000000..cb7cfdf --- /dev/null +++ b/410kern/smp/smp.c @@ -0,0 +1,200 @@ +/** + * @file smp.c + * @brief SMP bootup and utility code. + * + * @author Ryan Pearl (rpearl) + * @author Michael Sullivan (mjsulliv) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +extern uint64_t init_gdt[GDT_SEGS]; +extern char *init_tss; + +char smp_boot_stack[INIT_STACK_SIZE][MAX_CPUS]; + +extern uint32_t smp_boot_gdt_base; +extern uint16_t smp_boot_gdt_limit; +static void *smp_idt_base; /**< Stores the 32-bit IDT base before booting the + other cores. */ + +/** @brief a mapping from APIC IDs to CPU numbers */ +int apic2cpu[MAX_CPUS]; +/** @brief a mapping from CPU numbers to APIC IDs */ +int cpu2apic[MAX_CPUS]; + +volatile int cpus_booted = 1; +static void (*smp_main_fn)(int cpu); /**< Stores the entry point function for + the APs to run. */ + + +/** + * @brief Return what the kernel considers the CPU number of the current CPU + * Note that the CPU number is generally only safe to use if interrupts + * are disabled. Otherwise, the thread could get preempted and scheduled + * in the meantime. + * + * @return The current cpu number + */ +int smp_get_cpu(void) { + /* If only one CPU is running, it must be CPU 0. Making use + * of this fact makes it safe for people to call smp_get_cpu() + * in early start-up code, before paging is on, thus before + * the LAPIC is mapped and get_apic_id() is working. + */ + if (cpus_booted == 1) + return 0; + else + return apic2cpu[get_apic_id()]; +} + +/** + * @brief The first function run in C, in protected mode. + * Sets up the CPU state and calls the SMP entrypoint function. + * @return Does not return. + */ + +void squidboy(void) { + /* paging is not enabled, so read from physical memory. */ + int apic_id = (int)lapic_phys_read(LAPIC_ID); + apic_id = apic_id >> LAPIC_ID_SHIFT; + + int cpuno = apic2cpu[apic_id]; + + /* enable local APIC */ + lapic_phys_write(LAPIC_SVR, lapic_phys_read(LAPIC_SVR) | LAPIC_ENABLE); + /* clear error status register. Requires two writes */ + lapic_phys_write(LAPIC_ESR, 0); + lapic_phys_write(LAPIC_ESR, 0); + + /* clear interrupts */ + lapic_phys_write(LAPIC_EOI, 0); + + /* This cpu is currently running on the boot GDT: we needed to get to + * protected mode. Now, since the GDT contains a TSS entry, and the TSS is + * responsible for maintaining the esp0 "register" (among other things) we + * switch to a separate GDT and TSS for this core. + */ + extern const size_t init_tss_size; + char tss[init_tss_size]; + memcpy(&tss, &init_tss, init_tss_size); + + uint64_t gdt[GDT_SEGS]; + memcpy(gdt, init_gdt, sizeof(init_gdt)); + + /* N.B. This is NOT to be construed as style guidance!! */ + /* N.B. This is NOT to be construed as style guidance!! */ + /* N.B. This is NOT to be construed as style guidance!! */ + /* Needs to be kept in sync with init_gdt in boot/head.S */ + gdt[SEGSEL_KERNEL_TSS_IDX] -= 65536 * (34605392ull - (int)tss); + /**/ + + lgdt(gdt, sizeof(gdt)-1); + + + /* Load the same IDT into this GDT */ + lidt(smp_idt_base, IDT_ENTS * IDT_ENT_SIZE); + + /* Reload task register */ + ltr(SEGSEL_TSS); + + /* Disable floating point unit: + * see 410kern/boot/entry.c + */ + set_cr0(get_cr0() | CR0_EM); + + smp_main_fn(cpuno); + panic("cpu %d: smp entrypoint returned.", cpuno); +} + +/** @brief Delay for a number of microseconds. + * + * @return unit + */ +static void udelay(int us) { + int i; + for (i = 0; i < us; i++) + iodelay(); +} + +static void apic_wait() { + while ((lapic_read(LAPIC_ICRLO) & LAPIC_DELIVS) != 0) + continue; +} + +static int smp_boot_cpu(int cpuno) { + uint8_t entry = SMP_INIT_PAGE >> PAGE_SHIFT; + int apic_id = cpu2apic[cpuno]; + int booted = cpus_booted; + + /* send INIT IPI to this CPU */ + lapic_write(LAPIC_ICRHI, apic_id << LAPIC_ID_SHIFT); + lapic_write(LAPIC_ICRLO, LAPIC_INIT | LAPIC_ASSERT | LAPIC_FIELD); + udelay(1000 * 10); // 10ms + apic_wait(); + + lapic_write(LAPIC_ICRHI, apic_id << LAPIC_ID_SHIFT); + lapic_write(LAPIC_ICRLO, entry | LAPIC_STARTUP | LAPIC_FIELD | LAPIC_DEASSERT); + apic_wait(); + udelay(200); // 20us + + lapic_write(LAPIC_ICRHI, apic_id << LAPIC_ID_SHIFT); + lapic_write(LAPIC_ICRLO, entry | LAPIC_STARTUP | LAPIC_FIELD | LAPIC_DEASSERT); + apic_wait(); + udelay(200); // 20us + int ms; + for (ms = 0; ms < 500; ms++) { + if (cpus_booted > booted) + return 1; + udelay(1000); + } + return 0; +} + +/** @brief Sends the INIT and SIPI message to the APs to boot them. + * + * @return unit + */ +static void smp_boot_cpus() { + int cpu; + int num_cpus = smp_num_cpus(); + for (cpu = 1; cpu < num_cpus; cpu++) { + if (!smp_boot_cpu(cpu)) { + panic("cpu %d did not boot\n", cpu); + } + } +} + +/** @brief Boot the application processors + * + * @param entry The entry point function. The parameter is the cpu number. + * @return unit + */ +void smp_boot(void (*entry)(int)) { + smp_main_fn = entry; + + /* Gather information from the BSP that the APs need. */ + smp_boot_gdt_base = (uint32_t)&init_gdt; + smp_boot_gdt_limit = sizeof(init_gdt) - 1; + smp_idt_base = idt_base(); + + apic_init(); + + /* Copy code to a low address; it has to run in real mode. */ + extern char startup_begin; + memcpy((void *)SMP_INIT_PAGE, &startup_begin, PAGE_SIZE); + smp_boot_cpus(); +} diff --git a/410kern/smp/smp.h b/410kern/smp/smp.h new file mode 100644 index 0000000..6d37a9c --- /dev/null +++ b/410kern/smp/smp.h @@ -0,0 +1,20 @@ +/** + * @file smp.h + * @brief smp related definitions and stuff + * + * @author Ryan Pearl (rpearl) + * @author Michael Sullivan (mjsulliv) + */ + +#ifndef SMP_H +#define SMP_H + +#include +#include + +#define MAX_CPUS 16 + +void smp_boot(void (*entry)(int)); +int smp_get_cpu(void); + +#endif diff --git a/410kern/smp/smp4.pdf b/410kern/smp/smp4.pdf new file mode 100644 index 0000000..494c237 Binary files /dev/null and b/410kern/smp/smp4.pdf differ diff --git a/410kern/smp/smp_start.S b/410kern/smp/smp_start.S new file mode 100644 index 0000000..028bb36 --- /dev/null +++ b/410kern/smp/smp_start.S @@ -0,0 +1,55 @@ +/** @brief SMP bootstrap code. + * + * @author Ryan Pearl (rpearl) + */ + +#include +#include +#include + +/** @brief refer to a location once it's been moved. */ +#define REF(loc) (loc - startup_begin + SMP_INIT_PAGE) + +/** @brief 16-bit initially run on initial boot */ +.code16 +.global startup_begin +startup_begin: + cli + cld + //get to protected mode + lgdt REF(smp_boot_gdt_limit) + movl $CR0_PE, %eax + movl %eax, %cr0 + ljmp $SEGSEL_KERNEL_CS, $REF(smp_begin_protected) + +/** @brief Code run once 32-bit protected mode is enabled. */ +.code32 +smp_begin_protected: + /* perform an absolute jump to the smp startup code not in low-memory. */ + movl $smp_main, %eax + jmp *%eax +smp_main: + movl $SEGSEL_KERNEL_DS, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + movl $1, %esi + lock xaddl %esi, cpus_booted + + movl %esi, %ecx + shl $INIT_STACK_SHIFT, %ecx + addl $smp_boot_stack, %ecx + movl %ecx, %esp + call squidboy + + +/** @brief Initial GDT's limit */ +.global smp_boot_gdt_limit +smp_boot_gdt_limit: .word 0 + +/** @brief Initial GDT's base */ +.global smp_boot_gdt_base +smp_boot_gdt_base: .long 0 diff --git a/410kern/smp/smpboot.h b/410kern/smp/smpboot.h new file mode 100644 index 0000000..b5ebe0b --- /dev/null +++ b/410kern/smp/smpboot.h @@ -0,0 +1,19 @@ +/** + * @file smpboot.h + * @brief Defines related to the initial startup of APs + * Needs to be included from an assembly file + * + * @author Ryan Pearl (rpearl) + * @author Michael Sullivan (mjsulliv) + * @bug None known + */ + +#ifndef SMPBOOT_H +#define SMPBOOT_H + +#define SMP_INIT_PAGE 0x2000 + +#define INIT_STACK_SHIFT 11 +#define INIT_STACK_SIZE (1< +#include +#include +#include "doprnt.h" + +/* + * Common code for printf et al. + * + * The calling routine typically takes a variable number of arguments, + * and passes the address of the first one. This implementation + * assumes a straightforward, stack implementation, aligned to the + * machine's wordsize. Increasing addresses are assumed to point to + * successive arguments (left-to-right), as is the case for a machine + * with a downward-growing stack with arguments pushed right-to-left. + * + * To write, for example, fprintf() using this routine, the code + * + * fprintf(fd, format, args) + * FILE *fd; + * char *format; + * { + * _doprnt(format, &args, fd); + * } + * + * would suffice. (This example does not handle the fprintf's "return + * value" correctly, but who looks at the return value of fprintf + * anyway?) + * + * This version implements the following printf features: + * + * %d decimal conversion + * %u unsigned conversion + * %x hexadecimal conversion + * %X hexadecimal conversion with capital letters + * %o octal conversion + * %c character + * %s string + * %m.n field width, precision + * %-m.n left adjustment + * %0m.n zero-padding + * %*.* width and precision taken from arguments + * + * This version does not implement %f, %e, or %g. It accepts, but + * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not + * work correctly on machines for which sizeof(long) != sizeof(int). + * It does not even parse %D, %O, or %U; you should be using %ld, %o and + * %lu if you mean long conversion. + * + * As mentioned, this version does not return any reasonable value. + * + * Permission is granted to use, modify, or propagate this code as + * long as this notice is incorporated. + * + * Steve Summit 3/25/87 + */ + +/* + * Added formats for decoding device registers: + * + * printf("reg = %b", regval, "*") + * + * where is the output base expressed as a control character: + * i.e. '\10' gives octal, '\20' gives hex. Each is a sequence of + * characters, the first of which gives the bit number to be inspected + * (origin 1), and the rest (up to a control character (<= 32)) give the + * name of the register. Thus + * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE") + * would produce + * reg = 3 + * + * If the second character in is also a control character, it + * indicates the last bit of a bit field. In this case, printf will extract + * bits <1> to <2> and print it. Characters following the second control + * character are printed before the bit field. + * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE") + * would produce + * reg = b + */ +/* + * Added for general use: + * # prefix for alternate format: + * 0x (0X) for hex + * leading 0 for octal + * + print '+' if positive + * blank print ' ' if positive + * + * z signed hexadecimal + * r signed, 'radix' + * n unsigned, 'radix' + * + * D,U,O,Z same as corresponding lower-case versions + * (compatibility) + */ +/* + * Added ANSI %p for pointers. Output looks like 0x%08x. + */ +/* + * + * Added special for L4-use: %t format + * + * prints L4-threadids. standard format is "task.thread". Field-width + * may be specified with width-modifier. Padding begins with threadid, + * up to 2 chars, task-part follows. + * + * modifiers: + * # surrounds output with square brackets [] + * l prints the high and low part of a threadid + * fixed length for the dwords: 8 chars + * 0 as usual, padding after optional '[' + * - as usual + * + * Jork Loeser 9/20/99 + */ + +#define isdigit(d) ((d) >= '0' && (d) <= '9') +#define Ctod(c) ((c) - '0') + +#define MAXBUF (sizeof(long int) * 8) /* enough for binary */ + +static char digs[] = "0123456789abcdef"; + +static void +printnum(u, base, putc, putc_arg) + register unsigned long u; /* number to print */ + register int base; + void (*putc)(); + char *putc_arg; +{ + char buf[MAXBUF]; /* build number here */ + register char * p = &buf[MAXBUF-1]; + + do { + *p-- = digs[u % base]; + u /= base; + } while (u != 0); + + while (++p != &buf[MAXBUF]) + (*putc)(putc_arg, *p); +} + +static void +printnum_16(u, putc, putc_arg) + register unsigned long u; /* number to print */ + void (*putc)(); + char *putc_arg; +{ + char buf[8]; /* build number here */ + register char * p = &buf[7]; + int i; + + for(i=0; i<8;i++){ + *p-- = digs[u & 0x0f]; + u >>= 4; + }; + + for(i=0;i<8;i++){ + (*putc)(putc_arg, buf[i]); + } +} + +boolean_t _doprnt_truncates = FALSE; + +void _doprnt(fmt, args, radix, putc, putc_arg) + register const char *fmt; + va_list args; + int radix; /* default radix - for '%r' */ + void (*putc)(); /* character output */ + char *putc_arg; /* argument for putc */ +{ + int length; + int prec; + boolean_t ladjust; + char padc; + long long n, m; + unsigned long long u; + int plus_sign; + int sign_char; + boolean_t altfmt, truncate, upcase; + int base; + char c; + int longopt; + + while (*fmt != '\0') { + if (*fmt != '%') { + (*putc)(putc_arg, *fmt++); + continue; + } + + fmt++; + + length = 0; + prec = -1; + ladjust = FALSE; + padc = ' '; + plus_sign = 0; + sign_char = 0; + altfmt = FALSE; + longopt = 0; + + while (TRUE) { + if (*fmt == '#') { + altfmt = TRUE; + fmt++; + } + else if (*fmt == '-') { + ladjust = TRUE; + fmt++; + } + else if (*fmt == '+') { + plus_sign = '+'; + fmt++; + } + else if (*fmt == ' ') { + if (plus_sign == 0) + plus_sign = ' '; + fmt++; + } + else + break; + } + + if (*fmt == '0') { + padc = '0'; + fmt++; + } + + if (isdigit(*fmt)) { + while(isdigit(*fmt)) + length = 10 * length + Ctod(*fmt++); + } + else if (*fmt == '*') { + length = va_arg(args, int); + fmt++; + if (length < 0) { + ladjust = !ladjust; + length = -length; + } + } + + if (*fmt == '.') { + fmt++; + if (isdigit(*fmt)) { + prec = 0; + while(isdigit(*fmt)) + prec = 10 * prec + Ctod(*fmt++); + } + else if (*fmt == '*') { + prec = va_arg(args, int); + fmt++; + } + } + + while (*fmt == 'l'){ + longopt++; + fmt++; + } + + truncate = FALSE; + upcase = FALSE; + + switch(*fmt) { + case 'b': + case 'B': + { + register char *p; + boolean_t any; + register int i; + + u = va_arg(args, unsigned long); + p = va_arg(args, char *); + base = *p++; + printnum(u, base, putc, putc_arg); + + if (u == 0) + break; + + any = FALSE; + while ((i = *p++) != 0) { + /* NOTE: The '32' here is because ascii space */ + if (*p <= 32) { + /* + * Bit field + */ + register int j; + if (any) + (*putc)(putc_arg, ','); + else { + (*putc)(putc_arg, '<'); + any = TRUE; + } + j = *p++; + for (; (c = *p) > 32; p++) + (*putc)(putc_arg, c); + printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), + base, putc, putc_arg); + } + else if (u & (1<<(i-1))) { + if (any) + (*putc)(putc_arg, ','); + else { + (*putc)(putc_arg, '<'); + any = TRUE; + } + for (; (c = *p) > 32; p++) + (*putc)(putc_arg, c); + } + else { + for (; *p > 32; p++) + continue; + } + } + if (any) + (*putc)(putc_arg, '>'); + break; + } + + case 'c': + c = va_arg(args, int); + (*putc)(putc_arg, c); + break; + + case 't': + { + typedef struct { + unsigned version_low:10; + unsigned lthread:7; + unsigned task:11; + unsigned version_high:4; + unsigned site:17; + unsigned chief:11; + unsigned nest:4; + } tid_t; + typedef struct { + unsigned high; + unsigned low; + } lh_t; + union tid_t { + tid_t id; + lh_t lh; + } tid; + + tid = va_arg(args, union tid_t); + + if(longopt){ + + if(altfmt){ + n = 19; + } else { + n = 17; + } + + if (length > 0 && !ladjust) { + while(n < length){ + putc(putc_arg, ' '); + n++; + } + } + if(altfmt) putc(putc_arg, '['); + printnum_16( tid.lh.high, putc, putc_arg); + + putc(putc_arg, ':'); + + printnum_16( tid.lh.low, putc, putc_arg); + + if(altfmt) putc(putc_arg, ']'); + + if(length > 0 && ladjust) { + while(n < length){ + putc(putc_arg, ' '); + n++; + } + } + + } else { + + if(altfmt){ + n = 4; + } else { + n = 2; + } + + m = 1; + + m += tid.id.lthread >= 0x10; + n += tid.id.task >= 0x10; + n += tid.id.task >= 0x100; + + if (length > 0 && !ladjust && padc == ' ') { + while (n + 2 < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + if(altfmt) (*putc)(putc_arg, '['); + + if( length > 0 && !ladjust && padc == '0') { + while (n + 2 < length) { + putc(putc_arg, '0'); + n++; + } + } + + printnum(tid.id.task, 16, putc, putc_arg); + putc(putc_arg, '.'); + + if(length > 0 && !ladjust) { + while (n+m < length){ + putc(putc_arg, padc); + n++; + } + } + printnum(tid.id.lthread, 16, putc, putc_arg); + + if(altfmt) putc(putc_arg, ']'); + + if (n + m < length && ladjust) { + while (n + m < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + } + + break; + } + + case 's': + { + register char *p; + register char *p2; + + if (prec == -1) + prec = 0x7fffffff; /* MAXINT */ + + p = va_arg(args, char *); + + if (p == (char *)0) + p = ""; + + if (length > 0 && !ladjust) { + n = 0; + p2 = p; + + for (; *p != '\0' && n < prec; p++) + n++; + + p = p2; + + while (n < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + n = 0; + + while (*p != '\0') { + if (++n > prec) + break; + + (*putc)(putc_arg, *p++); + } + + if (n < length && ladjust) { + while (n < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + break; + } + + + case 'o': + truncate = _doprnt_truncates; + case 'O': + base = 8; + goto print_unsigned; + + case 'd': + truncate = _doprnt_truncates; + case 'D': + base = 10; + goto print_signed; + + case 'u': + truncate = _doprnt_truncates; + case 'U': + base = 10; + goto print_unsigned; + + case 'p': + padc = '0'; + length = 8; + /* + * We do this instead of just setting altfmt to TRUE + * because we want 0 to have a 0x in front, and we want + * eight digits after the 0x -- not just 6. + */ + (*putc)(putc_arg, '0'); + (*putc)(putc_arg, 'x'); + case 'x': + truncate = _doprnt_truncates; + base = 16; + goto print_unsigned; + case 'X': + base = 16; + upcase = TRUE; + goto print_unsigned; + + case 'z': + truncate = _doprnt_truncates; + base = 16; + goto print_signed; + case 'Z': + base = 16; + upcase = TRUE; + goto print_signed; + + case 'r': + truncate = _doprnt_truncates; + case 'R': + base = radix; + goto print_signed; + + case 'n': + truncate = _doprnt_truncates; + case 'N': + base = radix; + goto print_unsigned; + + print_signed: + if (longopt>1) + n = va_arg(args, long long); + else + n = va_arg(args, long); + if (n >= 0) { + u = n; + sign_char = plus_sign; + } + else { + u = -n; + sign_char = '-'; + } + goto print_num; + + print_unsigned: + if (longopt>1) + u = va_arg(args, unsigned long long); + else + u = va_arg(args, unsigned long); + goto print_num; + + print_num: + { + char buf[MAXBUF]; /* build number here */ + register char * p = &buf[MAXBUF-1]; + static char ldigits[] = "0123456789abcdef"; + static char udigits[] = "0123456789ABCDEF"; + char *digits = ldigits; + char *prefix = 0; + + if (truncate) u = (long)((int)(u)); + if (upcase) digits = udigits; + + if (u != 0 && altfmt) { + if (base == 8) + prefix = "0"; + else if (base == 16) + prefix = "0x"; + } + + do { + *p-- = digits[u % base]; + u /= base; + } while (u != 0); + + length -= (&buf[MAXBUF-1] - p); + if (sign_char) + length--; + if (prefix) + length -= strlen(prefix); + + if (padc == ' ' && !ladjust) { + /* blank padding goes before prefix */ + while (--length >= 0) + (*putc)(putc_arg, ' '); + } + if (sign_char) + (*putc)(putc_arg, sign_char); + if (prefix) + while (*prefix) + (*putc)(putc_arg, *prefix++); + if (padc == '0') { + /* zero padding goes after sign and prefix */ + while (--length >= 0) + (*putc)(putc_arg, '0'); + } + while (++p != &buf[MAXBUF]) + (*putc)(putc_arg, *p); + + if (ladjust) { + while (--length >= 0) + (*putc)(putc_arg, ' '); + } + break; + } + + case '\0': + fmt--; + break; + + default: + (*putc)(putc_arg, *fmt); + } + fmt++; + } +} diff --git a/410kern/stdio/doprnt.h b/410kern/stdio/doprnt.h new file mode 100644 index 0000000..d2bc0f5 --- /dev/null +++ b/410kern/stdio/doprnt.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef __DOPRNT_H_INCLUDED__ +#define __DOPRNT_H_INCLUDED__ + +#include + +void _doprnt( + register const char *fmt, + va_list args, + int radix, /* default radix - for '%r' */ + void (*putc)(), /* character output */ + char *putc_arg); /* argument for putc */ + +#endif /* __DOPRNT_H_INCLUDED__ */ diff --git a/410kern/stdio/doscan.c b/410kern/stdio/doscan.c new file mode 100644 index 0000000..f4c0a30 --- /dev/null +++ b/410kern/stdio/doscan.c @@ -0,0 +1,181 @@ +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: sscanf.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 3/93 + * + * Parse trivially simple strings + */ + +#include +#include +#include +#include +#include "doscan.h" + +/* + * All I need is a miracle ... + * to keep this from growing like all the other sscanf! + */ +int +_doscan(const char *fmt, va_list vp, + int (*getc)(void *getc_arg), + void (*ungetc)(int c, void *getc_arg), + void *getc_arg) +{ + register int c; + boolean_t neg; + boolean_t discard; + boolean_t invalid; + int vals = 0; + + while ((c = *fmt++) != 0) { + + if (c != '%') { + if (isspace(c)) + { + while (isspace(c = getc(getc_arg))); + if (c == 0) break; + ungetc(c, getc_arg); + continue; + } + else if (c == getc(getc_arg)) + continue; + else + break; /* mismatch */ + } + + discard = 0; + invalid = 1; + + more_fmt: + + c = getc(getc_arg); + if (c == 0) + break; /* end of input */ + + switch (*fmt++) { + + case 'd': + { + long n = 0; + + neg = c == '-'; + if (neg) c = getc(getc_arg); + + while (c >= '0' && c <= '9') { + n = n * 10 + (c - '0'); + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); + + if (neg) n = -n; + + /* done, store it away */ + if (!discard) + { + int *p = va_arg(vp, int *); + *p = n; + } + + break; + } + + case 'x': + { + long n = 0; + + neg = c == '-'; + if (neg) c = getc(getc_arg); + + while (1) + { + if ((c >= '0') && (c <= '9')) + n = n * 16 + (c - '0'); + else if ((c >= 'a') && (c <= 'f')) + n = n * 16 + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'F')) + n = n * 16 + (c - 'A' + 10); + else + break; + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); /* retract lookahead */ + + if (neg) n = -n; + + /* done, store it away */ + if (!discard) + { + int *p = va_arg(vp, int *); + *p = n; + } + + break; + } + + case 's': + { + char *buf = NULL; + + if (!discard) + buf = va_arg(vp, char *); + + while (c && !isspace(c)) + { + if (!discard) + *buf++ = c; + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); /* retract lookahead */ + + if (!discard) + *buf = 0; + + break; + } + + case '*': + discard = 1; + goto more_fmt; + + default: + break; + } + + if (invalid) + break; + else if (!discard) + vals++; + } + + return vals; +} + diff --git a/410kern/stdio/doscan.h b/410kern/stdio/doscan.h new file mode 100644 index 0000000..4973186 --- /dev/null +++ b/410kern/stdio/doscan.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef __DOSCAN_H_INCLUDED__ +#define __DOSCAN_H_INCLUDED__ + +int _doscan(const char *fmt, va_list vp, + int (*getc)(void *getc_arg), + void (*ungetc)(int c, void *getc_arg), + void *getc_arg); + +#endif /* __DOSCAN_H_INCLUDED__ */ diff --git a/410kern/stdio/hexdump.c b/410kern/stdio/hexdump.c new file mode 100644 index 0000000..636f21c --- /dev/null +++ b/410kern/stdio/hexdump.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +/* + * Print a buffer hexdump style. Example: + * + * .---------------------------------------------------------------------------. + * | 00000000 2e2f612e 6f757400 5445524d 3d787465 ./a.out.TERM=xte | + * | 00000010 726d0048 4f4d453d 2f616673 2f63732e rm.HOME=/afs/cs. | + * | 00000020 75746168 2e656475 2f686f6d 652f6c6f utah.edu/home/lo | + * | 00000030 6d657700 5348454c 4c3d2f62 696e2f74 mew.SHELL=/bin/t | + * | 00000040 63736800 4c4f474e 414d453d 6c6f6d65 csh.LOGNAME=lome | + * | 00000050 77005553 45523d6c 6f6d6577 00504154 w.USER=lomew.PAT | + * | 00000060 483d2f61 66732f63 732e7574 61682e65 H=/afs/cs.utah.e | + * | 00000070 64752f68 6f6d652f 6c6f6d65 772f6269 du/home/lomew/bi | + * | 00000080 6e2f4073 79733a2f 6166732f 63732e75 n/@sys:/afs/cs.u | + * | 00000090 7461682e 6564 tah.ed | + * `---------------------------------------------------------------------------' + * + * It might be useful to have an option for printing out little-endianly. + * Adapted from Godmar's hook.c. + */ +void +hexdump(void *buf, int len) +{ + int i, j; + char *b = (char *)buf; + + printf(".---------------------------------------------------------------------------.\n"); + for (i = 0; i < len; i += 16) { + printf("| %08x ", i); + for (j = i; j < i+16; j++) { + if (j % 4 == 0) + printf(" "); + if (j >= len) + printf(" "); + else + printf("%02x", (unsigned char)b[j]); + } + + printf(" "); + for (j = i; j < i+16; j++) + if (j >= len) + printf(" "); + else + printf("%c", isgraph(b[j]) ? b[j] : '.'); + printf(" |\n"); + } + printf("`---------------------------------------------------------------------------'\n"); +} diff --git a/410kern/stdio/kernel.mk b/410kern/stdio/kernel.mk new file mode 100644 index 0000000..aca1f8a --- /dev/null +++ b/410kern/stdio/kernel.mk @@ -0,0 +1,17 @@ +410KLIB_STDIO_OBJS := \ + doprnt.o \ + doscan.o \ + hexdump.o \ + printf.o \ + putchar.o \ + puts.o \ + sprintf.o \ + sscanf.o \ + + +410KLIB_STDIO_OBJS := $(410KLIB_STDIO_OBJS:%=$(410KDIR)/stdio/%) + +ALL_410KOBJS += $(410KLIB_STDIO_OBJS) +410KCLEANS += $(410KDIR)/libstdio.a + +$(410KDIR)/libstdio.a: $(410KLIB_STDIO_OBJS) diff --git a/410kern/stdio/printf.c b/410kern/stdio/printf.c new file mode 100644 index 0000000..6fdb651 --- /dev/null +++ b/410kern/stdio/printf.c @@ -0,0 +1,109 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1989 Carnegie Mellon University. + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF + * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY + * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF + * THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include +#include "doprnt.h" + +/* This version of printf is implemented in terms of putchar and puts. */ + +#define PRINTF_BUFMAX 128 + +struct printf_state { + char buf[PRINTF_BUFMAX]; + unsigned int index; +}; + +static void +flush(struct printf_state *state) +{ + int i; + + for (i = 0; i < state->index; i++) + putchar(state->buf[i]); + + state->index = 0; +} + +static void +printf_char(arg, c) + char *arg; + int c; +{ + struct printf_state *state = (struct printf_state *) arg; + + if (c == '\n') + { + state->buf[state->index] = 0; + puts(state->buf); + state->index = 0; + } + else if ((c == 0) || (state->index >= PRINTF_BUFMAX)) + { + flush(state); + putchar(c); + } + else + { + state->buf[state->index] = c; + state->index++; + } +} + +/* + * Printing (to console) + */ +int vprintf(const char *fmt, va_list args) +{ + struct printf_state state; + + state.index = 0; + _doprnt(fmt, args, 0, (void (*)())printf_char, (char *) &state); + + if (state.index != 0) + flush(&state); + + /* _doprnt currently doesn't pass back error codes, + so just assume nothing bad happened. */ + return 0; +} + +int +printf(const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vprintf(fmt, args); + va_end(args); + + return err; +} + diff --git a/410kern/stdio/putchar.c b/410kern/stdio/putchar.c new file mode 100644 index 0000000..3c467d0 --- /dev/null +++ b/410kern/stdio/putchar.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +/* 15-410 mods by de0u 2008-09-02 */ +#include +#include + +int putchar(int c) +{ + return ((unsigned char)putbyte(c)); +} + diff --git a/410kern/stdio/puts.c b/410kern/stdio/puts.c new file mode 100644 index 0000000..9ee9281 --- /dev/null +++ b/410kern/stdio/puts.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +/* Simple puts() implementation that just uses putchar(). + Note that our printf() is implemented + in terms of only puts() and putchar(), so that's all we need. + The only reason the caller might want to replace this function + is if putchar() has extremely high overhead for some reason. */ +int puts(const char *s) +{ + while (*s) + { + putchar(*s); + s++; + } + putchar('\n'); + return 0; +} + diff --git a/410kern/stdio/sprintf.c b/410kern/stdio/sprintf.c new file mode 100644 index 0000000..c667837 --- /dev/null +++ b/410kern/stdio/sprintf.c @@ -0,0 +1,104 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include "doprnt.h" + +#define SPRINTF_UNLIMITED -1 +struct sprintf_state { + char *buf; + unsigned int len; + unsigned int max; +}; + +static void +savechar(char *arg, int c) +{ + struct sprintf_state *state = (struct sprintf_state *)arg; + + if (state->max != (unsigned int)SPRINTF_UNLIMITED) + { + if (state->len >= state->max) { + state->len++; + return; + } + } + + state->len++; + *state->buf = c; + state->buf++; +} + +int vsprintf(char *s, const char *fmt, va_list args) +{ + struct sprintf_state state; + state.max = SPRINTF_UNLIMITED; + state.len = 0; + state.buf = s; + + _doprnt(fmt, args, 0, (void (*)()) savechar, (char *) &state); + *(state.buf) = '\0'; + + return state.len; +} + +int vsnprintf(char *s, int size, const char *fmt, va_list args) +{ + struct sprintf_state state; + state.max = size - 1; + state.len = 0; + state.buf = s; + + _doprnt(fmt, args, 0, (void (*)()) savechar, (char *) &state); + *(state.buf) = '\0'; + + return state.len; +} + +int sprintf(char *s, const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vsprintf(s, fmt, args); + va_end(args); + + return err; +} + +int snprintf(char *s, int size, const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vsnprintf(s, size, fmt, args); + va_end(args); + + return err; +} + diff --git a/410kern/stdio/sscanf.c b/410kern/stdio/sscanf.c new file mode 100644 index 0000000..7f48ea9 --- /dev/null +++ b/410kern/stdio/sscanf.c @@ -0,0 +1,65 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include "doscan.h" + +static int +readchar(arg) + void *arg; +{ + return *(*(unsigned char**)arg)++; +} + +static void +unchar(c, arg) + int c; + void *arg; +{ + (void)c; + (*(unsigned char**)arg)--; +} + +int vsscanf(s, fmt, args) + char *s; + char *fmt; + va_list args; +{ + return _doscan(fmt, args, readchar, unchar, &s); +} + +int sscanf(char *s, char *fmt, ...) +{ + va_list args; + int vals; + + va_start(args, fmt); + vals = vsscanf(s, fmt, args); + va_end(args); + + return vals; +} + diff --git a/410kern/stdio/stdio.h b/410kern/stdio/stdio.h new file mode 100644 index 0000000..b25b899 --- /dev/null +++ b/410kern/stdio/stdio.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_STDIO_H +#define _FLUX_MC_STDIO_H + +#ifndef ASSEMBLER +#include /* For size_t, NULL */ +#include +#include + +int putchar(int __c); +int puts(const char *__str); +int printf(const char *__format, ...) + __attribute__((__format__ (__printf__, 1, 2))); +int vprintf(const char *__format, va_list __vl); +int sprintf(char *__dest, const char *__format, ...) + __attribute__((__format__ (__printf__, 2, 3))); +int snprintf(char *__dest, size_t __size, const char *__format, ...) + __attribute__((__format__ (__printf__, 3, 4))); +int vsprintf(char *__dest, const char *__format, va_list __vl); +int vsnprintf(char *__dest, size_t __size, const char *__format, va_list __vl); +int sscanf(const char *__str, const char *__format, ...) + __attribute__((__format__ (__scanf__, 2, 3))); +void hexdump(void *buf, int len); + +#endif /* !ASSEMBLER */ + +#endif /* _FLUX_MC_STDIO_H */ diff --git a/410kern/stdlib/abs.c b/410kern/stdlib/abs.c new file mode 100644 index 0000000..3892eec --- /dev/null +++ b/410kern/stdlib/abs.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +#undef abs + +int abs(int val) +{ + return val >= 0 ? val : -val; +} + diff --git a/410kern/stdlib/atol.c b/410kern/stdlib/atol.c new file mode 100644 index 0000000..29d4fdb --- /dev/null +++ b/410kern/stdlib/atol.c @@ -0,0 +1,8 @@ +#include +#include + +long +atol(const char *str) +{ + return strtol(str, NULL, 10); +} diff --git a/410kern/stdlib/ctype.c b/410kern/stdlib/ctype.c new file mode 100644 index 0000000..2159f5a --- /dev/null +++ b/410kern/stdlib/ctype.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +int isascii(int c) +{ + return ((c) >= 0) && ((c) <= 126); +} + +int iscntrl(int c) +{ + return ((c) < ' ') || ((c) > 126); +} + +int isdigit(int c) +{ + return ((c) >= '0') && ((c) <= '9'); +} + +int isgraph(int c) +{ + return ((c) > ' ') && ((c) <= 126); +} + +int islower(int c) +{ + return (c >= 'a') && (c <= 'z'); +} + +int isprint(int c) +{ + return ((c) >= ' ') && ((c) <= 126); +} + +int isspace(int c) +{ + return ((c) == ' ') || ((c) == '\f') + || ((c) == '\n') || ((c) == '\r') + || ((c) == '\t') || ((c) == '\v'); +} + +int isupper(int c) +{ + return (c >= 'A') && (c <= 'Z'); +} + +int isxdigit(int c) +{ + return isdigit(c) || + ((c >= 'A') && (c <= 'F')) || + ((c >= 'a') && (c <= 'f')); +} + +int isalpha(int c) +{ + return islower(c) || isupper(c); +} + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +int ispunct(int c) +{ + return isgraph(c) && !isalnum(c); +} + +int toupper(int c) +{ + return ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 'A') : c; +} + +int tolower(int c) +{ + return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c; +} diff --git a/410kern/stdlib/ctype.h b/410kern/stdlib/ctype.h new file mode 100644 index 0000000..72eaa20 --- /dev/null +++ b/410kern/stdlib/ctype.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_CTYPE_H_ +#define _FLUX_MC_CTYPE_H_ + +int isascii(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int isalpha(int c); +int isalnum(int c); +int ispunct(int c); +int toupper(int c); +int tolower(int c); + + +#endif /* _FLUX_MC_CTYPE_H_ */ diff --git a/410kern/stdlib/kernel.mk b/410kern/stdlib/kernel.mk new file mode 100644 index 0000000..a91c4cc --- /dev/null +++ b/410kern/stdlib/kernel.mk @@ -0,0 +1,17 @@ +410KLIB_STDLIB_OBJS := \ + abs.o \ + atol.o \ + ctype.o \ + panic.o \ + qsort.o \ + rand.o \ + strtol.o \ + strtoul.o \ + + +410KLIB_STDLIB_OBJS := $(410KLIB_STDLIB_OBJS:%=$(410KDIR)/stdlib/%) + +ALL_410KOBJS += $(410KLIB_STDLIB_OBJS) +410KCLEANS += $(410KDIR)/libstdlib.a + +$(410KDIR)/libstdlib.a: $(410KLIB_STDLIB_OBJS) diff --git a/410kern/stdlib/panic.c b/410kern/stdlib/panic.c new file mode 100644 index 0000000..e145d93 --- /dev/null +++ b/410kern/stdlib/panic.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1996-1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include +#include +#include + +/* + * This function is called by the assert() macro defined in assert.h; + * it's also a nice simple general-purpose panic function. + */ +void panic(const char *fmt, ...) +{ + va_list vl; + + disable_interrupts(); + + va_start(vl, fmt); + sim_vprintf(fmt, vl); + va_end(vl); + + va_start(vl, fmt); + vprintf(fmt, vl); + va_end(vl); + printf("\n"); + + /* + * Nothing more to do. + */ + while(1) + continue; +} diff --git a/410kern/stdlib/qsort.c b/410kern/stdlib/qsort.c new file mode 100644 index 0000000..3c00eb6 --- /dev/null +++ b/410kern/stdlib/qsort.c @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +static inline char *med3(char *, char *, char *, int (*)()); +static inline void swapfunc(char *, char *, int, int); + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static inline void +swapfunc(a, b, n, swaptype) + char *a, *b; + int n, swaptype; +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static inline char * +med3(a, b, c, cmp) + char *a, *b, *c; + int (*cmp)(); +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void +qsort(a, n, es, cmp) + void *a; + size_t n, es; + int (*cmp)(); +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = a + es; + + pc = pd = a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/410kern/stdlib/rand.c b/410kern/stdlib/rand.c new file mode 100644 index 0000000..fcff0b5 --- /dev/null +++ b/410kern/stdlib/rand.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +static unsigned seed[2]; + +int +rand(void) +{ + seed[0] += 0xa859c317; + seed[0] += (seed[1] << 13) | (seed[1] >> 19); + seed[1] += seed[0]; + return seed[0] & 0x7FFFFFFF; +} + +void +srand(unsigned new_seed) +{ + seed[0] = seed[1] = new_seed; +} + +#if 0 /* test code */ + +#define CYCLES 100000000 + +void main(int argc, char **argv) +{ + unsigned orig_seed = atol(argv[1]); + int i; + + srand(orig_seed); + for(i = 0; i < CYCLES; i++) + { + int r = rand(); + /*printf("%08x\n", r);*/ + if ((seed[0] == orig_seed) && (seed[1] == orig_seed)) + { + printf("repeates after %d cycles\n", i); + exit(0); + } + } + printf("still not repeating after %d cycles\n", CYCLES); +} + +#endif + diff --git a/410kern/stdlib/stdlib.h b/410kern/stdlib/stdlib.h new file mode 100644 index 0000000..b1bf18a --- /dev/null +++ b/410kern/stdlib/stdlib.h @@ -0,0 +1,23 @@ +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include /* For size_t, NULL */ +#include /* "Listen to what the man says" */ + +long atol(const char *__str); +#define atoi(str) ((int)atol(str)) + +long strtol(const char *__p, char **__out_p, int __base); +unsigned long strtoul(const char *__p, char **__out_p, int __base); + +#define RAND_MAX ((signed int)0x7fffffff) +int rand(void); +void srand(unsigned new_seed); + +int abs(int val); + +void qsort(void *a, size_t n, size_t es, int (*cmp)(char*, char*)); + +void panic(const char *, ...); + +#endif diff --git a/410kern/stdlib/strtol.c b/410kern/stdlib/strtol.c new file mode 100644 index 0000000..90c4ef4 --- /dev/null +++ b/410kern/stdlib/strtol.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +long strtol(const char *p, char **out_p, int base) +{ + long v = 0; + int is_neg = 0; + + while (isspace(*p)) + p++; + if (*p == '-') + is_neg = 1, p++; + else if (*p == '+') + is_neg = 0; + if (((base == 16) || (base == 0)) && + ((*p == '0') && ((p[1] == 'x') || (p[1] == 'X')))) + { + p += 2; + base = 16; + } + if (base == 0) + { + if (*p == '0') + base = 8; + else + base = 10; + } + while (1) + { + char c = *p; + if ((c >= '0') && (c <= '9') && (c - '0' < base)) + v = (v * base) + (c - '0'); + else if ((c >= 'a') && (c <= 'z') && (c - 'a' + 10 < base)) + v = (v * base) + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'Z') && (c - 'A' + 10 < base)) + v = (v * base) + (c - 'A' + 10); + else + break; + p++; + } + if (is_neg) + v = -v; + if (out_p) *out_p = (char*)p; + return v; +} + diff --git a/410kern/stdlib/strtoul.c b/410kern/stdlib/strtoul.c new file mode 100644 index 0000000..59d8f2a --- /dev/null +++ b/410kern/stdlib/strtoul.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +unsigned long strtoul(const char *p, char **out_p, int base) +{ + unsigned long v = 0; + + while (isspace(*p)) + p++; + if (((base == 16) || (base == 0)) && + ((*p == '0') && ((p[1] == 'x') || (p[1] == 'X')))) + { + p += 2; + base = 16; + } + if (base == 0) + { + if (*p == '0') + base = 8; + else + base = 10; + } + while (1) + { + char c = *p; + if ((c >= '0') && (c <= '9') && (c - '0' < base)) + v = (v * base) + (c - '0'); + else if ((c >= 'a') && (c <= 'z') && (c - 'a' + 10 < base)) + v = (v * base) + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'Z') && (c - 'A' + 10 < base)) + v = (v * base) + (c - 'A' + 10); + else + break; + p++; + } + + if (out_p) *out_p = (char*)p; + return v; +} + diff --git a/410kern/string/kernel.mk b/410kern/string/kernel.mk new file mode 100644 index 0000000..802a6dd --- /dev/null +++ b/410kern/string/kernel.mk @@ -0,0 +1,27 @@ +410KLIB_STRING_OBJS:= \ + memcmp.o \ + memset.o \ + rindex.o \ + strcat.o \ + strchr.o \ + strcmp.o \ + strcpy.o \ + strcspn.o \ + strdup.o \ + strlen.o \ + strncat.o \ + strncmp.o \ + strncpy.o \ + strpbrk.o \ + strrchr.o \ + strspn.o \ + strstr.o \ + strtok.o \ + + +410KLIB_STRING_OBJS:= $(410KLIB_STRING_OBJS:%=$(410KDIR)/string/%) + +ALL_410KOBJS += $(410KLIB_STRING_OBJS) +410KCLEANS += $(410KDIR)/libstring.a + +$(410KDIR)/libstring.a: $(410KLIB_STRING_OBJS) diff --git a/410kern/string/memcmp.c b/410kern/string/memcmp.c new file mode 100644 index 0000000..204fd4b --- /dev/null +++ b/410kern/string/memcmp.c @@ -0,0 +1,53 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/memcmp.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcmp (s1, s2) compares the strings "s1" and "s2". + * It returns 0 if the strings are identical. It returns + * > 0 if the first character that differs into two strings + * is larger in s1 than in s2 or if s1 is longer than s2 and + * the contents are identical up to the length of s2. + * It returns < 0 if the first differing character is smaller + * in s1 than in s2 or if s1 is shorter than s2 and the + * contents are identical upto the length of s1. + */ + +int +memcmp(const void *s1v, const void *s2v, int size) +{ + register const char *s1 = s1v, *s2 = s2v; + register unsigned int a, b; + + while (size-- > 0) { + if ((a = *s1++) != (b = *s2++)) + return (a-b); + } + + return 0; +} diff --git a/410kern/string/memset.c b/410kern/string/memset.c new file mode 100644 index 0000000..6a40159 --- /dev/null +++ b/410kern/string/memset.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +void * +memset(void *tov, int c, size_t len) +{ + register char *to = tov; + + while (len-- > 0) + *to++ = c; + + return tov; +} + diff --git a/410kern/string/rindex.c b/410kern/string/rindex.c new file mode 100644 index 0000000..847b3dc --- /dev/null +++ b/410kern/string/rindex.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +char *rindex(const char *s, int c) +{ + char *it = 0; + + while (1) + { + if (*s == c) + it = (char *)s; + if (*s == 0) + return it; + s++; + } +} + diff --git a/410kern/string/strcat.c b/410kern/string/strcat.c new file mode 100644 index 0000000..b0906a0 --- /dev/null +++ b/410kern/string/strcat.c @@ -0,0 +1,38 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +char * +strcat(s, add) +register char *s, *add; +{ +register char *ret = s; + + while (*s) s++; + + while ((*s++ = *add++) != 0); + + return ret; +} diff --git a/410kern/string/strchr.c b/410kern/string/strchr.c new file mode 100644 index 0000000..5eff9e5 --- /dev/null +++ b/410kern/string/strchr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +char *strchr(const char *s, int c) +{ + while (1) + { + if (*s == c) + return (char*)s; + if (*s == 0) + return 0; + s++; + } +} + diff --git a/410kern/string/strcmp.c b/410kern/string/strcmp.c new file mode 100644 index 0000000..77cd82d --- /dev/null +++ b/410kern/string/strcmp.c @@ -0,0 +1,55 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/strcmp.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcmp (s1, s2) compares the strings "s1" and "s2". + * It returns 0 if the strings are identical. It returns + * > 0 if the first character that differs into two strings + * is larger in s1 than in s2 or if s1 is longer than s2 and + * the contents are identical up to the length of s2. + * It returns < 0 if the first differing character is smaller + * in s1 than in s2 or if s1 is shorter than s2 and the + * contents are identical upto the length of s1. + */ + +int +strcmp(s1,s2) +register unsigned char *s1, *s2; +{ +register unsigned int a, b; + + + + while ( (a = *s1++), (b = *s2++), a && b) { + if (a != b) + return (a-b); + } + + return a-b; +} diff --git a/410kern/string/strcpy.c b/410kern/string/strcpy.c new file mode 100644 index 0000000..66df3b9 --- /dev/null +++ b/410kern/string/strcpy.c @@ -0,0 +1,45 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: libmach_sa/strcpy.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcpy copies the contents of the string "from" including + * the null terminator to the string "to". A pointer to "to" + * is returned. + */ + +char * +strcpy(to,from) +register char *to, *from; +{ +register char *ret = to; + + while ((*to++ = *from++) != 0); + + return ret; +} diff --git a/410kern/string/strcspn.c b/410kern/string/strcspn.c new file mode 100644 index 0000000..97b2c91 --- /dev/null +++ b/410kern/string/strcspn.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Span the complement of string s2. + */ +size_t +strcspn(s1, s2) + const char *s1; + register const char *s2; +{ + register const char *p, *spanp; + register char c, sc; + + /* + * Stop as soon as we find any character from s2. Note that there + * must be a NUL in s2; it suffices to stop when we find that, too. + */ + for (p = s1;;) { + c = *p++; + spanp = s2; + do { + if ((sc = *spanp++) == c) + return (p - 1 - s1); + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/410kern/string/strdup.c b/410kern/string/strdup.c new file mode 100644 index 0000000..7275355 --- /dev/null +++ b/410kern/string/strdup.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + + + +char *strdup(const char *src) +{ + char *buf = malloc(strlen(src)+1); + if (buf) + strcpy(buf, src); + return buf; +} + diff --git a/410kern/string/string.h b/410kern/string/string.h new file mode 100644 index 0000000..e47934a --- /dev/null +++ b/410kern/string/string.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_STRING_H_ +#define _FLUX_MC_STRING_H_ + +#include + +size_t strlen(const char *__s); +char *strcpy(char *__dest, const char *__src); +char *strncpy(char *__dest, const char *__src, size_t __n); +char *strdup(const char *__s); +char *strcat(char *__dest, const char *__src); +char *strncat(char *__dest, const char *__src, size_t __n); +int strcmp(const char *__a, const char *__b); +int strncmp(const char *__a, const char *__b, size_t __n); +char *strchr(const char *__s, int __c); +char *strrchr(const char *__s, int __c); +char *strstr(const char *__haystack, const char *__needle); +char *strtok(char *__s, const char *__delim); +char *strpbrk(const char *__s1, const char *__s2); +size_t strspn(const char *__s1, const char *__s2); +size_t strcspn(const char *__s1, const char *__s2); + +void *memset(void *__to, int __ch, unsigned int __n); +int memcmp(const void *s1v, const void *s2v, int size); + +/* FIXME These are defined here only by tradition... we should move them. */ +void *memcpy(void *__to, const void *__from, unsigned int __n); +void *memmove(void *__to, const void *__from, unsigned int __n); + +/*** BSD compatibility functions; do not use in new code ***/ + +char *index(const char *__s, int __c); +char *rindex(const char *__s, int __c); + +void bcopy(const void *__from, void *__to, unsigned int __n); +void bzero(void *__to, unsigned int __n); + +#endif /* _FLUX_MC_STRING_H_ */ diff --git a/410kern/string/strlen.c b/410kern/string/strlen.c new file mode 100644 index 0000000..089b028 --- /dev/null +++ b/410kern/string/strlen.c @@ -0,0 +1,45 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/strlen.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strlen returns the number of characters in "string" preceeding + * the terminating null character. + */ + +int +strlen(string) + register char *string; +{ +register char *ret = string; + + while (*string++); + + return string - 1 - ret; + +} diff --git a/410kern/string/strncat.c b/410kern/string/strncat.c new file mode 100644 index 0000000..480b3b5 --- /dev/null +++ b/410kern/string/strncat.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes + * are written at dst (at most n+1 bytes being appended). Return dst. + */ +char * +strncat(dst, src, n) + char *dst; + const char *src; + register size_t n; +{ + if (n != 0) { + register char *d = dst; + register const char *s = src; + + while (*d != 0) + d++; + do { + if ((*d = *s++) == 0) + break; + d++; + } while (--n != 0); + *d = 0; + } + return (dst); +} diff --git a/410kern/string/strncmp.c b/410kern/string/strncmp.c new file mode 100644 index 0000000..6ce3f30 --- /dev/null +++ b/410kern/string/strncmp.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + while (1) + { + if (n <= 0) + return 0; + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + + s1++; + s2++; + n--; + } +} + diff --git a/410kern/string/strncpy.c b/410kern/string/strncpy.c new file mode 100644 index 0000000..19cf89a --- /dev/null +++ b/410kern/string/strncpy.c @@ -0,0 +1,51 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: libmach_sa/strncpy.c + * Author: Mary R. Thompson at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strncpy copies "count" characters from the "from" string to + * the "to" string. If "from" contains less than "count" characters + * "to" will be padded with null characters until exactly "count" + * characters have been written. The return value is a pointer + * to the "to" string. + */ + +char * +strncpy(to, from, count) + register char *to, *from; + register int count; +{ + register char *ret = to; + + while (count-- > 0 && (*to++ = *from++)); + + while (count-- > 0) + *to++ = '\0'; + + return ret; +} diff --git a/410kern/string/strpbrk.c b/410kern/string/strpbrk.c new file mode 100644 index 0000000..12ddef9 --- /dev/null +++ b/410kern/string/strpbrk.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(s1, s2) + register const char *s1, *s2; +{ + register const char *scanp; + register int c, sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != 0;) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} diff --git a/410kern/string/strrchr.c b/410kern/string/strrchr.c new file mode 100644 index 0000000..e7b5792 --- /dev/null +++ b/410kern/string/strrchr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +char * +strrchr(const char *s, int c) +{ + char *save; + + for (save = NULL; *s != '\0'; s++) + if (*s == c) + save = (char *)s; + + return save; +} diff --git a/410kern/string/strspn.c b/410kern/string/strspn.c new file mode 100644 index 0000000..a493f8f --- /dev/null +++ b/410kern/string/strspn.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Span the string s2 (skip characters that are in s2). + */ +size_t +strspn(s1, s2) + const char *s1; + register const char *s2; +{ + register const char *p = s1, *spanp; + register char c, sc; + + /* + * Skip any characters in s2, excluding the terminating \0. + */ +cont: + c = *p++; + for (spanp = s2; (sc = *spanp++) != 0;) + if (sc == c) + goto cont; + return (p - 1 - s1); +} diff --git a/410kern/string/strstr.c b/410kern/string/strstr.c new file mode 100644 index 0000000..7c2fb55 --- /dev/null +++ b/410kern/string/strstr.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +char *strstr(const char *haystack, const char *needle) +{ + int hlen = strlen(haystack); + int nlen = strlen(needle); + + while (hlen >= nlen) + { + if (!memcmp(haystack, needle, nlen)) + return (void*)haystack; + + haystack++; + hlen--; + } + return 0; +} + diff --git a/410kern/string/strtok.c b/410kern/string/strtok.c new file mode 100644 index 0000000..ba4f85d --- /dev/null +++ b/410kern/string/strtok.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +char * +strtok(s, delim) + register char *s; + register const char *delim; +{ + register char *spanp; + register int c, sc; + char *tok; + static char *last; + + + if (s == NULL && (s = last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/410kern/toplevel.mk b/410kern/toplevel.mk new file mode 100644 index 0000000..692a270 --- /dev/null +++ b/410kern/toplevel.mk @@ -0,0 +1,46 @@ +###################### FULL BUILD TARGETS ############################ + +FINALTARGETS=kernel +FINALVERYCLEANS=$(FINALTARGETS) +FINALCLEANS=$(FINALTARGETS:%=%.gz) $(FINALTARGETS:%=%.strip) + +$(patsubst %,$(BUILDDIR)/%.o,$(FINALTARGETS)) \ + : $(BUILDDIR)/%.o \ + : \ + $(KERNEL_BOOT_HEAD) \ + $(410KDIR)/partial_%.o \ + $(STUKDIR)/partial_%.o \ + $(410KLIBS) + mkdir -p $(BUILDDIR) + $(LD) -r $(KLDFLAGS) -o $@ $(filter-out %.a,$^) \ + --start-group $(410KLIBS) --end-group + +$(FINALTARGETS) : %: $(BUILDDIR)/%.o $(BUILDDIR)/user_apps.o + $(LD) $(KLDFLAGS) -o $@ $^ +# $(LD) -T $(410KDIR)/kernel.lds $(KLDFLAGS) -o $@ $^ + + +$(patsubst %,%.strip,$(FINALTARGETS)) : %.strip : % + $(OBJCOPY) -g $< $@ + +$(patsubst %,%.gz,$(FINALTARGETS)) : %.gz : %.strip + gzip -c $< > $@ + +### Boy was that a bad idea, especially for this semester. +### Too clever by half. Sorry. +### .INTERMEDIATE: $(FINALTARGETS:%=%.strip) +.INTERMEDIATE: $(FINALTARGETS:%=%.gz) + +$(410KDIR)/bootfd.img.gz: + @echo file $(410KDIR)/bootfd.img.gz missing + @false + +$(410KDIR)/menu.lst: + @echo file $(410KDIR)/menu.lst missing + @false + +ifeq (,$(INFRASTRUCTURE_OVERRIDE_BOOTFDIMG)) +bootfd.img: $(FINALTARGETS:%=%.gz) $(410KDIR)/bootfd.img.gz $(410KDIR)/menu.lst + gzip -cd $(410KDIR)/bootfd.img.gz > $(PROJROOT)/bootfd.img + mcopy -o -i "$(PROJROOT)/bootfd.img" $(FINALTARGETS:%=%.gz) $(410KDIR)/menu.lst ::/boot/ +endif diff --git a/410kern/x86/asm.S b/410kern/x86/asm.S new file mode 100644 index 0000000..646af1c --- /dev/null +++ b/410kern/x86/asm.S @@ -0,0 +1,220 @@ +/* x86/asm.S */ +/* Copyright (c) 2014 Carnegie Mellon University */ + +#include + +.global lgdt +lgdt: + movl 4(%esp), %eax /* Swap the order of the arguments passed in */ + movl 8(%esp), %ecx + pushl %eax + pushw %cx + lgdt (%esp) /* Load the new GDTR... */ + ljmp $SEGSEL_KERNEL_CS, $lgdt_reload /* Do a longjmp to cause a GDT reload */ +lgdt_reload: + movl $SEGSEL_KERNEL_DS, %eax /* Load up the data segment selectors */ + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + addl $6, %esp /* And return */ + ret + +.global lidt +lidt: + movl 4(%esp), %eax /* Swap the order of the arguments passed in */ + movl 8(%esp), %ecx + pushl %eax + pushw %cx + lidt (%esp) /* Load the IDTR */ + addl $6, %esp /* And return */ + ret + +# asm() to .S translation contributed by asubrama, F'08 +.global idt_base +idt_base: + subl $6, %esp /* get 6 bytes for sidt */ + sidt (%esp) /* sidt loads into the address */ + movl 2(%esp), %eax /* we ignore the lower 16 bits (limit bits) */ + addl $6, %esp /* reclaim stack */ + ret /* return the higher 32 bits */ + +.global gdt_base +gdt_base: + subl $6, %esp /* get 6 bytes for sgdt */ + sgdt (%esp) /* sgdt loads into the address */ + movl 2(%esp), %eax /* we ignore the lower 16 bits (limit bits) */ + addl $6, %esp /* reclaim stack */ + ret /* return the higher 32 bits */ + + +.global disable_interrupts +disable_interrupts: + cli + ret + +.global enable_interrupts +enable_interrupts: + sti + ret + +.global rdtsc +rdtsc: + rdtsc + ret + +.global inb +inb: + xorl %eax, %eax + movw 4(%esp), %dx + in %dx, %al + ret + +.global inw +inw: + xorl %eax, %eax + movw 4(%esp), %dx + in %dx, %ax + ret + +.global ind +ind: + xorl %eax, %eax + movw 4(%esp), %dx + in %dx, %eax + ret + +.global outb +outb: + movw 4(%esp), %dx + movb 8(%esp), %al + out %al, %dx + ret + +.global outw +outw: + movw 4(%esp), %dx + movw 8(%esp), %ax + out %ax, %dx + ret + +.global outd +outd: + movw 4(%esp), %dx + movl 8(%esp), %eax + out %eax, %dx + ret + +.global get_cr0 +get_cr0: + movl %cr0, %eax + ret + +.global get_cr2 +get_cr2: + movl %cr2, %eax + ret + +.global get_cr3 +get_cr3: + movl %cr3, %eax + ret + +.global get_cr4 +get_cr4: + movl %cr4, %eax + ret + +# cr0 is special: change must be followed +# by a "far jump" (thanks, nwf). + +.global set_cr0 +set_cr0: + movl 4(%esp), %eax # fetch param + movl %eax, %cr0 # set %cr0 + pushw %cs # 16 bits of %cs + pushl $set_cr0_cont # 32 bits of %eip + ljmp *(%esp) # load %cs:%eip from stack +set_cr0_cont: + addl $6, %esp # undo pushes + ret + +.global set_cr2 +set_cr2: + movl 4(%esp), %eax + movl %eax, %cr2 + ret + +.global set_cr3 +set_cr3: + movl 4(%esp), %eax + movl %eax, %cr3 + ret + +.global set_cr4 +set_cr4: + movl 4(%esp), %eax + movl %eax, %cr4 + ret + +tss_addr: /* "inspired" by idt_base() */ + pushl %ebp + movl %esp, %ebp + + subl $6, %esp /* allocate 6 bytes for sgdt */ + sgdt (%esp) /* sgdt stores into the address */ + movl 2(%esp), %edx /* skip limit bits, fetch base address */ + addl $6, %esp /* reclaim stack */ + + movl $SEGSEL_KERNEL_TSS_IDX,%eax + movl 4(%edx,%eax,8),%ecx /* high word of TSS segment descriptor */ + movl 0(%edx,%eax,8),%eax /* low word of TSS segment descriptor */ + shr $16,%eax /* eax 15:00 is tss-base 15:00 */ + + movl %ecx,%edx /* copy descriptor high word */ + shl $16,%edx + andl $0x00FF0000,%edx + orl %edx,%eax /* eax 23:00 is tss-base 23:00 */ + + andl $0xFF000000,%ecx /* turn descriptor high word into tss-base 31:24 */ + orl %ecx,%eax /* eax is tss-base */ + + leave + ret + +# esp0 is not a register. But we can pretend! +.global get_esp0 +get_esp0: + pushl %ebp + movl %esp, %ebp + call tss_addr + addl $4,%eax /* esp0 is 4 bytes into tss */ + movl (%eax), %eax + leave + ret + +.global set_esp0 +set_esp0: + pushl %ebp + movl %esp, %ebp + call tss_addr + addl $4,%eax /* esp0 is 4 bytes into tss */ + movl 8(%ebp), %ecx /* fetch new esp0 value from stack */ + movl %ecx, (%eax) + leave + ret + +.global iodelay +iodelay: + pushl %eax + inb $0x80,%al + inb $0x80,%al + popl %eax + ret + +.global ltr +ltr: + movl 4(%esp), %eax + ltr %ax + ret diff --git a/410kern/x86/asm.h b/410kern/x86/asm.h new file mode 100644 index 0000000..1a2e5d5 --- /dev/null +++ b/410kern/x86/asm.h @@ -0,0 +1,47 @@ +/** @file x86/asm.h + * @brief x86-specific assembly functions + * @author matthewj S2008 + */ + +#ifndef X86_ASM_H +#define X86_ASM_H + +#include + +/** @brief Loads a new gdt */ +void lgdt(void *gdt, unsigned int limit); +/** @brief Loads a new idt */ +void lidt(void *idt, unsigned int limit); +/** @brief Read address of IDT */ +void *idt_base(void); +/** @brief Read address of GDT */ +void *gdt_base(void); +/** @brief Load a segment selector into the task register. */ +void ltr(unsigned int sel); + +/** @brief Disables interrupts */ +void disable_interrupts(void); +/** @brief Enables interrupts */ +void enable_interrupts(void); + +/** @brief Read from the TSC */ +uint64_t rdtsc(void); + +/** @brief Reads 1 byte from given port */ +uint8_t inb(uint16_t port); +/** @brief Reads 2 bytes from given port */ +uint16_t inw(uint16_t port); +/** @brief Reads 4 bytes from given port */ +uint32_t ind(uint16_t port); + +/** @brief Writes 1 byte to target port */ +void outb(uint16_t port, uint8_t val); +/** @brief Writes 2 bytes to target port */ +void outw(uint16_t port, uint16_t val); +/** @brief Writes 4 bytes to target port */ +void outd(uint16_t port, uint32_t val); + +/** @brief Delay 1/8 microsecond */ +void iodelay(void); + +#endif /* !X86_ASM_H */ diff --git a/410kern/x86/bcopy.S b/410kern/x86/bcopy.S new file mode 100644 index 0000000..f687231 --- /dev/null +++ b/410kern/x86/bcopy.S @@ -0,0 +1,135 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include + + +#if 0 /* is this useful? */ + +/* l2rbcopy(from, to, bcount) */ + +ENTRY(l2rbcopy) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG2,%edx + movl B_ARG1,%edi + movl B_ARG0,%esi +/* move longs */ +0: cld + movl %edx,%ecx + sarl $2,%ecx + js 1f + rep + movsl +/* move bytes */ + movl %edx,%ecx + andl $3,%ecx + rep + movsb +1: + popl %esi + popl %edi + leave + ret +#endif + + + +/* + * bcopy - like l2rbcopy, but recognizes overlapping ranges and handles + * them correctly. + * bcopy(from, to, bytes) + * char *from, *to; + * int bytes; + */ +ENTRY(bcopy) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG0,%esi + movl B_ARG1,%edi +bcopy_common: + movl B_ARG2,%edx + leal (%esi,%edx), %eax /* from + bytes */ + cmpl %eax, %edi /* <= to */ + jae 0f + leal (%edi,%edx), %eax /* to + bytes */ + cmpl %eax, %esi /* <= from */ + jae 0f + cmpl %esi, %edi /* from > to */ + jb 0f + je 1f + + addl %edx, %esi; decl %esi + addl %edx, %edi; decl %edi + std + movl %edx,%ecx +/* move bytes backwards */ + rep + movsb + cld +1: +/* memcpy: return dest pointer */ + movl B_ARG0,%eax + popl %esi + popl %edi + leave + ret +/* move words forwards */ +0: cld + movl %edx,%ecx + sarl $2,%ecx + js 2f + rep + movsl +/* move bytes forwards */ + movl %edx,%ecx + andl $3,%ecx + rep + movsb +2: +/* memcpy: return dest pointer */ + movl B_ARG0,%eax + popl %esi + popl %edi + leave + ret + +/* memcpy(to, from, count) */ + +ENTRY(memcpy) +ENTRY(memmove) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG0,%edi + movl B_ARG1,%esi + jmp bcopy_common + diff --git a/410kern/x86/bzero.S b/410kern/x86/bzero.S new file mode 100644 index 0000000..6675745 --- /dev/null +++ b/410kern/x86/bzero.S @@ -0,0 +1,47 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bzero.S,v 1.8 1995/04/28 22:57:58 jtc Exp $") +#endif + + +ENTRY(bzero) + pushl %edi + movl S_ARG1,%edi + movl S_ARG2,%edx + + cld /* set fill direction forward */ + xorl %eax,%eax /* set fill data to 0 */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpl $16,%edx + jb L1 + + movl %edi,%ecx /* compute misalignment */ + negl %ecx + andl $3,%ecx + subl %ecx,%edx + rep /* zero until word aligned */ + stosb + + movl %edx,%ecx /* zero by words */ + shrl $2,%ecx + andl $3,%edx + rep + stosl + +L1: movl %edx,%ecx /* zero remainder by bytes */ + rep + stosb + + popl %edi + ret diff --git a/410kern/x86/cr.h b/410kern/x86/cr.h new file mode 100644 index 0000000..220bb37 --- /dev/null +++ b/410kern/x86/cr.h @@ -0,0 +1,123 @@ +/** @file x86/cr.h + * @brief Control register definitions for x86 CPUs. + */ + +#ifndef X86_CR_H +#define X86_CR_H + +/* These are #defines so that they may be used in assembler. */ + +#define CR0_PE (1 << 0) /**< Protection Enable */ +#define CR0_MP (1 << 1) /**< Monitor coProcessor (FPU) */ +#define CR0_EM (1 << 2) /**< EMulation (FPU) */ +#define CR0_TS (1 << 3) /**< Task Switched */ +#define CR0_ET (1 << 4) /**< Extension Type (FPU) */ +#define CR0_NE (1 << 5) /**< Numeric Error */ +#define CR0_WP (1 << 16) /**< Write Protect */ + /** Alignment Mask. + * + * @note On to enable alignment checks. This is not the only relevant + * bit for alignment checking -- see EFLAGS:AM. + */ +#define CR0_AM (1 << 18) +#define CR0_NW (1 << 29) /**< Not Write-through */ +#define CR0_CD (1 << 30) /**< Cache Disable */ +#define CR0_PG (1 << 31) /**< PaGing */ + +/* CR1 is reserved and contains no flags we know about */ +/* CR2 is used by #PF and contains no flags*/ + +#define CR3_PWT (1 << 3) /**< Page-level Writes Transparent */ +#define CR3_PCD (1 << 4) /**< Page-level Cache Disable */ + +#define CR4_VME (1 << 0) /**< Virtual-8086 Mode Extensions */ +#define CR4_PVI (1 << 1) /**< Protected-mode Virtual Interrupt */ +#define CR4_TSD (1 << 2) /**< Time Stamp Disable */ +#define CR4_DE (1 << 3) /**< Debugging Extensions */ +#define CR4_PSE (1 << 4) /**< Page Size Extensions */ +#define CR4_PAE (1 << 5) /**< Physical Address Extension */ +#define CR4_MCE (1 << 6) /**< Machine Check Enable */ +#define CR4_PGE (1 << 7) /**< Page Global Enable */ +#define CR4_PCE (1 << 8) /**< Performance-monitoring Counter Enable */ +#define CR4_OSFXSR (1 << 9) /**< Operating System Support FXSAVE/FXSTOR */ + /** Operating System Support for Unmasked SIMD Floating-Point Exceptions + * + * @note Intel's naming convention has gotten out of hand. + */ +#define CR4_OSXMMEXCPT (1 << 10) +#define CR4_VMXE (1 << 13) /**< Virtual-Machine eXtensions Enable */ +#define CR4_SMXE (1 << 14) /**< Safer-Mode eXtensions Enable */ + +#define CR8_TPL_MASK 0x0000000F /**< Task Priority Level (64-bit mode) */ + +#ifndef ASSEMBLER + +#include + +/** Get CR0. + * + * @note Use rarely. + */ +uint32_t get_cr0(void); + +/** Get CR2 + * + * @note Use when appropriate. + */ +uint32_t get_cr2(void); + +/** Get CR3, the root of the paging hierarchy. + * + * @note Use when appropriate. + */ +uint32_t get_cr3(void); + +/** Get CR4. + * + * @note Use rarely. + */ +uint32_t get_cr4(void); + +/** Set CR0. + * + * @note Use very rarely. + */ +void set_cr0(uint32_t); + +/** Set CR2. + * + * @note Use very rarely or not at all. + */ +void set_cr2(uint32_t); + +/** Set CR3. + * + * @note This operation implicitly flushes the TLB. + */ +void set_cr3(uint32_t); + +/** Set CR4. + * + * @note Use very rarely. + */ +void set_cr4(uint32_t); + +/* + * ESP0 is not a register. But we can pretend! + */ + +/** Get ESP0. + * + * @note Use when appropriate. + */ +uint32_t get_esp0(void); + +/** Set ESP0. + * + * @note Use when appropriate. + */ +void set_esp0(uint32_t); + +#endif /* ! ASSEMBLER */ + +#endif /* ! X86_CR_H */ diff --git a/410kern/x86/eflags.S b/410kern/x86/eflags.S new file mode 100644 index 0000000..7d7a863 --- /dev/null +++ b/410kern/x86/eflags.S @@ -0,0 +1,27 @@ +/**@file x86/eflags.S */ + + /** @brief Returns the EFLAGS register. */ +.global get_eflags +get_eflags: + /* Listen up. Because X86 loves you, there isn't a move from + * eflags to any general purpose register. However, it can be + * sent via the stack. Thus we... + */ + pushf /* Push flags to stack */ + pop %eax /* Pop flags to return */ + ret + +.global set_eflags + /** @brief Sets the EFLAGS register. */ +set_eflags: + /* The dual principle applies here as well: we have to push to + * the stack so we can pop the flags back off. This brings us to + * everybody's favorite nonvirtualizable instruction, popf. + * If you attempt to set EFLAGS:IF or other interesting bits without + * permission, the processor ignores you, whereas it "should" trigger + * a #GP fault or some other such behavior. + */ + push 4(%esp) /* Push flags to stack */ + popf /* Pop flags to EFLAGS */ + ret + diff --git a/410kern/x86/eflags.h b/410kern/x86/eflags.h new file mode 100644 index 0000000..76561c7 --- /dev/null +++ b/410kern/x86/eflags.h @@ -0,0 +1,60 @@ +/** @file 410kern/inc/x86/eflags.h + * @brief Includes symbolic names for the EFLAGS condition register. + * + * @note All bits above EFL_ID (0x00100000) are Reserved, Maintain 0. + */ + +#ifndef X86_EFLAGS_H +#define X86_EFLAGS_H + +/* These are #define rather than an enum so that they may be used + * from assembler. */ + +#define EFL_CF 0x00000001 /**< Carry Flag */ +#define EFL_RESV1 0x00000002 /**< Reserved, Maintain 1 */ +#define EFL_PF 0x00000004 /**< Parity Flag */ +#define EFL_RESV2 0x00000008 /**< Reserved, Maintain 0 */ +#define EFL_AF 0x00000010 /**< Auxiliary Flag */ +#define EFL_RESV3 0x00000020 /**< Reserved, Maintain 0 */ +#define EFL_ZF 0x00000040 /**< Zero Flag */ +#define EFL_SF 0x00000080 /**< Sign Flag */ +#define EFL_TF 0x00000100 /**< Trap Flag (single step) */ +#define EFL_IF 0x00000200 /**< Interrupt Flag */ +#define EFL_DF 0x00000400 /**< Direction Flag */ +#define EFL_OF 0x00000800 /**< Overflow Flag */ +#define EFL_IOPL_RING0 0x00000000 /**< IO only at ring 0 */ +#define EFL_IOPL_RING1 0x00001000 /**< IO only at ring 0/1 */ +#define EFL_IOPL_RING2 0x00002000 /**< IO only at ring 0/1/2 */ +#define EFL_IOPL_RING3 0x00003000 /**< IO for all and sundry */ +#define EFL_IOPL_SHIFT 12 /**< Leftshift for IOPL location */ +#define EFL_NT 0x00004000 /**< Nested Task */ +#define EFL_RESV4 0x00008000 /**< Reserved, Maintain 0 */ +#define EFL_RF 0x00010000 /**< Resume Flag */ + + /** Virtual 8086 Mode + * + * @warning THIS IS NOT RELATED to Virtual Memory "VM". Unless you + * are certain, this bit is not the bit you are looking for. + */ +#define EFL_VM 0x00020000 + + /** Alignment Check + * + * @note This bit is modifiable by user code. See CR0:AM for another. + */ +#define EFL_AC 0x00040000 + +#define EFL_VIF 0x00080000 /**< Virtual Interrupt Flag */ +#define EFL_VIP 0x00100000 /**< Virtual Interrupt Pending */ +#define EFL_ID 0x00200000 /**< IDentification Support (CPUID) */ + +#ifndef ASSEMBLER + +#include + +uint32_t get_eflags(void); +void set_eflags(uint32_t); + +#endif + +#endif /* !X86_EFLAGS_H */ diff --git a/410kern/x86/idt.h b/410kern/x86/idt.h new file mode 100644 index 0000000..97e69ab --- /dev/null +++ b/410kern/x86/idt.h @@ -0,0 +1,36 @@ +/** @file x86/idt.h + * @brief x86-specific IDT slots + * @author matthewj S2008 + */ + +#ifndef X86_IDT_H +#define X86_IDT_H + +#define IDT_DE 0 /**< Devision Error (Fault) */ +#define IDT_DB 1 /**< Debug Exception (Fault/Trap) */ +#define IDT_NMI 2 /**< Non-Maskable Interrupt (Interrupt) */ +#define IDT_BP 3 /**< Breakpoint (Trap) */ +#define IDT_OF 4 /**< Overflow (Trap) */ +#define IDT_BR 5 /**< BOUND Range exceeded (Fault) */ +#define IDT_UD 6 /**< UnDefined Opcode (Fault) */ +#define IDT_NM 7 /**< No Math coprocessor (Fault) + Device Not Available */ +#define IDT_DF 8 /**< Double Fault (Abort) */ +#define IDT_CSO 9 /**< Coprocessor Segment Overrun (Fault) */ +#define IDT_TS 10 /**< Invalid Task Segment Selector (Fault) */ +#define IDT_NP 11 /**< Segment Not Present (Fault) */ +#define IDT_SS 12 /**< Stack Segment Fault (Fault) */ +#define IDT_GP 13 /**< General Protection Fault (Fault) */ +#define IDT_PF 14 /**< Page Fault (Fault) */ + /* IDT entry 15 is reserved. */ +#define IDT_MF 16 /**< X87 Math Fault (Fault) */ +#define IDT_AC 17 /**< Alignment Check (Fault) */ +#define IDT_MC 18 /**< Machine Check (Abort) */ +#define IDT_XF 19 /**< SSE Floating Point Exception (Fault) */ + /* IDT entries 16 through 31 are reserved. */ +#define IDT_KERN_START 32 /**< Kernel-defined IDT entries start here */ + +#define IDT_ENTS 256 /* There are this many IDT entries */ +#define IDT_ENT_SIZE 8 /* An IDT entry is this size, in bytes */ + +#endif /* !X86_IDT_H */ diff --git a/410kern/x86/interrupt_defines.h b/410kern/x86/interrupt_defines.h new file mode 100644 index 0000000..2033809 --- /dev/null +++ b/410kern/x86/interrupt_defines.h @@ -0,0 +1,20 @@ +/** @file x86/interrupt_defines.h + * @brief The "simple contract" version of the PIC module. + * @author de0u + */ + +#ifndef _INTERRUPT_DEFINES_H_ +#define _INTERRUPT_DEFINES_H_ + +/* import "everything" from our backer */ +#define X86_PIC_DEFINITIONS +#include + +#define INT_CTL_PORT (MASTER_ICW) +#define INT_ACK_CURRENT (NON_SPEC_EOI) + +#ifndef ASSEMBLER +void interrupt_setup(void); +#endif /* ASSEMBLER */ + +#endif /* !_INTERRUPT_DEFINES_H_ */ diff --git a/410kern/x86/interrupts.c b/410kern/x86/interrupts.c new file mode 100644 index 0000000..476037e --- /dev/null +++ b/410kern/x86/interrupts.c @@ -0,0 +1,13 @@ +/** @file x86/interrupts.c + * @brief Implementation of the "simple contract" version of the PIC module. + * @author de0u + */ + +#include + +void +interrupt_setup(void) +{ + /* IRQ 0..15, please occupy IDT slots 32...47 */ + pic_init(X86_PIC_MASTER_IRQ_BASE, X86_PIC_SLAVE_IRQ_BASE); +} diff --git a/410kern/x86/kernel.mk b/410kern/x86/kernel.mk new file mode 100644 index 0000000..497f320 --- /dev/null +++ b/410kern/x86/kernel.mk @@ -0,0 +1,17 @@ +410K_X86_OBJS := \ + asm.o \ + bcopy.o \ + bzero.o \ + eflags.o \ + interrupts.o \ + keyhelp.o \ + keylayout.o \ + pic.o \ + rtc.o + +410K_X86_OBJS := $(410K_X86_OBJS:%=$(410KDIR)/x86/%) + +ALL_410KOBJS += $(410K_X86_OBJS) +410KCLEANS += $(410KDIR)/libx86.a + +$(410KDIR)/libx86.a: $(410K_X86_OBJS) diff --git a/410kern/x86/keyhelp.c b/410kern/x86/keyhelp.c new file mode 100644 index 0000000..7371264 --- /dev/null +++ b/410kern/x86/keyhelp.c @@ -0,0 +1,401 @@ +/** + * The 15-410 reference kernel keyboard handling code. + * + * @author Steve Muckle + * + * @author Edited by zra for the 2003-2004 season. + * + * @author Edited by mpa for spring 2004 + * + * @author Rewritten by nwf for spring 2007. + * + * @author Rewritten by aspauldi for spring 2022. + * + * Functions for turning keyboard scancodes + * into chars. + * + * Notice that we use Scancode Set 1 + */ +/*@{*/ + +#include +#include + +#include +#include + +/** Deconstructs a scancode into its relevant parts */ +/*@{*/ +#define SCANCODE_GET_PRESS(s) (!(s & 0x80)) +#define SCANCODE_GET_CODE(s) (s & 0x7F) +/*@}*/ + +/** + * Defines the current state of scancode processing. + * + * Most keys will be processed in the simple or extended states, including + * KHE_PRINT. In some situations, KHE_CTL_PAUSE and KHE_PAUSE will + * need to process longer scancodes. In such situations, key_sequence is used + * to determine which sub-state of PAUSE/CTL+PAUSE is being used. + */ +typedef enum { + KS_SIMPLE, + KS_EXT, + KS_PAUSE, + KS_CTL_PAUSE +} kb_state_t; + +/** + * This is returned as the upper bits of the result of + * process_scancode and may be interrogated more readily by + * the KH_ macros in keyhelp.h + * + * WARNING: + * The bottom bits overlap with the KH_RESULT_ codes in the + * return value. + */ +static short key_state = 0; + +/** + * Tracks which kind of key is currently being processed, and which substate + * of that processing the key is in. key_sequence is only relevent to the + * KS_PAUSE and KS_CTL_PAUSE states. + */ +/*@{*/ +static kb_state_t scan_state = KS_SIMPLE; +static int key_sequence = 0; +/*@}*/ + +/** + * Checks if the given scancode came from the numpad. + * + * @param scancode a simple scancode + * @return True if the code came from the numpad, false otherwise. + */ +static int +is_numpad_scan(int scancode) +{ + int res = 0; + + switch(scan_state) + { + case KS_SIMPLE: + res = (scancode == 0x37) || ((0x47 <= scancode) && (scancode <= 0x53)); + break; + case KS_EXT: + res = (scancode == 0x1C) || (scancode == 0x35); + break; + case KS_PAUSE: + case KS_CTL_PAUSE: + break; + default: + panic("Illegal keyboard scancode state in is_numpad_scan()"); + } + + return res; +} + +/** + * Converts the given information into a final kh_type, ready to be returned to + * the caller of process_scancode. + * + * Note that this function always considers the raw code to be present, + * regardless of its value. Intermediate states should instead return the + * current modifier state directly. + * + * This function must be called after the modifier key state has been updated. + * Additionally, this processing must happen before scan_state tranitions, + * or else the \n and / keys on the numpad may not be flagged as a numpad + * key correctly. + * + * @param pressed Set when the key is being pressed. + * @param keycode A simple scancode. + * @param code The processed character result. + * @param rcode The base character result. + * @return The final processed kh_type. + */ +static kh_type +process_result(int pressed, int keycode, + unsigned char code, unsigned char rcode) +{ + kh_type res = 0; + + reject(SCANCODE_GET_CODE(keycode) != keycode); + + /* Check if code exists. */ + if(rcode != KHE_UNDEFINED && code != KHE_UNDEFINED) + res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT); + else + code = 0; + + if(pressed) + res |= KH_RESULT_MAKE << KH_RMODS_SHIFT; + + if(is_numpad_scan(keycode)) + res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT; + + return res | ((code & KH_CHAR_SMASK) << KH_CHAR_SHIFT) + | ((rcode & KH_RAWCHAR_SMASK) << KH_RAWCHAR_SHIFT) + | (KH_RESULT_HASRAW << KH_RMODS_SHIFT) + | ((key_state & KH_STATE_SMASK) << KH_STATE_SHIFT); +} + +/** + * Uses the given code and rcode to update the modifier key state. Updates + * the code, if necessary. + * + * @param code The code to be processed and updated. + * @param rcode The raw code to be processed. + * @param pressed Set when the key event that generated the rcode was a make. + */ +static void +process_mod_key(unsigned char *code, unsigned char rcode, int pressed) +{ + int mod_key; + + reject(code == NULL); + + switch(rcode) + { + case KHE_LCTL: + mod_key = KH_LCONTROL_KEY; + break; + case KHE_RCTL: + mod_key = KH_RCONTROL_KEY; + break; + case KHE_LSHIFT: + mod_key = KH_LSHIFT_KEY; + break; + case KHE_RSHIFT: + mod_key = KH_RSHIFT_KEY; + break; + case KHE_LALT: + mod_key = KH_LALT_KEY; + break; + case KHE_RALT: + mod_key = KH_RALT_KEY; + break; + case KHE_CAPSLOCK: + mod_key = KH_CAPS_LOCK; + break; + case KHE_NUMLOCK: + mod_key = KH_NUM_LOCK; + break; + default: + mod_key = -1; + break; + } + + if(mod_key > 0) + { + /* compat */ + *code = KHE_UNDEFINED; + + if((mod_key == KH_CAPS_LOCK) || (mod_key == KH_NUM_LOCK)) /* toggle */ + key_state = (pressed) ? key_state ^ mod_key : key_state; + else /* absolute */ + key_state = (pressed) ? key_state | mod_key : key_state & ~mod_key; + } +} + +/** + * Determines which layer the processed code should come from. + * + * @param keycode a simple scancode. + * @return The layer which should be used to process the scancode. + */ +static kl_layer_t +process_simple_layer(int keycode) +{ + int shift_pressed = !!(key_state & (KH_LSHIFT_KEY | KH_RSHIFT_KEY)); + int caps_locked = !!(key_state & KH_CAPS_LOCK); + int num_locked = !!(key_state & KH_NUM_LOCK); + int ctl_pressed = !!(key_state & (KH_LCONTROL_KEY | KH_RCONTROL_KEY)); + int is_numpad = is_numpad_scan(keycode); + kl_layer_t layer = KL_BASE; + + reject(SCANCODE_GET_CODE(keycode) != keycode); + + if (ctl_pressed && (kl_get_key(KL_CTL, keycode) != KLE_LOWER)) { + layer = KL_CTL; + } else if (shift_pressed && (kl_get_key(KL_SHIFT, keycode) != KLE_LOWER)) { + layer = KL_SHIFT; + } else if ((((caps_locked != shift_pressed) && !is_numpad) || + (num_locked && is_numpad)) && + (kl_get_key(KL_LOCK, keycode) != KLE_LOWER)) { + layer = KL_LOCK; + } + + return layer; +} + +/** + * Processes scancodes in the simple state by either transitioning to the + * extended state or mapping the simple scancode to a character. + * + * @param keypress The scancode to be processed. + * @return The final kh_type to be returned by process_scancode. + */ +static kh_type +process_simple_scan(int keypress) +{ + int pressed = SCANCODE_GET_PRESS(keypress); + int keycode = SCANCODE_GET_CODE(keypress); + unsigned char code = KHE_UNDEFINED; + unsigned char rcode = KHE_UNDEFINED; + kl_layer_t code_layer = KL_BASE; + kh_type res = (key_state & KH_STATE_SMASK) << KH_STATE_SHIFT; + + switch(keypress) + { + case 0xE0: + /* Begin extended sequence */ + scan_state = KS_EXT; + break; + case 0xE1: + /* Begin pause sequence */ + scan_state = KS_PAUSE; + key_sequence = 0; + break; + default: + /* Determine the layer and process the layout. */ + code_layer = process_simple_layer(keycode); + rcode = kl_get_key(KL_BASE, keycode); + code = kl_get_key(code_layer, keycode); + + /* Perform final processing on the result */ + process_mod_key(&code, rcode, pressed); + res = process_result(pressed, keycode, code, rcode); + break; + } + + return res; +} + +/** + * Processes scancodes in the extended state. Notably, this includes + * the arrow keys as well as some of the more unusual keys + * on the keyboard. + * + * @param keypress The scancode to be processed. + * @return A fully processed kh_type result. + */ +static kh_type +process_extended_scan(int keypress) +{ + int pressed = SCANCODE_GET_PRESS(keypress); + int keycode = SCANCODE_GET_CODE(keypress); + unsigned char code = KHE_UNDEFINED; + unsigned char rcode = KHE_UNDEFINED; + kh_type res = (key_state & KH_STATE_SMASK) << KH_STATE_SHIFT; + + switch(keypress) + { + case 0x2A: /* Press */ + case 0xAA: /* Release */ + /* Fake LSHIFT (used by print and numpad keys) - intermediate state. */ + scan_state = KS_SIMPLE; + break; + case 0x46: + /* Control + Pause sequence start */ + scan_state = KS_CTL_PAUSE; + key_sequence = 0; + break; + default: + /* Get key and process. Must process_result() before state transition. */ + rcode = code = kl_get_key(KL_EXT, keycode); + process_mod_key(&code, rcode, pressed); + res = process_result(pressed, keycode, code, rcode); + scan_state = KS_SIMPLE; + break; + } + + return res; +} + +/** + * Processes scancodes in the pause states (pause/ctl+pause). + * + * Note that the original implementation of keyhelp did something undefined + * if a sequence was interrupted (it either pretended that the scancode + * wasn't interrupting the sequence or reset the state). As such, this + * implementation simply resets the state to KS_SIMPLE when a sequence is + * interrupted. + * + * @param keypress The scancode to be processed. + * @return A fully precessed kh_type. + */ +static kh_type +process_pause_scan(int keypress) +{ + /* Determine which sequence should be checked. */ + const unsigned char pause_seq[] = { 0x1D, 0x45, 0xE1, 0x9D, 0xC5 }; + const unsigned char ctl_pause_seq[] = { 0xE0, 0xC6 }; + const unsigned char *seq = (scan_state == KS_PAUSE) + ? pause_seq : ctl_pause_seq; + unsigned int seq_size = (scan_state == KS_PAUSE) + ? sizeof(pause_seq) : sizeof(ctl_pause_seq); + + int keycode = SCANCODE_GET_CODE(keypress); + kh_type res = (key_state & KH_STATE_SMASK) << KH_STATE_SHIFT; + + affirm((scan_state == KS_PAUSE) || (scan_state == KS_CTL_PAUSE)); + affirm((0 <= key_sequence) && (key_sequence < seq_size)); + + if(seq[key_sequence] == keypress) + { + key_sequence++; + if(key_sequence == seq_size) + { + /* Only makes are reported for pause. */ + res = process_result(1, keycode, KHE_PAUSE, KHE_PAUSE); + scan_state = KS_SIMPLE; + } + } else { + /* No match, reset. */ + scan_state = KS_SIMPLE; + } + + return res; +} + +/** The entrypoint to the keyboard processing library. + * + * @param keypress A raw scancode as returned by the keyboard hardware. + * @return A kh_type indicating the keyboard modifier key states, result + * modifier bits, and potentially ASCII/410 Upper Code Plane + * translations. + */ +kh_type +process_scancode(int keypress) +{ + kh_type res; + + switch(scan_state) + { + case KS_SIMPLE: + res = process_simple_scan(keypress); + break; + case KS_EXT: + res = process_extended_scan(keypress); + break; + case KS_PAUSE: + case KS_CTL_PAUSE: + res = process_pause_scan(keypress); + break; + default: + panic("Illegal keyboard scancode state in process_scancode()"); + } + + /* + * We must return at least the modifier bits. + * + * key_state needs to be cast to int without sign extension for this check + * to work (integer promotion, grr...), which is why the mask is applied. + */ + affirm(KH_STATE(res) == (key_state & KH_STATE_SMASK)); + + return res; +} + +/*@}*/ diff --git a/410kern/x86/keyhelp.h b/410kern/x86/keyhelp.h new file mode 100644 index 0000000..1a39b6d --- /dev/null +++ b/410kern/x86/keyhelp.h @@ -0,0 +1,205 @@ +#ifndef KEYHELP_H +#define KEYHELP_H + +#define KEY_IDT_ENTRY 0x21 +#define KEYBOARD_PORT 0x60 + +#ifndef ASSEMBLER + +/** Return type of process_scancode. Four bytes wide, which are broken down as + * follows: + * + * - The top two (most significant) bytes are a state field composed of the + * KH_*_KEY, KH_*_LOCK, and KH_RESULT_* values below. + * - The third byte is defined as the "raw" result and gives a cannonical, + * unshifted name for the key pressed, if KH_HASDATA() gives true + * [KH_RESULT_HASDATA on]. + * - The fourth (least significant byte) gives a "common" value of the result. + * This is the representation subject to all modifier keys. + */ +typedef int kh_type; + + /**@{ kh_type bitfield breakdown definitions */ +#define KH_STATE_SHIFT 16 +#define KH_STATE_SMASK 0x0FF00 +#define KH_RMODS_SHIFT 16 +#define KH_RMODS_SMASK 0x000F + /* Note that there are bits in neither of these MASKs; these are reserved for + * future expanson; see commentary below. + */ +#define KH_RAWCHAR_SHIFT 8 +#define KH_RAWCHAR_SMASK 0x0FF +#define KH_CHAR_SHIFT 0 +#define KH_CHAR_SMASK 0x0FF + /**@}*/ + + /**@{ Utility macros for parsing the return of process_scancode() */ + /** Extract STATE fields from return type */ +#define KH_STATE(k) ((k >> KH_STATE_SHIFT) & KH_STATE_SMASK) + /** Extract RMODS fields from return type */ +#define KH_RMODS(k) ((k >> KH_RMODS_SHIFT) & KH_RMODS_SMASK) + /** Extract RAWCHAR field from return type */ +#define KH_GETRAW(k) ((k >> KH_RAWCHAR_SHIFT) & KH_RAWCHAR_SMASK) + /** Extract CHARACTER field from return type */ +#define KH_GETCHAR(k) ((k >> KH_CHAR_SHIFT) & KH_CHAR_SMASK) + + /** Return nonzero if the CapsLock is on in the status word k */ +#define KH_CAPSLOCK(k) (!!((k>>KH_STATE_SHIFT)&KH_CAPS_LOCK)) + /** Return nonzero if either shift is down in the status word k */ +#define KH_SHIFT(k) (!!((k>>KH_STATE_SHIFT)&(KH_LSHIFT_KEY|KH_RSHIFT_KEY))) + /** Return nonzero if either ctl is down in the status word k */ +#define KH_CTL(k) (!!((k>>KH_STATE_SHIFT)&(KH_LCONTROL_KEY|KH_RCONTROL_KEY))) + /** Return nonzero if either alt is down in the status word k */ +#define KH_ALT(k) (!!((k>>KH_STATE_SHIFT)&(KH_LALT_KEY|KH_RALT_KEY))) + + /** Return nonzero if the status word k contains a raw character value */ +#define KH_HASRAW(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_HASRAW)) + /** Return nonzero if the status word k contains a character value */ +#define KH_HASDATA(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_HASDATA)) + /** Return nonzero if the status word k results are from the Numeric Pad. + * @pre Valid only if KH_HASDATA(k) is nonzero. */ +#define KH_NUMPAD(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_NUMPAD)) + /** Return nonzero if the status work k results from a key going down. + * @pre Valid only if KH_HASDATA(k) is nonzero. */ +#define KH_ISMAKE(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_MAKE)) + + /** Return nonzero if the status word k character is from the + * 410 Upper Code Plane. + * + * @pre Valid only if KH_HASDATA(k) is nonzero. */ +#define KH_ISEXTENDED(k) (!!(KH_GETCHAR(k)&0x80)) + + /** Return nonzero if the status word k raw result character is from + * the 410 Upper Code Plane. + * + * @pre Valid only if KH_HASDATA(k) is nonzero. */ +#define KH_ISRAWEXTENDED(k) (!!(KH_GETRAW(k)&0x80)) + /**@}*/ + +/**@{ key_state variables */ + /** Left shift */ +#define KH_LSHIFT_KEY 0x8000 + /** Right shift */ +#define KH_RSHIFT_KEY 0x4000 + /** Left control */ +#define KH_LCONTROL_KEY 0x2000 + /** Right control */ +#define KH_RCONTROL_KEY 0x1000 + /** Left alt */ +#define KH_LALT_KEY 0x0800 + /** Right alt */ +#define KH_RALT_KEY 0x0400 + /** Caps lock */ +#define KH_CAPS_LOCK 0x0200 + /** Num lock */ +#define KH_NUM_LOCK 0x0100 +/**@}*/ + + /* Reserved bits in range 0x00F0; these are currently NOT inside either of the + * MASKS above. + * + * @bug Currently the LGUI and RGUI modifiers are ignored. + * @bug Currently ScrollLock is not treated as a modifier. + */ + +/**@{*/ + /** Result contains a meaningful answer beyond the modifier bits. If this + * bit is OFF in the returned word, the calling implementation SHOULD NOT + * make access to either the result or the raw result. + * + * (As a debugging hint, the current implementation should be returning zeros + * in those fields in this case. If lots of zeros seem to be going to + * screen, check one's handling of this case!) + */ +#define KH_RESULT_HASRAW 0x08 + + /** Result contains a meaningful answer beyond the modifier bits and raw + * code. That is to say that this contains a translated code that you + * probably care about. + */ +#define KH_RESULT_HASDATA 0x04 + + /** Signals that the result is from the Numeric Pad. */ +#define KH_RESULT_NUMPAD 0x02 + + /** If KH_RESULT_HASDATA, this bit is asserted for MAKE events and clear for + * BREAK events. Traditional parsing logic probably only wants to emit + * chars when KH_RESULT_MAKE is turned on. + */ +#define KH_RESULT_MAKE 0x01 +/**@}*/ + +enum kh_extended_e { + /* Some control codes are returned within the ASCII encoding scheme, where + * the ASCII definition is sufficiently close to what we're after. + */ + KHE_ESCAPE = 0x1B, + KHE_BACKSPACE = '\b', + KHE_TAB = '\t', + KHE_ENTER = '\n', + KHE_DELETE = 0x7F, + + /* + * The remainder of ASCII, from 0x20 - 0x7F, is returned as ASCII. But then + * we run out of mappings and, rather than inventing a mapping to the unused + * control characters, we invent our own upper code plane, which we'll call + * the 410 Upper Code Plane. + */ + + KHE_UNDEFINED = 0x80, /**< A non-ASCII character for which we don't have an + escape sequence. Traditional results would have + been to return a '?' but this leaves the behavior + to the implementation */ + + KHE_ARROW_UP, + KHE_ARROW_LEFT, + KHE_ARROW_DOWN, + KHE_ARROW_RIGHT, + + /* Modifiers */ + KHE_LALT, + KHE_RALT, + KHE_LCTL, + KHE_RCTL, + KHE_LSHIFT, + KHE_RSHIFT, + /* KHE_LGUI, */ + /* KHE_RGUI, */ + KHE_CAPSLOCK, + KHE_NUMLOCK, + + /* F keys */ + KHE_F1, + KHE_F2, + KHE_F3, + KHE_F4, + KHE_F5, + KHE_F6, + KHE_F7, + KHE_F8, + KHE_F9, + KHE_F10, + KHE_F11, + KHE_F12, + + /* Sequenced characters */ + KHE_PAUSE, + KHE_PRINT_SCREEN, + + /* Num-pad keys */ + KHE_BEGIN, + KHE_HOME, + KHE_END, + KHE_INSERT, + KHE_PAGE_UP, + KHE_PAGE_DOWN, + + /* The "context menu" key */ + KHE_APPS, +}; + +kh_type process_scancode(int keypress); + +#endif /*!ASSEMBLER*/ + +#endif diff --git a/410kern/x86/keylayout.c b/410kern/x86/keylayout.c new file mode 100644 index 0000000..1a28472 --- /dev/null +++ b/410kern/x86/keylayout.c @@ -0,0 +1,234 @@ +/** + * @file keylayout.c + * @author Andrew Spaulding (aspauldi) + * + * Definition for the active keyboard layout, which can be changed using + * various macros. + * + * The placement of characters in the layout tables is bound to how scancodes + * are interpreted on a qwerty keyboard. Any alternative layouts must rebind + * keys with respect to this. + * + * Note that a zero in the layer table is not interpreted as 0 (or '\0'), but + * instead informs the layer preprocessing logic that it needs to return the + * empty value for that layer. This is done to ease the initialization of the + * tables, as it lets us automatically set unlisted values to the layers empty + * value. A literal 0 can be added to a table with KLE_ZERO. + */ + +#include +#include +#include + +/** Defines the list of keyboard layouts supported by the system. */ +static const unsigned char kb_layouts[KB_LAYOUT_COUNT][KL_COUNT][KL_SIZE] = { + /** Qwerty keyboard layout (default). */ + [KB_LAYOUT_QWERTY] = { + /* Base layer */ + { [0x01] = KHE_ESCAPE, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', KHE_LCTL, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', KHE_LSHIFT, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', KHE_RSHIFT, '*', + KHE_LALT, ' ', KHE_CAPSLOCK, KHE_F1, KHE_F2, KHE_F3, KHE_F4, KHE_F5, + KHE_F6, KHE_F7, KHE_F8, KHE_F9, KHE_F10, KHE_NUMLOCK, KHE_UNDEFINED, + KHE_HOME, KHE_ARROW_UP, KHE_PAGE_UP, '-', + KHE_ARROW_LEFT, KHE_BEGIN, KHE_ARROW_RIGHT, '+', + KHE_END, KHE_ARROW_DOWN, KHE_PAGE_DOWN, KHE_INSERT, KHE_DELETE, + KHE_PRINT_SCREEN, /* Alt + Print */ + [0x57] = KHE_F11, KHE_F12, /* 0x59-0x7F */ }, + + /* Lock layer */ + { /* Caps layer */ + [0x10] = 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', + [0x1E] = 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', + [0x2C] = 'Z', 'X', 'C', 'V', 'B', 'N', 'M', + /* Num layer */ + [0x47] = '7', '8', '9', + [0x4b] = '4', '5', '6', + [0x4f] = '1', '2', '3', '0', '.' }, + + /* Shift layer */ + { [0x02] = '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', + [0x1A] = '{', '}', + [0x27] = ':', '\"', '~', + [0x2B] = '|', + [0x33] = '<', '>', '?' }, + + /* Control layer */ + { [0x03] = KLE_ZERO, [0x07] = 0x1E, [0x0C] = 0x1F, + [0x10] = 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, + 0x0F, 0x10, 0x1B, 0x1D, + [0x1E] = 0x01, 0x13, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, + [0x2B] = 0x1C, 0x1A, 0x18, 0x03, 0x16, 0x02, 0x0E, 0x0D }, + + /* Extended layer. Cannot be lowered from. */ + { [0x1C] = '\n', KHE_RCTL, + [0x35] = '/', [0x37] = KHE_PRINT_SCREEN, KHE_RALT, + [0x48] = KHE_ARROW_UP, [0x4B] = KHE_ARROW_LEFT, + [0x4D] = KHE_ARROW_RIGHT, [0x50] = KHE_ARROW_DOWN, + [0x53] = KHE_DELETE, [0x5D] = KHE_APPS } + }, + + /** Dvorak keyboard layout. */ + [KB_LAYOUT_DVORAK] = { + /* Base layer */ + { [0x01] = KHE_ESCAPE, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '[', ']', '\b', '\t', + '\'', ',', '.', 'p', 'y', 'f', 'g', 'c', + 'r', 'l', '/', '=', '\n', KHE_LCTL, 'a', 'o', + 'e', 'u', 'i', 'd', 'h', 't', 'n', 's', + '-', '`', KHE_LSHIFT, '\\', ';', 'q', 'j', 'k', + 'x', 'b', 'm', 'w', 'v', 'z', KHE_RSHIFT, '*', + KHE_LALT, ' ', KHE_CAPSLOCK, KHE_F1, KHE_F2, KHE_F3, KHE_F4, KHE_F5, + KHE_F6, KHE_F7, KHE_F8, KHE_F9, KHE_F10, KHE_NUMLOCK, KHE_UNDEFINED, + KHE_HOME, KHE_ARROW_UP, KHE_PAGE_UP, '-', + KHE_ARROW_LEFT, KHE_BEGIN, KHE_ARROW_RIGHT, '+', + KHE_END, KHE_ARROW_DOWN, KHE_PAGE_DOWN, KHE_INSERT, KHE_DELETE, + KHE_PRINT_SCREEN, /* Alt + Print */ + [0x57] = KHE_F11, KHE_F12, /* 0x59-0x7F */ }, + + /* Lock layer */ + { /* Caps layer */ + [0x13] = 'P', 'Y', 'F', 'G', 'C', 'R', 'L', + [0x1E] = 'A', 'O', 'E', 'U', 'I', 'D', 'H', 'T', 'N', 'S', + [0x2D] = 'Q', 'J', 'K', 'X', 'B', 'M', 'W', 'V', 'Z', + /* Num layer */ + [0x47] = '7', '8', '9', + [0x4b] = '4', '5', '6', + [0x4f] = '1', '2', '3', '0', '.' }, + + /* Shift layer */ + { [0x02] = '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '{', '}', + [0x10] = '\"', '<', '>', + [0x1A] = '?', '+', + [0x28] = '_', '~', [0x2B] = '|', ':' }, + + /* Control layer */ + { /** @bug Still bound to qwerty. */ + [0x03] = KLE_ZERO, [0x07] = 0x1E, [0x0C] = 0x1F, + [0x10] = 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, + 0x0F, 0x10, 0x1B, 0x1D, + [0x1E] = 0x01, 0x13, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, + [0x2B] = 0x1C, 0x1A, 0x18, 0x03, 0x16, 0x02, 0x0E, 0x0D }, + + /* Extended layer. Cannot be lowered from. */ + { [0x1C] = '\n', KHE_RCTL, + [0x35] = '/', [0x37] = KHE_PRINT_SCREEN, KHE_RALT, + [0x48] = KHE_ARROW_UP, [0x4B] = KHE_ARROW_LEFT, + [0x4D] = KHE_ARROW_RIGHT, [0x50] = KHE_ARROW_DOWN, + [0x53] = KHE_DELETE, [0x5D] = KHE_APPS } + }, + + /** Colemak keyboard layout. */ + [KB_LAYOUT_COLEMAK] = { + /* Base layer */ + { [0x01] = KHE_ESCAPE, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'f', 'p', 'g', 'j', 'l', 'u', + 'y', ';', '[', ']', '\n', KHE_LCTL, 'a', 'r', + 's', 't', 'd', 'h', 'n', 'e', 'i', 'o', + '\'', '`', KHE_LSHIFT, '\\', 'z', 'x', 'c', 'v', + 'b', 'k', 'm', ',', '.', '/', KHE_RSHIFT, '*', + KHE_LALT, ' ', KHE_CAPSLOCK, KHE_F1, KHE_F2, KHE_F3, KHE_F4, KHE_F5, + KHE_F6, KHE_F7, KHE_F8, KHE_F9, KHE_F10, KHE_NUMLOCK, KHE_UNDEFINED, + KHE_HOME, KHE_ARROW_UP, KHE_PAGE_UP, '-', + KHE_ARROW_LEFT, KHE_BEGIN, KHE_ARROW_RIGHT, '+', + KHE_END, KHE_ARROW_DOWN, KHE_PAGE_DOWN, KHE_INSERT, KHE_DELETE, + KHE_PRINT_SCREEN, /* Alt + Print */ + [0x57] = KHE_F11, KHE_F12, /* 0x59-0x7F */ }, + + /* Lock layer */ + { /* Caps layer */ + [0x10] = 'Q', 'W', 'F', 'P', 'G', 'J', 'L', 'U', 'Y', + [0x1E] = 'A', 'R', 'S', 'T', 'D', 'H', 'N', 'E', 'I', 'O', + [0x2C] = 'Z', 'X', 'C', 'V', 'B', 'K', 'M', + /* Num layer */ + [0x47] = '7', '8', '9', + [0x4b] = '4', '5', '6', + [0x4f] = '1', '2', '3', '0', '.' }, + + /* Shift layer */ + { [0x02] = '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', + [0x19] = ':', '{', '}', + [0x28] = '\"', '~', + [0x2B] = '|', + [0x33] = '<', '>', '?' }, + + /* Control layer */ + { /** @bug Still bound to qwerty. */ + [0x03] = KLE_ZERO, [0x07] = 0x1E, [0x0C] = 0x1F, + [0x10] = 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, + 0x0F, 0x10, 0x1B, 0x1D, + [0x1E] = 0x01, 0x13, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, + [0x2B] = 0x1C, 0x1A, 0x18, 0x03, 0x16, 0x02, 0x0E, 0x0D }, + + /* Extended layer. Cannot be lowered from. */ + { [0x1C] = '\n', KHE_RCTL, + [0x35] = '/', [0x37] = KHE_PRINT_SCREEN, KHE_RALT, + [0x48] = KHE_ARROW_UP, [0x4B] = KHE_ARROW_LEFT, + [0x4D] = KHE_ARROW_RIGHT, [0x50] = KHE_ARROW_DOWN, + [0x53] = KHE_DELETE, [0x5D] = KHE_APPS } + } +}; + +/** + * Defines the value that layer processing should return when it finds a + * zero in the layer table. + */ +static unsigned char kb_empty[KL_COUNT] = { + [KL_BASE] = KHE_UNDEFINED, + [KL_LOCK] = KLE_LOWER, + [KL_SHIFT] = KLE_LOWER, + [KL_CTL] = KLE_LOWER, + [KL_EXT] = KHE_UNDEFINED +}; + +/** Holds the systems active keyboard layout. Qwerty by default. */ +static kb_layout_t active_layout = KB_LAYOUT_QWERTY; + +/** + * @brief Reads a key from the active keyboard layout. + * + * Attempts to read the keycode from the given layer of the current layout. + * + * It is illegal to give an invalid layer or out of range keycode. + * + * @param layer The layer to read the key from. + * @param keycode The keycode of the key to be obtained. + * @return A character representative of the key and layout, or KHE_UNDEFINED. + */ +unsigned char +kl_get_key(kl_layer_t layer, int keycode) +{ + reject((layer < 0) || (layer >= KL_COUNT)); + reject((keycode < 0) || (keycode >= KL_SIZE)); + + affirm_msg((KB_LAYOUT_MIN <= active_layout) && + (active_layout < KB_LAYOUT_COUNT), + "kl_get_key() found a corrupt active keyboard layout!"); + + // Get the key and perform pre-processing on it. + unsigned char key = kb_layouts[active_layout][layer][keycode]; + key = (key == KLE_EMPTY) ? kb_empty[layer] : key; + key = (key == KLE_ZERO) ? 0x00 : key; + return key; +} + +/** + * @brief Sets the active keyboard layout to the given layout. + * + * It is illegal to give this function an invalid layout. + * + * @param layout The layout to be set as the active layout. + * @return void + */ +void +kl_set_layout(kb_layout_t layout) +{ + reject((layout < KB_LAYOUT_MIN) || (layout >= KB_LAYOUT_COUNT)); + + active_layout = layout; +} diff --git a/410kern/x86/keylayout.h b/410kern/x86/keylayout.h new file mode 100644 index 0000000..2452ecf --- /dev/null +++ b/410kern/x86/keylayout.h @@ -0,0 +1,66 @@ +/** + * @file keylayout.h + * @author Andrew Spaulding (aspauldi) + * @brief Defines the interface and constants to be used to interract with + * and/or change the active keyboard layout. + */ + +#ifndef __KEYLAYOUT_INTERNAL_H__ +#define __KEYLAYOUT_INTERNAL_H__ + +/** The number of scancodes in a layer for a keyboard layout. */ +#define KL_SIZE 128 + +/** + * Defines the keyboard layouts supported by the system. The active keyboard + * layout may be changed by call kl_set_layout(). + * + * KB_LAYOUT_MIN and KB_LAYOUT_COUNT compare true to the minimum layout number + * and total number of keyboard layouts respectively. + */ +typedef enum { + KB_LAYOUT_MIN = 0, + KB_LAYOUT_QWERTY = KB_LAYOUT_MIN, + KB_LAYOUT_DVORAK, + KB_LAYOUT_COLEMAK, + KB_LAYOUT_COUNT +} kb_layout_t; + +/** + * Defines the layers which can be accessed in the scancode table for the + * basic plain. + * + * Finding a KLE_LOWER in a layer means that the scancode decoding logic + * will try to use the lower layer. The requirements for that layer must + * still be satisfied, however. E.g., dropping from shift to lock won't use + * numpad keys if num lock isn't on. + */ +typedef enum { + KL_BASE = 0, + KL_LOCK = 1, + KL_SHIFT = 2, + KL_CTL = 3, + KL_EXT = 4, + KL_COUNT +} kl_layer_t; + +/** + * Special values for keyboard layout layer tables. + * + * KLE_EMPTY is an alias for zero, it means the slot in the lookup table wasn't + * specified. KLE_ZERO is used to ask kl_get_key to return 0. KLE_LOWER is used + * to inform the layer processing logic that it should try the next layer down. + */ +enum { + KLE_EMPTY = 0x00, + KLE_ZERO = 0xFE, + KLE_LOWER = 0xFF, +}; + +/* Reads a key from the given layer of the active layout */ +unsigned char kl_get_key(kl_layer_t layer, int keycode); + +/* Sets the active keyboard layout */ +void kl_set_layout(kb_layout_t layout); + +#endif /* __KEYLAYOUT_INTERNAL_H__ */ diff --git a/410kern/x86/misc.h b/410kern/x86/misc.h new file mode 100644 index 0000000..2956a3d --- /dev/null +++ b/410kern/x86/misc.h @@ -0,0 +1,13 @@ +#ifndef _X86_MISC_H_ +#define _X86_MISC_H_ + +/* FIXME! This file is full of things that need better homes. */ + + /** @brief #PF thrown from user code */ +#define PF_ERRCODE_USER 0x4 + /** @brief #PF thrown due to write error */ +#define PF_ERRCODE_WRITE 0x2 + /** @brief #PF thrown due to protection error */ +#define PF_ERRCODE_PROT 0x1 + +#endif diff --git a/410kern/x86/page.h b/410kern/x86/page.h new file mode 100644 index 0000000..6a0f133 --- /dev/null +++ b/410kern/x86/page.h @@ -0,0 +1,20 @@ +/* + * page.h + * Created for use in 15-410 at CMU + * Joey Echeverria (jge) + */ + +#ifndef _PAGE_H_ +#define _PAGE_H_ + +/* Pages are 4K */ + +#ifndef PAGE_SHIFT +#define PAGE_SHIFT 12 +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE (1 << PAGE_SHIFT) +#endif + +#endif /* _PAGE_H_ */ diff --git a/410kern/x86/pic.c b/410kern/x86/pic.c new file mode 100644 index 0000000..290e4db --- /dev/null +++ b/410kern/x86/pic.c @@ -0,0 +1,123 @@ +/** @file 410kern/x86/pic.c + * @brief Provides initialization functions for the Programmable Interrupt + * Controllers. + */ + +#define X86_PIC_DEFINITIONS +#include +#include + + /** @brief Bring up the PICs on this system. + * + * @param master_base is the offset into the IDT that the first PIC + * uses for its IRQ0. (So master_base through master_base + 7 + * will be used.) + * + * @param slave_base is the offset into the IDT that the slave PIC + * uses for its IRQ0. + * + * @post This function will enable IRQs on the PICs; EFLAGS:IF still + * can be used to disable interrupts. It is therefore suggested + * that this be called before IF is enabled the first time. + * + * @note This function assumes that there are only two PICs and that + * they are layed out as is conventional in IO space and that + * they are ganged together through master's IRQ2. The last + * system that violated these assumptions went offline roughly + * forever ago. If you don't like these, use the APICs which + * are better for you anyway. + */ +void +pic_init( unsigned char master_base, unsigned char slave_base ) +{ + /* Bring the master IDT up; yes I know that the IO looks odd. + * It's supposed to be, apparently. + */ + outb( MASTER_ICW, PICM_ICW1 ); + outb( MASTER_OCW, master_base ); + outb( MASTER_OCW, PICM_ICW3 ); + outb( MASTER_OCW, PICM_ICW4 ); + + /* Same dance with the slave as with the master */ + outb( SLAVE_ICW, PICS_ICW1 ); + outb( SLAVE_OCW, slave_base ); + outb( SLAVE_OCW, PICS_ICW3 ); + outb( SLAVE_OCW, PICS_ICW4 ); + + /* Tell the master and slave that any IRQs they had outstanding + * have been acknowledged. + */ + outb( MASTER_ICW, NON_SPEC_EOI ); + outb( SLAVE_ICW, NON_SPEC_EOI ); + + /* Enable all IRQs on master and slave */ + outb ( SLAVE_OCW, 0 ); + outb ( MASTER_OCW, 0 ); +} + + /** @brief Acknowledge the master or slave correctly, based on the + * IRQ number given. + * + * @param irq The IRQ, from the master PIC's perspective, that is to + * be acknowledged. This means that 0-7 are master IRQs and + * 8-15 are slave. + */ +void +pic_acknowledge(unsigned char irq) +{ + /* Note that SEND_EOI_IRn is just n, so we don't need any fancy map */ + if ( irq <= 7 ) { + outb(MASTER_ICW, SPECIFIC_EOI | irq ); + } else if ( irq <= 15 ) { + outb(SLAVE_ICW, SPECIFIC_EOI | (irq & 0x07) ); + outb(MASTER_ICW, SPECIFIC_EOI | PICS_ICW3 ); + } else { + return; + } +} + + /** @brief Acknowledge the master PIC for an arbitrary interrupt. */ +void +pic_acknowledge_any_master(void) +{ + outb(MASTER_ICW, NON_SPEC_EOI ); +} + + /** @brief Acknowledge the slave PIC for an arbitrary interrupt. + * @note Also acknowledges the master's input from the slave. + */ +void +pic_acknowledge_any_slave(void) +{ + outb(SLAVE_ICW, NON_SPEC_EOI ); + outb(MASTER_ICW, SPECIFIC_EOI | PICS_ICW3 ); +} + + /** @brief Test if a given IRQ is active. + * + * @pre Arguably interrupts should be off. + * + * @param irq The IRQ, from the master PIC's perspective, that is to + * be acknowledged. This means that 0-7 are master IRQs and + * 8-15 are slave. + * + * @return True if active, false if not (including bogus IRQ values) + */ +int +pic_irq_active(unsigned char irq) +{ + unsigned char port; + unsigned char mask; + + if ( irq > 15 ) { + return 0; + } else if ( irq <= 7 ) { + port = MASTER_ICW; + mask = 1 << irq; + } else { + port = SLAVE_ICW; + mask = 1 << (irq - 8); + } + outb(port, READ_IS_ONRD | OCW_TEMPLATE | READ_NEXT_RD); + return ((inb(port) & mask) != 0); +} diff --git a/410kern/x86/pic.h b/410kern/x86/pic.h new file mode 100644 index 0000000..f5c6eeb --- /dev/null +++ b/410kern/x86/pic.h @@ -0,0 +1,224 @@ +/** @file 410kern/inc/x86/pic.h + * @brief Describes the Programmable Interrupt Controllers frequently + * associated with X86 machines. + * + * @note Define X86_PIC_DEFINITIONS before including this file if you + * abolutely must have the full definitions in place. This file + * is more usually included for the API it defines, not its constants. + */ + +/* Because this obnoxious ball of wax is just a lot (and boy do we mean + * a lot) of definitions, it's been lifted from gnumach, under the CMU + * license. Details follow. Let this be a lesson to you about the + * longevity of boring code! + * + * Modified by nwf@cs.jhu.edu for CMU 15-410, S2008. + * Modified again by nwf@cs.jhu.edu for CMU 14-410, S2010. The OCW2 + * values contained herein were wrong. Let _that_ be a lesson to you! + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* +Copyright (c) 1988,1989 Prime Computer, Inc. Natick, MA 01760 +All Rights Reserved. + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and +without fee is hereby granted, provided that the above +copyright notice appears in all copies and that both the +copyright notice and this permission notice appear in +supporting documentation, and that the name of Prime +Computer, Inc. not be used in advertising or publicity +pertaining to distribution of the software without +specific, written prior permission. + +THIS SOFTWARE IS PROVIDED "AS IS", AND PRIME COMPUTER, +INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN +NO EVENT SHALL PRIME COMPUTER, INC. BE LIABLE FOR ANY +SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN ACTION OF CONTRACT, NEGLIGENCE, OR +OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef X86_PIC_H +#define X86_PIC_H + +#ifdef X86_PIC_DEFINITIONS + +/* +** The following are definitions used to locate the PICs in the system +*/ + +#define ADDR_PIC_BASE 0x20 +#define OFF_ICW 0x00 +#define OFF_OCW 0x01 +#define SIZE_PIC 0x80 + +#define MASTER_ICW (ADDR_PIC_BASE + OFF_ICW) +#define MASTER_OCW (ADDR_PIC_BASE + OFF_OCW) +#define SLAVE_ICW (ADDR_PIC_BASE + OFF_ICW + SIZE_PIC) +#define SLAVE_OCW (ADDR_PIC_BASE + OFF_OCW + SIZE_PIC) + +/* +** The following banks of definitions ICW1, ICW2, ICW3, and ICW4 are used +** to define the fields of the various ICWs for initialisation of the PICs +*/ + +/* +** ICW1 +*/ + +#define ICW_TEMPLATE 0x10 + +#define LEVL_TRIGGER 0x08 +#define EDGE_TRIGGER 0x00 +#define ADDR_INTRVL4 0x04 +#define ADDR_INTRVL8 0x00 +#define SINGLE__MODE 0x02 +#define CASCADE_MODE 0x00 +#define ICW4__NEEDED 0x01 +#define NO_ICW4_NEED 0x00 + +/* +** ICW2 is used to hold the interrupt base. +*/ + +/* +** ICW3 +*/ + +#define SLAVE_ON_IR0 0x01 +#define SLAVE_ON_IR1 0x02 +#define SLAVE_ON_IR2 0x04 +#define SLAVE_ON_IR3 0x08 +#define SLAVE_ON_IR4 0x10 +#define SLAVE_ON_IR5 0x20 +#define SLAVE_ON_IR6 0x40 +#define SLAVE_ON_IR7 0x80 + +#define I_AM_SLAVE_0 0x00 +#define I_AM_SLAVE_1 0x01 +#define I_AM_SLAVE_2 0x02 +#define I_AM_SLAVE_3 0x03 +#define I_AM_SLAVE_4 0x04 +#define I_AM_SLAVE_5 0x05 +#define I_AM_SLAVE_6 0x06 +#define I_AM_SLAVE_7 0x07 + +/* +** ICW4 +*/ + +#define SNF_MODE_ENA 0x10 +#define SNF_MODE_DIS 0x00 +#define BUFSLAV_MODE 0x08 +#define BUFMSTR_MODE 0x0C +#define NONBUFD_MODE 0x00 +#define AUTO_EOI_MOD 0x02 +#define NRML_EOI_MOD 0x00 +#define I8086_EMM_MOD 0x01 +#define SET_MCS_MODE 0x00 + +/* +** OCW1 +*/ + +#define PICM_MASK 0xFF +#define PICS_MASK 0xFF + +/* +** OCW2 +*/ + +#define NON_SPEC_EOI 0x20 +#define SPECIFIC_EOI 0x60 +#define ROT_NON_SPEC 0xA0 +#define SET_ROT_AEOI 0x80 +#define RSET_ROTAEOI 0x00 +#define ROT_SPEC_EOI 0xE0 +#define SET_PRIORITY 0xC0 +#define NO_OPERATION 0x40 + +#define SEND_EOI_IR0 0x00 +#define SEND_EOI_IR1 0x01 +#define SEND_EOI_IR2 0x02 +#define SEND_EOI_IR3 0x03 +#define SEND_EOI_IR4 0x04 +#define SEND_EOI_IR5 0x05 +#define SEND_EOI_IR6 0x06 +#define SEND_EOI_IR7 0x07 + +/* +** OCW3 +*/ + +#define OCW_TEMPLATE 0x08 +#define SPECIAL_MASK 0x40 +#define MASK_MDE_SET 0x20 +#define MASK_MDE_RST 0x00 +#define POLL_COMMAND 0x04 +#define NO_POLL_CMND 0x00 +#define READ_NEXT_RD 0x02 +#define READ_IR_ONRD 0x00 +#define READ_IS_ONRD 0x01 + +/* +** Standard PIC initialization values for PCs. +*/ +#define PICM_ICW1 (ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8 \ + | CASCADE_MODE | ICW4__NEEDED) +#define PICM_ICW3 (SLAVE_ON_IR2) +#define PICM_ICW4 (SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD \ + | I8086_EMM_MOD) + +#define PICS_ICW1 (ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8 \ + | CASCADE_MODE | ICW4__NEEDED) +#define PICS_ICW3 (I_AM_SLAVE_2) +#define PICS_ICW4 (SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD \ + | I8086_EMM_MOD) + +#endif /* X86_PIC_DEFINITIONS */ + + /** @brief Default location of the master PIC's interrupts in the IDT */ +#define X86_PIC_MASTER_IRQ_BASE 0x20 + /** @brief Default location of the slave PIC's interrupts in the IDT */ +#define X86_PIC_SLAVE_IRQ_BASE 0x28 + +#ifndef ASSEMBLER + +void pic_init( unsigned char master_base, unsigned char slave_base ); +void pic_acknowledge( unsigned char irq ); +void pic_acknowledge_any_master(void); +void pic_acknowledge_any_slave(void); +int pic_irq_active( unsigned char irq ); + +#endif /* !ASSEMBLER */ + +#endif /* !X86_PIC_H */ diff --git a/410kern/x86/rtc.c b/410kern/x86/rtc.c new file mode 100644 index 0000000..027e86d --- /dev/null +++ b/410kern/x86/rtc.c @@ -0,0 +1,17 @@ +#include +#include + +int getrtcfield (int field) { + outb(RTC_PORT_OUT, field); + int bcd = inb(RTC_PORT_IN); + return (bcd & 0xF) + (bcd >> 4)*10; +} + +void gettime (time_t *time) { + time->year = getrtcfield(RTC_YEAR); + time->month = getrtcfield(RTC_MONTH); + time->day = getrtcfield(RTC_DAY); + time->hour = getrtcfield(RTC_HOURS); + time->minute = getrtcfield(RTC_MINS); + time->second = getrtcfield(RTC_SECS); +} diff --git a/410kern/x86/rtc.h b/410kern/x86/rtc.h new file mode 100644 index 0000000..059bab4 --- /dev/null +++ b/410kern/x86/rtc.h @@ -0,0 +1,27 @@ +#ifndef _RTC_H_ +#define _RTC_H_ + +#define RTC_SECS 0 +#define RTC_MINS 2 +#define RTC_HOURS 4 +#define RTC_DAY 7 +#define RTC_MONTH 8 +#define RTC_YEAR 9 + +#define RTC_PORT_OUT 0x70 +#define RTC_PORT_IN 0x71 + +typedef struct time { + int year; + int month; + int day; + int hour; + int minute; + int second; +} time_t; + +void gettime(time_t *time); + +void printtime(); + +#endif /* _RTC_H_ */ diff --git a/410kern/x86/seg.h b/410kern/x86/seg.h new file mode 100644 index 0000000..4ea7aca --- /dev/null +++ b/410kern/x86/seg.h @@ -0,0 +1,39 @@ +/** @file x86/seg.h + * @brief Predefined segment selectors + * + * @note Must match other course-specific code (e.g., head.S). + * + * @author matthewj S2008 + * @author rpearl S2012 + */ + +#ifndef X86_SEG_H +#define X86_SEG_H + +#define SEGSEL_KERNEL_TSS_IDX 1 +#define SEGSEL_KERNEL_CS_IDX 2 +#define SEGSEL_KERNEL_DS_IDX 3 +#define SEGSEL_USER_CS_IDX 4 +#define SEGSEL_USER_DS_IDX 5 +#define SEGSEL_SPARE0_IDX 6 +#define SEGSEL_SPARE1_IDX 7 +#define SEGSEL_SPARE2_IDX 8 +#define SEGSEL_SPARE3_IDX 9 + +#define GDT_SEGS 10 + +#define SEG_TYPE_TSS 0x09 +#define SEG_TYPE_DATA 0x03 +#define SEG_TYPE_CODE 0x0b + +#define SEGSEL_TSS 0x08 /**< Task Segment Selector */ +#define SEGSEL_KERNEL_CS 0x10 /**< Kernel Code Segment */ +#define SEGSEL_KERNEL_DS 0x18 /**< Kernel Data Segment */ +#define SEGSEL_USER_CS 0x23 /**< User Code Segment */ +#define SEGSEL_USER_DS 0x2b /**< User Data Segment */ +#define SEGSEL_SPARE0 0x30 /**< Spare Segment 0 (assuming RPL 0) */ +#define SEGSEL_SPARE1 0x38 /**< Spare Segment 1 (assuming RPL 0) */ +#define SEGSEL_SPARE2 0x40 /**< Spare Segment 2 (assuming RPL 0) */ +#define SEGSEL_SPARE3 0x48 /**< Spare Segment 3 (assuming RPL 0) */ + +#endif /* !X86_SEG_H */ diff --git a/410kern/x86/timer_defines.h b/410kern/x86/timer_defines.h new file mode 100644 index 0000000..35d1e35 --- /dev/null +++ b/410kern/x86/timer_defines.h @@ -0,0 +1,24 @@ +/** + * @file x86/timer_defines.h + * Date: January 15th 2003 + * Author: Steve Muckle + * + * Important defines for the timer. + * + * @bug This is, at the moment, a quite 410 specific slice of the PIT's + * capabilities. If somebody wants to, for example, drive the PC + * speaker for real, it would be great if they fleshed this out a bit + * and submitted patches. + */ +#ifndef _TIME_DEFINES_H_ +#define _TIME_DEFINES_H_ + +#define TIMER_RATE 1193182 + +#define TIMER_IDT_ENTRY 0x20 +#define TIMER_PERIOD_IO_PORT 0x40 +#define TIMER_MODE_IO_PORT 0x43 +#define TIMER_SQUARE_WAVE 0x36 +#define TIMER_ONE_SHOT 0x30 + +#endif diff --git a/410kern/x86/video_defines.h b/410kern/x86/video_defines.h new file mode 100644 index 0000000..77f64ef --- /dev/null +++ b/410kern/x86/video_defines.h @@ -0,0 +1,54 @@ +/** + * @file x86/video_defines.h + * @date January 15th 2003 + * @author Steve Muckle + * @brief Important values for console output. + */ + +#ifndef _VIDEO_DEFINES_H +#define _VIDEO_DEFINES_H + + +/* --- CRTC Register Manipulation --- */ +#define CRTC_IDX_REG 0x3d4 +#define CRTC_DATA_REG 0x3d5 +#define CRTC_CURSOR_LSB_IDX 15 +#define CRTC_CURSOR_MSB_IDX 14 + +/* --- Screen Memory --- */ +#define CONSOLE_MEM_BASE 0xB8000 + +#define CONSOLE_WIDTH 80 +#define CONSOLE_HEIGHT 25 + +/* Bits 3:0 are the foreground color, bits 6:4 are the + background color, and bit 7 specifies blink (annoying). */ +#define FGND_BLACK 0x0 +#define FGND_BLUE 0x1 +#define FGND_GREEN 0x2 +#define FGND_CYAN 0x3 +#define FGND_RED 0x4 +#define FGND_MAG 0x5 +#define FGND_BRWN 0x6 +#define FGND_LGRAY 0x7 /* Light gray. */ +#define FGND_DGRAY 0x8 /* Dark gray. */ +#define FGND_BBLUE 0x9 /* Bright blue. */ +#define FGND_BGRN 0xA /* Bright green. */ +#define FGND_BCYAN 0xB /* Bright cyan. */ +#define FGND_PINK 0xC +#define FGND_BMAG 0xD /* Bright magenta. */ +#define FGND_YLLW 0xE +#define FGND_WHITE 0xF + +#define BGND_BLACK 0x00 +#define BGND_BLUE 0x10 +#define BGND_GREEN 0x20 +#define BGND_CYAN 0x30 +#define BGND_RED 0x40 +#define BGND_MAG 0x50 +#define BGND_BRWN 0x60 +#define BGND_LGRAY 0x70 /* Light gray. */ + +#define BLINK 0x80 /* Annoying. */ + +#endif diff --git a/410user/crt0.c b/410user/crt0.c new file mode 100644 index 0000000..abe8c50 --- /dev/null +++ b/410user/crt0.c @@ -0,0 +1,19 @@ +/* @file crt0.c + * @brief The 15-410 userland C runtime setup function + * + * @note The build infrastructure "knows" that _main is the entrypoint + * function and will do the right thing as a result. + */ + +#include +#include +#include + +extern int main(int argc, char *argv[]); +extern void install_autostack(void * stack_high, void * stack_low); + +void _main(int argc, char *argv[], void *stack_high, void *stack_low) +{ + install_autostack(stack_high, stack_low); + exit(main(argc, argv)); +} diff --git a/410user/exec2obj.c b/410user/exec2obj.c new file mode 100644 index 0000000..80c1a57 --- /dev/null +++ b/410user/exec2obj.c @@ -0,0 +1,208 @@ +#include "410kern/inc/exec2obj.h" +#include +#include + +#define STABS 0 + +void print_usage() { + fprintf(stderr, "Usage: exec2obj ...\n"); + fprintf(stderr, "Creates a .s file containing a const char array for each file\n"); + fprintf(stderr, "given as an argument. Each array is initialized to the contents\n"); + fprintf(stderr, "of that file. A table of contents is also created. Look at\n"); + fprintf(stderr, "exec2obj.h for more information.\n\n"); +} + +char header[] = +#if STABS +"\t.file\t\"user_apps.c\"\n" +"\t.stabs\t\"/home/gghartma/15-410/proj2/\",100,0,0,.Ltext0\n" +"\t.stabs\t\"user_apps.c\",100,0,0,.Ltext0\n" +#endif +"\t.text\n" +".Ltext0:\n" +#if STABS +"\t.stabs\t\"gcc2_compiled.\",60,0,0,0\n" +"\t.stabs\t\"int:t(0,1)=r(0,1);-2147483648;2147483647;\",128,0,0,0\n" +"\t.stabs\t\"char:t(0,2)=r(0,2);0;127;\",128,0,0,0\n" +"\t.stabs\t\"long int:t(0,3)=r(0,3);-2147483648;2147483647;\",128,0,0,0\n" +"\t.stabs\t\"unsigned int:t(0,4)=r(0,4);0000000000000;0037777777777;\",128,0,0,0\n" +"\t.stabs\t\"long unsigned int:t(0,5)=r(0,5);0000000000000;0037777777777;\",128,0,0,0\n" +"\t.stabs\t\"long long int:t(0,6)=@s64;r(0,6);01000000000000000000000;0777777777777777777777;\",128,0,0,0\n" +"\t.stabs\t\"long long unsigned int:t(0,7)=@s64;r(0,7);0000000000000;01777777777777777777777;\",128,0,0,0\n" +"\t.stabs\t\"short int:t(0,8)=@s16;r(0,8);-32768;32767;\",128,0,0,0\n" +"\t.stabs\t\"short unsigned int:t(0,9)=@s16;r(0,9);0;65535;\",128,0,0,0\n" +"\t.stabs\t\"signed char:t(0,10)=@s8;r(0,10);-128;127;\",128,0,0,0\n" +"\t.stabs\t\"unsigned char:t(0,11)=@s8;r(0,11);0;255;\",128,0,0,0\n" +"\t.stabs\t\"float:t(0,12)=r(0,1);4;0;\",128,0,0,0\n" +"\t.stabs\t\"double:t(0,13)=r(0,1);8;0;\",128,0,0,0\n" +"\t.stabs\t\"long double:t(0,14)=r(0,1);12;0;\",128,0,0,0\n" +"\t.stabs\t\"complex int:t(0,15)=s8real:(0,1),0,32;imag:(0,1),32,32;;\",128,0,0,0\n" +"\t.stabs\t\"complex float:t(0,16)=R3;8;0;\",128,0,0,0\n" +"\t.stabs\t\"complex double:t(0,17)=R4;16;0;\",128,0,0,0\n" +"\t.stabs\t\"complex long double:t(0,18)=R5;24;0;\",128,0,0,0\n" +"\t.stabs\t\"void:t(0,19)=(0,19)\",128,0,0,0\n" +"\t.stabs\t\"__builtin_va_list:t(0,20)=*(0,2)\",128,0,0,0\n" +"\t.stabs\t\"_Bool:t(0,21)=@s8;-16\",128,0,0,0\n" +"\t.stabs\t\"user_apps.c\",130,0,0,0\n" +"\t.stabs\t\"410kern/lib/inc/exec2obj.h\",130,0,0,0\n" +"\t.stabs\t\"exec2obj_userapp_TOC_entry:t(2,1)=(2,2)=s264execname:(2,3)=ar(2,4)=r(2,4);0000000000000;0037777777777;;0;255;(2,5)=k(0,2),0,2048;execbytes:(2,6)=*(2,5),2048,32;execlen:(0,1),2080,32;;\",128,0,21,0\n" +"\t.stabn\t162,0,0,0\n" +#endif +"\t.section\t.rodata\n" + ; + +void emit_file_header(FILE *s, const char *file, int execsize) +{ + fprintf(s,".globl %s_exec2obj_userapp_code_ptr\n", file); + fprintf(s,"\t.align 32\n"); + fprintf(s,"\t.type\t%s_exec2obj_userapp_code_ptr, @object\n", file); + fprintf(s,"\t.size\t%s_exec2obj_userapp_code_ptr, %d\n", file, execsize); + fprintf(s,"%s_exec2obj_userapp_code_ptr:\n", file); +} + +int emit_file_bytes(FILE *out, FILE *in, int bytes) +{ + char line[1]; + static const size_t sz = sizeof(line) / sizeof(line[0]); + while (1) { + size_t rval = fread(line, sizeof(line[0]), sz, in); + if (rval <= 0) + break; + bytes -= rval; + fprintf(out, "\t.byte\t%d", line[0]); + char *it = line + 1; + char *end = line + rval; + while (it != end) { + fprintf(out, ",%d", *it++); + } + fprintf(out, "\n"); + } + return bytes; +} + +void emit_dir_header(FILE *out, int nrfiles) +{ + fprintf(out, ".globl exec2obj_userapp_count\n" + "\t.align 4\n" + "\t.type\texec2obj_userapp_count, @object\n" + "\t.size\texec2obj_userapp_count, 4\n" + "exec2obj_userapp_count:\n"); + fprintf(out, "\t.long\t%d\n", nrfiles); + fprintf(out, ".globl exec2obj_userapp_TOC\n" + "\t.align 32\n" + "\t.type\texec2obj_userapp_TOC, @object\n"); + fprintf(out, "\t.size\texec2obj_userapp_TOC, %d\n", sizeof(exec2obj_userapp_TOC)); + fprintf(out, "exec2obj_userapp_TOC:\n"); +} + +void emit_dir_entry(FILE *out, const char *name, int size) +{ + /* This is an awful hack, since we want the directory listing file + * named something that it can't be named on the host file system + * and can't appear in a symbol name. */ + const char *listed_name = + (strcmp(name, "__DIR_LISTING__") == 0) ? "." : name; + + fprintf(out, "\t.string\t\"%s\"\n", listed_name); + fprintf(out, "\t.zero\t%d\n", sizeof(exec2obj_userapp_TOC[0].execname) - strlen(listed_name) - 1); + fprintf(out, "\t.long\t%s_exec2obj_userapp_code_ptr\n", name); + fprintf(out, "\t.long\t%d\n", size); +} + + +void emit_dir_footer(FILE *out, int nrfiles) +{ + fprintf(out, "\t.zero\t%d\n", + sizeof(exec2obj_userapp_TOC) - nrfiles * sizeof(exec2obj_userapp_TOC[0])); + fprintf(out, +#if STABS + "\t.stabs\t\"exec2obj_userapp_count:G(1,1)=k(0,1)\",32,0,8,0\n" + "\t.stabs\t\"exec2obj_userapp_TOC:G(1,2)=ar(2,4);0;127;(1,3)=k(2,1)\",32,0,9,0\n" + "\t.stabs\t\"idle_exec2obj_userapp_code_ptr:G(1,4)=ar(2,4);0;9574;(2,5)\",32,0,2,0\n" + "\t.stabs\t\"shell_exec2obj_userapp_code_ptr:G(1,5)=ar(2,4);0;39418;(2,5)\",32,0,4,0\n" + "\t.stabs\t\"init_exec2obj_userapp_code_ptr:G(1,6)=ar(2,4);0;21722;(2,5)\",32,0,6,0\n" +#endif + "\t.text\n" +#if STABS + "\t.stabs \"\",100,0,0,.Letext\n" +#endif + ".Letext:\n" +#if STABS + "\t.section\t.note.GNU-stack,\"\",@progbits\n" + "\t.ident\t\"GCC: (GNU) 3.3.5 (Debian 1:3.3.5-13)\"\n" +#endif + ); +} + +#define MAX_FNAME 128 + +int main(int argc, char** argv) { + FILE *in; + int execsize = 0; + int file_iter = 1; + int execsizes[MAX_NUM_APP_ENTRIES]; + + char fname_buf[MAX_FNAME]; + + /* If there are no executables specified it's an error. */ + if (argc < 2) { + print_usage(); + return -1; + } + + if (argc > MAX_NUM_APP_ENTRIES + 1) { + fprintf(stderr, "Too many executables: The maximum is %d\n", MAX_NUM_APP_ENTRIES); + } + + fwrite(header, sizeof(header[0]), sizeof(header) / sizeof(header[0]) - 1, stdout); + + while (file_iter < argc) { + + strncpy(fname_buf, argv[file_iter], MAX_FNAME); + strncat(fname_buf, ".strip", MAX_FNAME - strlen(fname_buf)); + + in = fopen(fname_buf,"r"); + if (!in) { + fprintf(stderr, "Could not open %s for reading; falling back.\n",fname_buf); + + /* Open the executable. */ + in = fopen(argv[file_iter],"r"); + if (!in) { + fprintf(stderr, "Could not open %s for reading.\n",argv[file_iter]); + printf("\n\n.abort\n\n"); + return -1; + } + } + + /* Find size of executable. */ + fseek(in,0,SEEK_END); + execsize = ftell(in); + fseek(in,0,SEEK_SET); + + execsizes[file_iter] = execsize; + + + /* Output the header of the file. */ + + emit_file_header(stdout, argv[file_iter], execsize); + emit_file_bytes(stdout, in, execsize); + + fclose(in); + + /* Move on to the next file. */ + file_iter++; + } + + emit_dir_header(stdout, argc-1); + + /* Output the table of contents. */ + file_iter = 1; + + /* Output all other entries in TOC. */ + while(file_iter < argc) { + emit_dir_entry(stdout, argv[file_iter], execsizes[file_iter]); + file_iter++; + } + emit_dir_footer(stdout, argc-1); + return 0; +} diff --git a/410user/inc/410_tests.h b/410user/inc/410_tests.h new file mode 100644 index 0000000..01d0e95 --- /dev/null +++ b/410user/inc/410_tests.h @@ -0,0 +1,77 @@ +/* Test program for 15-410 project 3 Fall 2003 + * Tadashi Okoshi (slash) + */ + +#ifndef _410_TESTS_H_ +#define _410_TESTS_H_ + +#define TEST_START_CMPLT " START__TYPE_COMPLETE" +#define TEST_START_ABORT " START__TYPE_ABORT" +#define TEST_START_4EVER " START__TYPE_FOREVER" + /** An obsoleted progress detection mechanism. */ +#define TEST_START_4EVER_PROGRESS " START__TYPE_FOREVER_PROGRESS" + +#define TEST_END_SUCCESS " END__SUCCESS" +#define TEST_END_FAIL " END__FAIL" + +/*Don't change this for now. (slash)*/ +#define TEST_PFX "(^_^)_" + +#include /* lprintf() */ + +#ifndef ASSEMBLER + +#include /* report_start(), etc. */ + +/* macros added by mtomczak */ +/* macro assumptions: + 1) static char test_name[] is defined (using DEF_TEST_NAME macro) + 2) In each function, REPORT_LOCAL_INIT called before REPORT_ON_ERR +*/ + +#define DEF_TEST_NAME(x) const char *test_name = x + +#define REPORT_START_CMPLT report_start(START_CMPLT) +#define REPORT_START_ABORT report_start(START_ABORT) +#define REPORT_START_4EVER report_start(START_4EVER) + +#define REPORT_END_SUCCESS report_end(END_SUCCESS) +#define REPORT_END_FAIL report_end(END_FAIL) + +#define REPORT_LOCAL_INIT +#define REPORT_MISC(x) report_misc(x) +#define REPORT_ERR(x,code) report_err(x, code) +#define REPORT_FAIL_ERR(x,code) report_fatal(x, code) +#define REPORT_ON_ERR(exp) report_on_err(#exp, __LINE__, exp) +#define REPORT_FAILOUT_ON_ERR(exp) fatal_on_err(#exp, __LINE__, exp) + +/**************************************************/ +/*memo*/ +/* + +//At the beginning of the test code. +lprintf("%s%s%s",TEST_PFX,test_name,TEST_START_CMPLT); + or +lprintf("%s%s%s",TEST_PFX,test_name,TEST_START_ABORT); + or +lprintf("%s%s%s",TEST_PFX,test_name,TEST_START_4EVER); + +//In the test body... +.... +lprintf("%s%s%s",TEST_PFX,test_name,"foo mesg."); +lprintf("%s%s%s",TEST_PFX,test_name,"bar mesg."); +.... + +//At the end of the test (only START_CMPLT case) +lprintf("%s%s%s",TEST_PFX,test_name,TEST_END_SUCCESS); + or +lprintf("%s%s%s",TEST_PFX,test_name,TEST_END_FAIL); + +*/ + +#define TEST_PROG_ENGAGE(i) sim_fr_prog(i) +#define TEST_PROG_PROGRESS sim_fr_here() + +#endif /* !ASSEMBLER */ + +#endif /* _410_TESTS_H_ */ diff --git a/410user/inc/asm_style.h b/410user/inc/asm_style.h new file mode 100644 index 0000000..6af13da --- /dev/null +++ b/410user/inc/asm_style.h @@ -0,0 +1,126 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +#ifndef _ASM_STYLE_H_ +#define _ASM_STYLE_H_ + +/* 15-410 */ +#ifndef HAVE_P2ALIGN +#define HAVE_P2ALIGN +#endif +#ifndef __ELF__ +#define __ELF__ +#endif +/* 15-410 */ + +/* This is a more reliable delay than a few short jmps. */ +#define IODELAY pushl %eax; inb $0x80,%al; inb $0x80,%al; popl %eax + +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#ifdef i486 +#define TEXT_ALIGN 4 +#else +#define TEXT_ALIGN 2 +#endif +#define DATA_ALIGN 2 +#define ALIGN TEXT_ALIGN + +/* + * The .align directive has different meaning on the x86 when using ELF + * than when using a.out. + * Newer GNU as remedies this problem by providing .p2align and .balign. + */ +#if defined(HAVE_P2ALIGN) +# define P2ALIGN(p2) .p2align p2 +#elif defined(__ELF__) +# define P2ALIGN(p2) .align (1<<(p2)) +#else +# define P2ALIGN(p2) .align p2 +#endif + +#define LCL(x) x + +#define LB(x,n) n +#ifndef __ELF__ +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : +#define SEXT(x) "_"#x +#else +#define EXT(x) x +#define LEXT(x) x ## : +#define SEXT(x) #x +#endif +#define GLEXT(x) .globl EXT(x); LEXT(x) +#define LCLL(x) x ## : +#define gLB(n) n ## : +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f + + +/* Symbol types */ +#ifdef __ELF__ +#define FUNCSYM(x) .type x,@function +#else +#define FUNCSYM(x) /* nothing */ +#endif + + +#ifdef GPROF + +#define MCOUNT .data; gLB(9) .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); P2ALIGN(TEXT_ALIGN); LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + P2ALIGN(TEXT_ALIGN); LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; P2ALIGN(TEXT_ALIGN); gLB(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#else /* ndef GPROF */ + +#define MCOUNT +#define ENTRY(x) FUNCSYM(x); .globl EXT(x); P2ALIGN(TEXT_ALIGN); LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + P2ALIGN(TEXT_ALIGN); LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; P2ALIGN(TEXT_ALIGN); gLB(x) + +#endif /* ndef GPROF */ + + +#define Entry(x) P2ALIGN(TEXT_ALIGN); GLEXT(x) +#define DATA(x) P2ALIGN(DATA_ALIGN); GLEXT(x) + +#endif /* _ASM_STYLE_H_ */ diff --git a/410user/inc/assert.h b/410user/inc/assert.h new file mode 100644 index 0000000..0d989a8 --- /dev/null +++ b/410user/inc/assert.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + * + * Author: Bryan Ford, University of Utah CSL + */ +#ifndef _ASSERT_H_ +#define _ASSERT_H_ + +extern void panic(const char *format, ...); + +#ifndef NDEBUG +#define assert(expression) do { \ + if(!(expression)) { \ + panic("%s:%u: failed assertion `%s'", __FILE__, __LINE__, #expression);\ + } \ +} while(0) +#else +#define assert(expression) ((void)0) +#endif + +/* Extended for 15-410 at Carnegie Mellon. + * + * The following conditions are checked even if NDEBUG is defined: + * affirm(3 > 0); + * affirm_msg(3 > 0, "arithmetic broken around %d and %d", 3, 0); + * reject(0 > 3); + * reject_msg(0 > 3, "arithmetic broken around %d and %d", 0, 3); + */ + +#define affirm(expression) do { \ + if(!(expression)) { \ + panic("%s:%u: failed affirmation `%s'", \ + __FILE__, __LINE__, #expression); \ + } \ +} while(0) + +#define reject(expression) do { \ + if(expression) { \ + panic("%s:%u: rejecting result `%s'", __FILE__, __LINE__, #expression);\ + } \ +} while(0) + +#define affirm_msg(expression, ...) do { \ + if(!(expression)) { \ + panic(__VA_ARGS__); \ + } \ +} while(0) + +#define reject_msg(expression, ...) \ + affirm_msg(!(expression), __VA_ARGS__) + +#endif /* _ASSERT_H_ */ diff --git a/410user/inc/cond.h b/410user/inc/cond.h new file mode 100644 index 0000000..aa12609 --- /dev/null +++ b/410user/inc/cond.h @@ -0,0 +1,18 @@ +/** @file cond.h + * @brief This file defines the interface for condition variables. + */ + +#ifndef COND_H +#define COND_H + +#include +#include + +/* condition variable functions */ +int cond_init( cond_t *cv ); +void cond_destroy( cond_t *cv ); +void cond_wait( cond_t *cv, mutex_t *mp ); +void cond_signal( cond_t *cv ); +void cond_broadcast( cond_t *cv ); + +#endif /* COND_H */ diff --git a/410user/inc/malloc.h b/410user/inc/malloc.h new file mode 100644 index 0000000..88827f6 --- /dev/null +++ b/410user/inc/malloc.h @@ -0,0 +1,17 @@ +#include +#include + +#ifndef _MALLOC_WRAPPERS_H_ +#define _MALLOC_WRAPPERS_H_ + +void *malloc(size_t size); +void *calloc(size_t nelt, size_t eltsize); +void *realloc(void *buf, size_t new_size); +void free(void *buf); + +void *_malloc(size_t size); +void *_calloc(size_t nelt, size_t eltsize); +void *_realloc(void *buf, size_t new_size); +void _free(void *buf); + +#endif /* _MALLOC_WRAPPERS_H_ */ diff --git a/410user/inc/mutex.h b/410user/inc/mutex.h new file mode 100644 index 0000000..36ec0e1 --- /dev/null +++ b/410user/inc/mutex.h @@ -0,0 +1,15 @@ +/** @file mutex.h + * @brief This file defines the interface for mutexes. + */ + +#ifndef MUTEX_H +#define MUTEX_H + +#include + +int mutex_init( mutex_t *mp ); +void mutex_destroy( mutex_t *mp ); +void mutex_lock( mutex_t *mp ); +void mutex_unlock( mutex_t *mp ); + +#endif /* MUTEX_H */ diff --git a/410user/inc/rand.h b/410user/inc/rand.h new file mode 100644 index 0000000..6c23819 --- /dev/null +++ b/410user/inc/rand.h @@ -0,0 +1,35 @@ +/* A C-program for MT19937: Integer version */ +/* genrand() generates one pseudorandom unsigned integer (32bit) */ +/* which is uniformly distributed among 0 to 2^32-1 for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* 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., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* Any feedback is very welcome. For any question, comments, */ +/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ +/* matumoto@math.keio.ac.jp */ + +#ifndef _RAND_H +#define _RAND_H + +void sgenrand( unsigned long ); +unsigned long genrand( void ); + +#endif /* _RAND_H */ diff --git a/410user/inc/rwlock.h b/410user/inc/rwlock.h new file mode 100644 index 0000000..ad793f8 --- /dev/null +++ b/410user/inc/rwlock.h @@ -0,0 +1,20 @@ +/** @file rwlock.h + * @brief This file defines the interface to readers/writers locks + */ + +#ifndef RWLOCK_H +#define RWLOCK_H + +#define RWLOCK_READ 0 +#define RWLOCK_WRITE 1 + +#include + +/* readers/writers lock functions */ +int rwlock_init( rwlock_t *rwlock ); +void rwlock_lock( rwlock_t *rwlock, int type ); +void rwlock_unlock( rwlock_t *rwlock ); +void rwlock_destroy( rwlock_t *rwlock ); +void rwlock_downgrade( rwlock_t *rwlock); + +#endif /* RW_H */ diff --git a/410user/inc/sem.h b/410user/inc/sem.h new file mode 100644 index 0000000..8509042 --- /dev/null +++ b/410user/inc/sem.h @@ -0,0 +1,16 @@ +/** @file sem.h + * @brief This file defines the interface to semaphores + */ + +#ifndef SEM_H +#define SEM_H + +#include + +/* semaphore functions */ +int sem_init( sem_t *sem, int count ); +void sem_wait( sem_t *sem ); +void sem_signal( sem_t *sem ); +void sem_destroy( sem_t *sem ); + +#endif /* SEM_H */ diff --git a/410user/inc/stdarg.h b/410user/inc/stdarg.h new file mode 100644 index 0000000..ba9add0 --- /dev/null +++ b/410user/inc/stdarg.h @@ -0,0 +1,18 @@ +#ifndef _STDARG_H_ +#define _STDARG_H_ + +/* This is awful, but really these are compiler intrinsics, so we use the + * GNU compiler intrinsics. + */ + +#ifdef __GNUC__ +typedef __builtin_va_list va_list; +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) +#else +#error "Don't know how to use varargs not on GNUC, sorry." +#endif + +#endif diff --git a/410user/inc/stdbool.h b/410user/inc/stdbool.h new file mode 100644 index 0000000..5060f36 --- /dev/null +++ b/410user/inc/stdbool.h @@ -0,0 +1,15 @@ +/** @file stdbool.h + * @author John Gallagher (gallaghe) + */ + +#ifndef _STDBOOL_H_ +#define _STDBOOL_H_ + +#define bool _Bool + +#define false 0 +#define true 1 + +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H_ */ diff --git a/410user/inc/stddef.h b/410user/inc/stddef.h new file mode 100644 index 0000000..b321b53 --- /dev/null +++ b/410user/inc/stddef.h @@ -0,0 +1,12 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#include /* for size_t, ptrdiff_t */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define offsetof(stype,field) ((size_t)(&((stype*)NULL)->field)) + +#endif /* _STDDEF_H_ */ diff --git a/410user/inc/stdint.h b/410user/inc/stdint.h new file mode 100644 index 0000000..9bdf21c --- /dev/null +++ b/410user/inc/stdint.h @@ -0,0 +1,114 @@ +/** @file lib/stdint.h + * + * @brief Standard integer type definitions + * + * @bug The standard integer state of our library is a little questionable. + * I think types.h has become a dumping ground for things that don't fit well, + * and some of that should move here/be deleted. + * It's missing a few things that it probably should have (wchar, ptrdiff + * sizing), but I think it should be fine until students actually use those + * features. + * + * @author matthewj S2008 + @author Matt Bryant (mbryant) S'16 + */ + +#ifndef LIB_STDINT_H +#define LIB_STDINT_H + +#ifndef ASSEMBLER + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long int32_t; +typedef signed long long int64_t; + +typedef int intptr_t; +typedef unsigned int uintptr_t; + +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; + +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +#endif /* !ASSEMBLER */ + +#define UINT8_C(x) (x) +#define UINT16_C(x) (x) +#define UINT32_C(x) (x ## U) +#define UINT64_C(x) (x ## ULL) + +#define INT8_C(x) (x) +#define INT16_C(x) (x) +#define INT32_C(x) (x) +#define INT64_C(x) (x ## LL) + +#define INTMAX_C(x) (x ## LL) +#define UINTMAX_C(x) (x ## ULL) + +#define INT8_MIN (-128) +#define INT8_MAX (127) +#define INT16_MIN (-32768) +#define INT16_MAX (32767) +#define INT32_MIN (0x80000000) +#define INT32_MAX (0x7FFFFFFF) +#define INT64_MIN (0x8000000000000000LL) +#define INT64_MAX (0x7FFFFFFFFFFFFFFFLL) + +#define UINT8_MAX (255) +#define UINT16_MAX (65535) +#define UINT32_MAX (0xFFFFFFFF) +#define UINT64_MAX (0xFFFFFFFFFFFFFFFFULL) + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#endif /* !LIB_STDINT_H */ diff --git a/410user/inc/thread.h b/410user/inc/thread.h new file mode 100644 index 0000000..cd8358f --- /dev/null +++ b/410user/inc/thread.h @@ -0,0 +1,26 @@ +/** @file thread.h + * @brief This file defines thread-management interface. + * + * It should NOT contain any of the thread library internals. + * Therefore, you may NOT modify this file. + * + * However, you MAY modify user/libthread/thr_internals.h. + * + */ + + + +#ifndef THREAD_H +#define THREAD_H + +#include + +/* thread library functions */ +int thr_init( unsigned int size ); +int thr_create( void *(*func)(void *), void *args ); +int thr_join( int tid, void **statusp ); +void thr_exit( void *status ); +int thr_getid( void ); +int thr_yield( int tid ); + +#endif /* THREAD_H */ diff --git a/410user/inc/types.h b/410user/inc/types.h new file mode 100644 index 0000000..eef2003 --- /dev/null +++ b/410user/inc/types.h @@ -0,0 +1,23 @@ +/** @file lib/types.h + * @brief Defines some C standard types as well as + * wrapper types for some of the imported FLUX library code. + * @author matthewj S2008 + */ + +#ifndef LIB_TYPES_H +#define LIB_TYPES_H + +typedef unsigned int size_t; +typedef unsigned long ptrdiff_t; + +/* WRAPPERS */ + +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_t; + +typedef enum { + FALSE = 0, + TRUE +} boolean_t; + +#endif /* !LIB_TYPES_H */ diff --git a/410user/libRNG/mt19937int.c b/410user/libRNG/mt19937int.c new file mode 100644 index 0000000..809bc01 --- /dev/null +++ b/410user/libRNG/mt19937int.c @@ -0,0 +1,97 @@ +/* A C-program for MT19937: Integer version */ +/* genrand() generates one pseudorandom unsigned integer (32bit) */ +/* which is uniformly distributed among 0 to 2^32-1 for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* 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., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* Any feedback is very welcome. For any question, comments, */ +/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ +/* matumoto@math.keio.ac.jp */ + +/* modified for 15-410 at CMU by Zachary Anderson(zra) */ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0df /* constant vector a */ +#define UPPER_MASK 0x80000000 /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffff /* least significant r bits */ + +/* Tempering parameters */ +#define TEMPERING_MASK_B 0x9d2c5680 +#define TEMPERING_MASK_C 0xefc60000 +#define TEMPERING_SHIFT_U(y) (y >> 11) +#define TEMPERING_SHIFT_S(y) (y << 7) +#define TEMPERING_SHIFT_T(y) (y << 15) +#define TEMPERING_SHIFT_L(y) (y >> 18) + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializing the array with a NONZERO seed */ +void +sgenrand(seed) +unsigned long seed; +{ + /* setting initial seeds to mt[N] using */ + /* the generator Line 25 of Table 1 in */ + /* [KNUTH 1981, The Art of Computer Programming */ + /* Vol. 2 (2nd Ed.), pp102] */ + mt[0]= seed & 0xffffffff; + for (mti=1; mti= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if sgenrand() has not been called, */ + sgenrand(4357); /* a default initial seed is used */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1]; + } + for (;kk> 1) ^ mag01[y & 0x1]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]; + + mti = 0; + } + + y = mt[mti++]; + y ^= TEMPERING_SHIFT_U(y); + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; + y ^= TEMPERING_SHIFT_L(y); + + return y; +} diff --git a/410user/libRNG/user.mk b/410user/libRNG/user.mk new file mode 100644 index 0000000..29b2bb7 --- /dev/null +++ b/410user/libRNG/user.mk @@ -0,0 +1,6 @@ +410ULIB_RNG_OBJS = $(410UDIR)/libRNG/mt19937int.o + +ALL_410UOBJS += $(410ULIB_RNG_OBJS) +410UCLEANS += $(410UDIR)/libRNG.a + +$(410UDIR)/libRNG.a: $(410ULIB_RNG_OBJS) diff --git a/410user/libmalloc/malloc.c b/410user/libmalloc/malloc.c new file mode 100644 index 0000000..90bcf99 --- /dev/null +++ b/410user/libmalloc/malloc.c @@ -0,0 +1,639 @@ +/* + ****************************************************************************** + * mm-baseline.c * + * 64-bit struct-based implicit free list memory allocator * + * 15-213: Introduction to Computer Systems * + * * + * ************************************************************************ * + * DOCUMENTATION * + * * + * ** STRUCTURE. ** * + * * + * Both allocated and free blocks share the same header structure. * + * HEADER: 8-byte, aligned to 8th byte of an 16-byte aligned heap, where * + * - The lowest order bit is 1 when the block is allocated, and * + * 0 otherwise. * + * - The whole 8-byte value with the least significant bit set to 0 * + * represents the size of the block as a size_t * + * The size of a block includes the header and footer. * + * FOOTER: 8-byte, aligned to 0th byte of an 16-byte aligned heap. It * + * contains the exact copy of the block's header. * + * The minimum blocksize is 32 bytes. * + * * + * Allocated blocks contain the following: * + * HEADER, as defined above. * + * PAYLOAD: Memory allocated for program to store information. * + * FOOTER, as defined above. * + * The size of an allocated block is exactly PAYLOAD + HEADER + FOOTER. * + * * + * Free blocks contain the following: * + * HEADER, as defined above. * + * FOOTER, as defined above. * + * The size of an unallocated block is at least 32 bytes. * + * * + * Block Visualization. * + * block block+8 block+size-8 block+size * + * Allocated blocks: | HEADER | ... PAYLOAD ... | FOOTER | * + * * + * block block+8 block+size-8 block+size * + * Unallocated blocks: | HEADER | ... (empty) ... | FOOTER | * + * * + * ************************************************************************ * + * ** INITIALIZATION. ** * + * * + * The following visualization reflects the beginning of the heap. * + * start start+8 start+16 * + * INIT: | PROLOGUE_FOOTER | EPILOGUE_HEADER | * + * PROLOGUE_FOOTER: 8-byte footer, as defined above, that simulates the * + * end of an allocated block. Also serves as padding. * + * EPILOGUE_HEADER: 8-byte block indicating the end of the heap. * + * It simulates the beginning of an allocated block * + * The epilogue header is moved when the heap is extended. * + * * + * ************************************************************************ * + * ** BLOCK ALLOCATION. ** * + * * + * Upon memory request of size S, a block of size S + dsize, rounded up to * + * 16 bytes, is allocated on the heap, where dsize is 2*8 = 16. * + * Selecting the block for allocation is performed by finding the first * + * block that can fit the content based on a first-fit or next-fit search * + * policy. * + * The search starts from the beginning of the heap pointed by heap_listp. * + * It sequentially goes through each block in the implicit free list, * + * the end of the heap, until either * + * - A sufficiently-large unallocated block is found, or * + * - The end of the implicit free list is reached, which occurs * + * when no sufficiently-large unallocated block is available. * + * In case that a sufficiently-large unallocated block is found, then * + * that block will be used for allocation. Otherwise--that is, when no * + * sufficiently-large unallocated block is found--then more unallocated * + * memory of size chunksize or requested size, whichever is larger, is * + * requested through mem_sbrk, and the search is redone. * + * * + * ************************************************************************ * + * ** ADVICE FOR STUDENTS. ** * + * Step 0: Please read the writeup! * + * Write your heap checker. Write your heap checker. Write. Heap. checker. * + * Good luck, and have fun! * + * * + ****************************************************************************** + */ + +/* Do not change the following! */ +#include +#include +#include +#include +#include +#include + +#undef NDEBUG // the assert()s in this particular implementation are all O(1) and vital +#include + +#include "memlib.h" + +#define dbg_requires(...) assert(__VA_ARGS__) +#define dbg_assert(...) assert(__VA_ARGS__) +#define dbg_ensures(...) assert(__VA_ARGS__) + +/* Basic constants */ +typedef uint64_t word_t; +static const size_t wsize = sizeof(word_t); // word and header size (bytes) +static const size_t dsize = 2*sizeof(word_t); // double word size (bytes) +static const size_t min_block_size = 4*sizeof(word_t); // Minimum block size +static const size_t chunksize = (1 << 12); // requires (chunksize % 16 == 0) + +static const word_t alloc_mask = 0x1; +static const word_t size_mask = ~(word_t)0xF; + +typedef struct block +{ + /* Header contains size + allocation flag */ + word_t header; + /* + * We don't know how big the payload will be. Declaring it as an + * array of size 0 allows computing its starting address using + * pointer notation. + */ + char payload[0]; + /* + * We can't declare the footer as part of the struct, since its starting + * position is unknown + */ +} block_t; + + +/* Global variables */ +/* Pointer to first block */ +static block_t *heap_listp = NULL; + +/* Function prototypes for internal helper routines */ +static block_t *extend_heap(size_t size); +static void place(block_t *block, size_t asize); +static block_t *find_fit(size_t asize); +static block_t *coalesce(block_t *block); + +static size_t max(size_t x, size_t y); +static size_t round_up(size_t size, size_t n); +static word_t pack(size_t size, bool alloc); + +static size_t extract_size(word_t header); +static size_t get_size(block_t *block); +static size_t get_payload_size(block_t *block); + +static bool extract_alloc(word_t header); +static bool get_alloc(block_t *block); + +static void write_header(block_t *block, size_t size, bool alloc); +static void write_footer(block_t *block, size_t size, bool alloc); + +static block_t *payload_to_header(void *bp); +static void *header_to_payload(block_t *block); + +static block_t *find_next(block_t *block); +static word_t *find_prev_footer(block_t *block); +static block_t *find_prev(block_t *block); + +bool mm_checkheap(int lineno); + +/* + * mm_init: initializes the heap; it is run once when heap_start == NULL. + * prior to any extend_heap operation, this is the heap: + * start start+8 start+16 + * INIT: | PROLOGUE_FOOTER | EPILOGUE_HEADER | + * heap_listp ends up pointing to the epilogue header. + */ +bool mm_init(void) +{ + mem_init(0xffffffff); + + // Create the initial empty heap + word_t *start = (word_t *)(mem_sbrk(2*wsize)); + + if (start == NULL) + { + return false; + } + + start[0] = pack(0, true); // Prologue footer + start[1] = pack(0, true); // Epilogue header + // Heap starts with first block header (epilogue) + heap_listp = (block_t *) &(start[1]); + + // Extend the empty heap with a free block of chunksize bytes + if (extend_heap(chunksize) == NULL) + { + return false; + } + return true; +} + +/* + * malloc: allocates a block with size at least (size + dsize), rounded up to + * the nearest 16 bytes, with a minimum of 2*dsize. Seeks a + * sufficiently-large unallocated block on the heap to be allocated. + * If no such block is found, extends heap by the maximum between + * chunksize and (size + dsize) rounded up to the nearest 16 bytes, + * and then attempts to allocate all, or a part of, that memory. + * Returns NULL on failure, otherwise returns a pointer to such block. + * The allocated block will not be used for further allocations until + * freed. + */ +void *_malloc(size_t size) +{ + dbg_requires(mm_checkheap(__LINE__)); + + size_t asize; // Adjusted block size + size_t extendsize; // Amount to extend heap if no fit is found + block_t *block; + void *bp = NULL; + + if (heap_listp == NULL) // Initialize heap if it isn't initialized + { + mm_init(); + } + + if (size == 0) // Ignore spurious request + { + dbg_ensures(mm_checkheap(__LINE__)); + return bp; + } + + // Adjust block size to include overhead and to meet alignment requirements + asize = round_up(size, dsize) + dsize; + + // Search the free list for a fit + block = find_fit(asize); + + // If no fit is found, request more memory, and then and place the block + if (block == NULL) + { + extendsize = max(asize, chunksize); + block = extend_heap(extendsize); + if (block == NULL) // extend_heap returns an error + { + return bp; + } + + } + + place(block, asize); + bp = header_to_payload(block); + + dbg_ensures(mm_checkheap(__LINE__)); + return bp; +} + +/* + * free: Frees the block such that it is no longer allocated while still + * maintaining its size. Block will be available for use on malloc. + */ +void _free(void *bp) +{ + if (bp == NULL) + { + return; + } + + block_t *block = payload_to_header(bp); + size_t size = get_size(block); + + write_header(block, size, false); + write_footer(block, size, false); + + coalesce(block); + +} + +/* + * realloc: returns a pointer to an allocated region of at least size bytes: + * if ptrv is NULL, then call malloc(size); + * if size == 0, then call free(ptr) and returns NULL; + * else allocates new region of memory, copies old data to new memory, + * and then free old block. Returns old block if realloc fails or + * returns new pointer on success. + */ +void *_realloc(void *ptr, size_t size) +{ + block_t *block = payload_to_header(ptr); + size_t copysize; + void *newptr; + + // If size == 0, then free block and return NULL + if (size == 0) + { + _free(ptr); + return NULL; + } + + // If ptr is NULL, then equivalent to malloc + if (ptr == NULL) + { + return _malloc(size); + } + + // Otherwise, proceed with reallocation + newptr = _malloc(size); + // If malloc fails, the original block is left untouched + if (!newptr) + { + return NULL; + } + + // Copy the old data + copysize = get_payload_size(block); // gets size of old payload + if(size < copysize) + { + copysize = size; + } + memcpy(newptr, ptr, copysize); + + // Free the old block + _free(ptr); + + return newptr; +} + +/* + * calloc: Allocates a block with size at least (elements * size + dsize) + * through malloc, then initializes all bits in allocated memory to 0. + * Returns NULL on failure. + */ +void *_calloc(size_t nmemb, size_t size) +{ + void *bp; + size_t asize = nmemb * size; + + if (asize/nmemb != size) + // Multiplication overflowed + return NULL; + + bp = _malloc(asize); + if (bp == NULL) + { + return NULL; + } + // Initialize all bits to 0 + memset(bp, 0, asize); + + return bp; +} + +/******** The remaining content below are helper and debug routines ********/ + +/* + * extend_heap: Extends the heap with the requested number of bytes, and + * recreates epilogue header. Returns a pointer to the result of + * coalescing the newly-created block with previous free block, if + * applicable, or NULL in failure. + */ +static block_t *extend_heap(size_t size) +{ + void *bp; + + // Allocate an even number of words to maintain alignment + size = round_up(size, dsize); + if ((bp = mem_sbrk(size)) == NULL) + { + return NULL; + } + + // Initialize free block header/footer + block_t *block = payload_to_header(bp); + write_header(block, size, false); + write_footer(block, size, false); + // Create new epilogue header + block_t *block_next = find_next(block); + write_header(block_next, 0, true); + + // Coalesce in case the previous block was free + return coalesce(block); +} + +/* Coalesce: Coalesces current block with previous and next blocks if either + * or both are unallocated; otherwise the block is not modified. + * Returns pointer to the coalesced block. After coalescing, the + * immediate contiguous previous and next blocks must be allocated. + */ +static block_t *coalesce(block_t * block) +{ + block_t *block_next = find_next(block); + block_t *block_prev = find_prev(block); + + bool prev_alloc = extract_alloc(*(find_prev_footer(block))); + bool next_alloc = get_alloc(block_next); + size_t size = get_size(block); + + if (prev_alloc && next_alloc) // Case 1 + { + return block; + } + + else if (prev_alloc && !next_alloc) // Case 2 + { + size += get_size(block_next); + write_header(block, size, false); + write_footer(block, size, false); + } + + else if (!prev_alloc && next_alloc) // Case 3 + { + size += get_size(block_prev); + write_header(block_prev, size, false); + write_footer(block_prev, size, false); + block = block_prev; + } + + else // Case 4 + { + size += get_size(block_next) + get_size(block_prev); + write_header(block_prev, size, false); + write_footer(block_prev, size, false); + + block = block_prev; + } + return block; +} + +/* + * place: Places block with size of asize at the start of bp. If the remaining + * size is at least the minimum block size, then split the block to the + * the allocated block and the remaining block as free, which is then + * inserted into the segregated list. Requires that the block is + * initially unallocated. + */ +static void place(block_t *block, size_t asize) +{ + size_t csize = get_size(block); + + if ((csize - asize) >= min_block_size) + { + block_t *block_next; + write_header(block, asize, true); + write_footer(block, asize, true); + + block_next = find_next(block); + write_header(block_next, csize-asize, false); + write_footer(block_next, csize-asize, false); + } + + else + { + write_header(block, csize, true); + write_footer(block, csize, true); + } +} + +/* + * find_fit: Looks for a free block with at least asize bytes with + * first-fit policy. Returns NULL if none is found. + */ +static block_t *find_fit(size_t asize) +{ + block_t *block; + + for (block = heap_listp; get_size(block) > 0; + block = find_next(block)) + { + + if (!(get_alloc(block)) && (asize <= get_size(block))) + { + return block; + } + } + return NULL; // no fit found +} + +/* + * max: returns x if x > y, and y otherwise. + */ +static size_t max(size_t x, size_t y) +{ + return (x > y) ? x : y; +} + + +/* + * round_up: Rounds size up to next multiple of n + */ +static size_t round_up(size_t size, size_t n) +{ + return (n * ((size + (n-1)) / n)); +} + +/* + * pack: returns a header reflecting a specified size and its alloc status. + * If the block is allocated, the lowest bit is set to 1, and 0 otherwise. + */ +static word_t pack(size_t size, bool alloc) +{ + return alloc ? (size | 1) : size; +} + + +/* + * extract_size: returns the size of a given header value based on the header + * specification above. + */ +static size_t extract_size(word_t word) +{ + return (word & size_mask); +} + +/* + * get_size: returns the size of a given block by clearing the lowest 4 bits + * (as the heap is 16-byte aligned). + */ +static size_t get_size(block_t *block) +{ + return extract_size(block->header); +} + +/* + * get_payload_size: returns the payload size of a given block, equal to + * the entire block size minus the header and footer sizes. + */ +static size_t get_payload_size(block_t *block) +{ + size_t asize = get_size(block); + return asize - dsize; +} + +/* + * extract_alloc: returns the allocation status of a given header value based + * on the header specification above. + */ +static bool extract_alloc(word_t word) +{ + return (bool)(word & alloc_mask); +} + +/* + * get_alloc: returns true when the block is allocated based on the + * block header's lowest bit, and false otherwise. + */ +static bool get_alloc(block_t *block) +{ + return extract_alloc(block->header); +} + +/* + * write_header: given a block and its size and allocation status, + * writes an appropriate value to the block header. + */ +static void write_header(block_t *block, size_t size, bool alloc) +{ + block->header = pack(size, alloc); +} + + +/* + * write_footer: given a block and its size and allocation status, + * writes an appropriate value to the block footer by first + * computing the position of the footer. + */ +static void write_footer(block_t *block, size_t size, bool alloc) +{ + word_t *footerp = (word_t *)((block->payload) + get_size(block) - dsize); + *footerp = pack(size, alloc); +} + + +/* + * find_next: returns the next consecutive block on the heap by adding the + * size of the block. + */ +static block_t *find_next(block_t *block) +{ + dbg_requires(block != NULL); + block_t *block_next = (block_t *)(((char *)block) + get_size(block)); + + dbg_ensures(block_next != NULL); + return block_next; +} + +/* + * find_prev_footer: returns the footer of the previous block. + */ +static word_t *find_prev_footer(block_t *block) +{ + // Compute previous footer position as one word before the header + return (&(block->header)) - 1; +} + +/* + * find_prev: returns the previous block position by checking the previous + * block's footer and calculating the start of the previous block + * based on its size. + */ +static block_t *find_prev(block_t *block) +{ + word_t *footerp = find_prev_footer(block); + size_t size = extract_size(*footerp); + return (block_t *)((char *)block - size); +} + +/* + * payload_to_header: given a payload pointer, returns a pointer to the + * corresponding block. + */ +static block_t *payload_to_header(void *bp) +{ + return (block_t *)(((char *)bp) - offsetof(block_t, payload)); +} + +/* + * header_to_payload: given a block pointer, returns a pointer to the + * corresponding payload. + */ +static void *header_to_payload(block_t *block) +{ + return (void *)(block->payload); +} + +/* mm_checkheap: checks the heap for correctness; returns true if + * the heap is correct, and false otherwise. + * can call this function using mm_checkheap(__LINE__); + * to identify the line number of the call site. + */ +bool mm_checkheap(int lineno) +{ + (void)lineno; + if (heap_listp != NULL) + { + // check prologue footer: size is 0 and prologue is allocated + word_t prologue_footer = *find_prev_footer(heap_listp); + assert(extract_size(prologue_footer) == 0 && extract_alloc(prologue_footer)); + + // check header-footer consistency + block_t *block = heap_listp; + if (get_size(block) != 0) + { + word_t block_header = block->header; + word_t block_footer = *(find_prev_footer(find_next(heap_listp))); + assert(extract_size(block_header) == extract_size(block_footer)); + assert(extract_alloc(block_header) == extract_alloc(block_footer)); + } + } + return true; +} diff --git a/410user/libmalloc/memlib.c b/410user/libmalloc/memlib.c new file mode 100644 index 0000000..8332559 --- /dev/null +++ b/410user/libmalloc/memlib.c @@ -0,0 +1,72 @@ +/* This should look a lot like 15-213 support code. + * Guess what... + */ + +/* memlib.c - functions for modeling the memory system */ +/* $begin memlib */ + +#include +#include +#include + +/* #define PAGE_SIZE 0x00001000 */ +/* #define PAGE_ALIGN_MASK 0xFFFFF000 */ +#define PAGE_ALIGN_MASK ((unsigned int) ~((unsigned int) (PAGE_SIZE-1))) + +#ifndef NULL +#define NULL 0 +#endif + +/* private global variables */ +static char *mem_max_addr; /* max virtual address for the heap */ +static char *mem_brkp; /* Simulated brk pointer */ +static char *mem_alloctop; /* Maximum allocated address */ + +extern void *_end; /* The end of the ELF binary address space */ + +/* + * mem_init - initializes the memory system model + */ +void mem_init(int max_heap_addr) +{ + /* The max address for the heap. */ + mem_max_addr = (char*)max_heap_addr; + mem_brkp = (char*)&_end + PAGE_SIZE; + mem_brkp = (char*)((int)mem_brkp & PAGE_ALIGN_MASK); + while (new_pages(mem_brkp, PAGE_SIZE)) + mem_brkp += PAGE_SIZE; + mem_alloctop = mem_brkp + PAGE_SIZE; +} + +/* + * mem_sbrk - simply uses the the sbrk function. Extends the heap + * by incr bytes and returns the start address of the new area. In + * this model, the heap cannot be shrunk. + */ +void *mem_sbrk(int incr) +{ + char *old_brk = mem_brkp; + + /* Error check the request. */ + if ( (incr < 0) || ((old_brk + incr) > mem_max_addr)) { + return (void *)NULL; + } + + if (old_brk + incr > mem_alloctop) { + int allocincr = old_brk + incr - mem_alloctop; + allocincr += PAGE_SIZE - 1; + allocincr &= PAGE_ALIGN_MASK; + + /* Issue a SBRK for more memory. */ + if (new_pages((void*)mem_alloctop, allocincr)) { + return (void *)NULL; + } + + mem_alloctop += allocincr; + } + + mem_brkp += incr; + + return (void *)old_brk; +} +/* $end memlib */ diff --git a/410user/libmalloc/memlib.h b/410user/libmalloc/memlib.h new file mode 100644 index 0000000..b4b8a62 --- /dev/null +++ b/410user/libmalloc/memlib.h @@ -0,0 +1,13 @@ +/* + * memlib.h + * Modified for use in 15-410 at CMU + * Zachary Anderson(zra) + */ + +#ifndef _MEMLIB_H +#define _MEMLIB_H + +void *mem_init(int size); +void *mem_sbrk(int incr); + +#endif /* _MEMLIB_H */ diff --git a/410user/libmalloc/user.mk b/410user/libmalloc/user.mk new file mode 100644 index 0000000..1e92daa --- /dev/null +++ b/410user/libmalloc/user.mk @@ -0,0 +1,7 @@ +410U_MALLOC_OBJS := malloc.o memlib.o +410U_MALLOC_OBJS := $(410U_MALLOC_OBJS:%=$(410UDIR)/libmalloc/%) + +ALL_410UOBJS += $(410U_MALLOC_OBJS) +410UCLEANS += $(410UDIR)/libmalloc.a + +$(410UDIR)/libmalloc.a: $(410U_MALLOC_OBJS) diff --git a/410user/libsimics/simics.S b/410user/libsimics/simics.S new file mode 100644 index 0000000..28c35dc --- /dev/null +++ b/410user/libsimics/simics.S @@ -0,0 +1,14 @@ +/* simics.S - Simics interface (user side) */ +/* Copyright (c) 2014 Carnegie Mellon University */ + +/* sim_call(ebx, ecx, edx) */ +.global sim_call +sim_call: + push %ebx + mov 0x8(%esp), %ebx + mov 0xC(%esp), %ecx + mov 0x10(%esp), %edx + mov $0, %eax + xchg %ebx, %ebx + pop %ebx + ret diff --git a/410user/libsimics/simics.h b/410user/libsimics/simics.h new file mode 100644 index 0000000..f865d5a --- /dev/null +++ b/410user/libsimics/simics.h @@ -0,0 +1,84 @@ +/** @file lib/simics.h + * @brief Simics interface (kernel side) + * @author matthewj S2008 + */ + +#ifndef LIB_SIMICS_H +#define LIB_SIMICS_H + +#ifdef ASSEMBLER +#define lprintf sim_printf +#endif + +#define SIM_IN_SIMICS 0x04100000 +#define SIM_MEMSIZE 0x04100001 +#define SIM_PUTS 0x04100002 +#define SIM_BREAKPOINT 0x04100003 +#define SIM_HALT 0x04100004 + +#define SIM_CK1 0x04108000 +#define SIM_FR_INKEYS 0x04108004 +#define SIM_FR_PROG 0x04108006 +#define SIM_FR_HERE 0x04108007 + +#define SIM_TEST_REPORT 0x0410800B + +#ifdef ASSEMBLER + +/* Now *this* is a fun macro. It expands into a simics call to 'num' with + * arguments 'arg0' and 'arg1'. For use in assembly functions, to call simics + * without touching the stack. */ + +#define INLINE_SIMCALL(num, arg0, arg1) \ + mov $num, %ebx; \ + mov arg0, %ecx; \ + mov arg1, %edx; \ + xchg %ebx, %ebx; + +#endif + +#ifndef ASSEMBLER + +#include + +/** @brief Calls simics. Arguments are ebx, ecx, edx. */ +extern int sim_call(int ebx, ...); + +/** @brief Returns whether we are in simics */ +extern int sim_in_simics(void); + +/** @brief Returns machine memory size, from simics */ +extern int sim_memsize(void); + +/** @brief Prints a string to the simics console */ +extern void sim_puts(const char *arg); + +/** @brief Breakpoint */ +extern void sim_breakpoint(void); + +/** @brief Halt the simulation */ +extern void sim_halt(void); + +/** @brief Run the checkpoint 1 checker. */ +extern void sim_ck1(void); + +/** @brief Grading harness stuff */ +extern void sim_fr_prog(int a); +extern void sim_fr_here(void); + +/** @brief Convenience wrappers around sim_puts(). */ +extern void sim_vprintf(const char* fmt, va_list ap); +extern void sim_printf(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); + +/** @brief readline(), but wrapped in "magic" */ +int magic_readline(int size, char *buf); + +void sim_update_scoreboard(char *testname, int success); + +/* "Compatibility mode" for old code */ +#define MAGIC_BREAK sim_breakpoint() +#define lprintf(...) sim_printf(__VA_ARGS__) + +#endif /* !ASSEMBLER */ + +#endif /* !LIB_SIMICS_H */ diff --git a/410user/libsimics/simics_c.c b/410user/libsimics/simics_c.c new file mode 100644 index 0000000..c32a298 --- /dev/null +++ b/410user/libsimics/simics_c.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include /* for readline() */ + +int sim_in_simics(void) { + return sim_call(SIM_IN_SIMICS); +} + +int sim_memsize(void) { + return sim_call(SIM_MEMSIZE); +} + +void sim_puts(const char *arg) { + sim_call(SIM_PUTS, arg); +} + +void sim_breakpoint(void) { + sim_call(SIM_BREAKPOINT); +} + +void sim_halt(void) { + sim_call(SIM_HALT); +} + +void sim_ck1(void) { + sim_call(SIM_CK1); +} + +void sim_fr_prog(int a) { + sim_call(SIM_FR_PROG, a); +} + +void sim_fr_here(void) { + sim_call(SIM_FR_HERE); +} + +void sim_vprintf(const char* fmt, va_list ap) +{ + char str[256]; + vsnprintf(str, sizeof(str) - 1, fmt, ap); + sim_puts(str); +} + +void sim_printf(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sim_vprintf(fmt, ap); + va_end(ap); +} + +void sim_update_scoreboard(char *testname, int success) { + sim_call(SIM_TEST_REPORT, testname, success); +} + +int magic_readline(int size, char *buf) { + sim_call(SIM_FR_INKEYS); + return readline(size, buf); +} diff --git a/410user/libsimics/user.mk b/410user/libsimics/user.mk new file mode 100644 index 0000000..a31bbaf --- /dev/null +++ b/410user/libsimics/user.mk @@ -0,0 +1,10 @@ +410U_SIMICS_OBJS := \ + simics.o \ + simics_c.o + +410U_SIMICS_OBJS := $(410U_SIMICS_OBJS:%=$(410UDIR)/libsimics/%) + +ALL_410UOBJS += $(410U_SIMICS_OBJS) +410UCLEANS += $(410UDIR)/libsimics.a + +$(410UDIR)/libsimics.a: $(410U_SIMICS_OBJS) diff --git a/410user/libstdio/doprnt.c b/410user/libstdio/doprnt.c new file mode 100644 index 0000000..548e626 --- /dev/null +++ b/410user/libstdio/doprnt.c @@ -0,0 +1,646 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include +#include +#include "doprnt.h" + +/* + * Common code for printf et al. + * + * The calling routine typically takes a variable number of arguments, + * and passes the address of the first one. This implementation + * assumes a straightforward, stack implementation, aligned to the + * machine's wordsize. Increasing addresses are assumed to point to + * successive arguments (left-to-right), as is the case for a machine + * with a downward-growing stack with arguments pushed right-to-left. + * + * To write, for example, fprintf() using this routine, the code + * + * fprintf(fd, format, args) + * FILE *fd; + * char *format; + * { + * _doprnt(format, &args, fd); + * } + * + * would suffice. (This example does not handle the fprintf's "return + * value" correctly, but who looks at the return value of fprintf + * anyway?) + * + * This version implements the following printf features: + * + * %d decimal conversion + * %u unsigned conversion + * %x hexadecimal conversion + * %X hexadecimal conversion with capital letters + * %o octal conversion + * %c character + * %s string + * %m.n field width, precision + * %-m.n left adjustment + * %0m.n zero-padding + * %*.* width and precision taken from arguments + * + * This version does not implement %f, %e, or %g. It accepts, but + * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not + * work correctly on machines for which sizeof(long) != sizeof(int). + * It does not even parse %D, %O, or %U; you should be using %ld, %o and + * %lu if you mean long conversion. + * + * As mentioned, this version does not return any reasonable value. + * + * Permission is granted to use, modify, or propagate this code as + * long as this notice is incorporated. + * + * Steve Summit 3/25/87 + */ + +/* + * Added formats for decoding device registers: + * + * printf("reg = %b", regval, "*") + * + * where is the output base expressed as a control character: + * i.e. '\10' gives octal, '\20' gives hex. Each is a sequence of + * characters, the first of which gives the bit number to be inspected + * (origin 1), and the rest (up to a control character (<= 32)) give the + * name of the register. Thus + * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE") + * would produce + * reg = 3 + * + * If the second character in is also a control character, it + * indicates the last bit of a bit field. In this case, printf will extract + * bits <1> to <2> and print it. Characters following the second control + * character are printed before the bit field. + * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE") + * would produce + * reg = b + */ +/* + * Added for general use: + * # prefix for alternate format: + * 0x (0X) for hex + * leading 0 for octal + * + print '+' if positive + * blank print ' ' if positive + * + * z signed hexadecimal + * r signed, 'radix' + * n unsigned, 'radix' + * + * D,U,O,Z same as corresponding lower-case versions + * (compatibility) + */ +/* + * Added ANSI %p for pointers. Output looks like 0x%08x. + */ +/* + * + * Added special for L4-use: %t format + * + * prints L4-threadids. standard format is "task.thread". Field-width + * may be specified with width-modifier. Padding begins with threadid, + * up to 2 chars, task-part follows. + * + * modifiers: + * # surrounds output with square brackets [] + * l prints the high and low part of a threadid + * fixed length for the dwords: 8 chars + * 0 as usual, padding after optional '[' + * - as usual + * + * Jork Loeser 9/20/99 + */ + +#define isdigit(d) ((d) >= '0' && (d) <= '9') +#define Ctod(c) ((c) - '0') + +#define MAXBUF (sizeof(long int) * 8) /* enough for binary */ + +static char digs[] = "0123456789abcdef"; + +static void +printnum(u, base, putc, putc_arg) + register unsigned long u; /* number to print */ + register int base; + void (*putc)(); + char *putc_arg; +{ + char buf[MAXBUF]; /* build number here */ + register char * p = &buf[MAXBUF-1]; + + do { + *p-- = digs[u % base]; + u /= base; + } while (u != 0); + + while (++p != &buf[MAXBUF]) + (*putc)(putc_arg, *p); +} + +static void +printnum_16(u, putc, putc_arg) + register unsigned long u; /* number to print */ + void (*putc)(); + char *putc_arg; +{ + char buf[8]; /* build number here */ + register char * p = &buf[7]; + int i; + + for(i=0; i<8;i++){ + *p-- = digs[u & 0x0f]; + u >>= 4; + }; + + for(i=0;i<8;i++){ + (*putc)(putc_arg, buf[i]); + } +} + +boolean_t _doprnt_truncates = FALSE; + +void _doprnt(fmt, args, radix, putc, putc_arg) + register const char *fmt; + va_list args; + int radix; /* default radix - for '%r' */ + void (*putc)(); /* character output */ + char *putc_arg; /* argument for putc */ +{ + int length; + int prec; + boolean_t ladjust; + char padc; + long long n, m; + unsigned long long u; + int plus_sign; + int sign_char; + boolean_t altfmt, truncate, upcase; + int base; + char c; + int longopt; + + while (*fmt != '\0') { + if (*fmt != '%') { + (*putc)(putc_arg, *fmt++); + continue; + } + + fmt++; + + length = 0; + prec = -1; + ladjust = FALSE; + padc = ' '; + plus_sign = 0; + sign_char = 0; + altfmt = FALSE; + longopt = 0; + + while (TRUE) { + if (*fmt == '#') { + altfmt = TRUE; + fmt++; + } + else if (*fmt == '-') { + ladjust = TRUE; + fmt++; + } + else if (*fmt == '+') { + plus_sign = '+'; + fmt++; + } + else if (*fmt == ' ') { + if (plus_sign == 0) + plus_sign = ' '; + fmt++; + } + else + break; + } + + if (*fmt == '0') { + padc = '0'; + fmt++; + } + + if (isdigit(*fmt)) { + while(isdigit(*fmt)) + length = 10 * length + Ctod(*fmt++); + } + else if (*fmt == '*') { + length = va_arg(args, int); + fmt++; + if (length < 0) { + ladjust = !ladjust; + length = -length; + } + } + + if (*fmt == '.') { + fmt++; + if (isdigit(*fmt)) { + prec = 0; + while(isdigit(*fmt)) + prec = 10 * prec + Ctod(*fmt++); + } + else if (*fmt == '*') { + prec = va_arg(args, int); + fmt++; + } + } + + while (*fmt == 'l'){ + longopt++; + fmt++; + } + + truncate = FALSE; + upcase = FALSE; + + switch(*fmt) { + case 'b': + case 'B': + { + register char *p; + boolean_t any; + register int i; + + u = va_arg(args, unsigned long); + p = va_arg(args, char *); + base = *p++; + printnum(u, base, putc, putc_arg); + + if (u == 0) + break; + + any = FALSE; + while ((i = *p++) != 0) { + /* NOTE: The '32' here is because ascii space */ + if (*p <= 32) { + /* + * Bit field + */ + register int j; + if (any) + (*putc)(putc_arg, ','); + else { + (*putc)(putc_arg, '<'); + any = TRUE; + } + j = *p++; + for (; (c = *p) > 32; p++) + (*putc)(putc_arg, c); + printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), + base, putc, putc_arg); + } + else if (u & (1<<(i-1))) { + if (any) + (*putc)(putc_arg, ','); + else { + (*putc)(putc_arg, '<'); + any = TRUE; + } + for (; (c = *p) > 32; p++) + (*putc)(putc_arg, c); + } + else { + for (; *p > 32; p++) + continue; + } + } + if (any) + (*putc)(putc_arg, '>'); + break; + } + + case 'c': + c = va_arg(args, int); + (*putc)(putc_arg, c); + break; + + case 't': + { + typedef struct { + unsigned version_low:10; + unsigned lthread:7; + unsigned task:11; + unsigned version_high:4; + unsigned site:17; + unsigned chief:11; + unsigned nest:4; + } tid_t; + typedef struct { + unsigned high; + unsigned low; + } lh_t; + union tid_t { + tid_t id; + lh_t lh; + } tid; + + tid = va_arg(args, union tid_t); + + if(longopt){ + + if(altfmt){ + n = 19; + } else { + n = 17; + } + + if (length > 0 && !ladjust) { + while(n < length){ + putc(putc_arg, ' '); + n++; + } + } + if(altfmt) putc(putc_arg, '['); + printnum_16( tid.lh.high, putc, putc_arg); + + putc(putc_arg, ':'); + + printnum_16( tid.lh.low, putc, putc_arg); + + if(altfmt) putc(putc_arg, ']'); + + if(length > 0 && ladjust) { + while(n < length){ + putc(putc_arg, ' '); + n++; + } + } + + } else { + + if(altfmt){ + n = 4; + } else { + n = 2; + } + + m = 1; + + m += tid.id.lthread >= 0x10; + n += tid.id.task >= 0x10; + n += tid.id.task >= 0x100; + + if (length > 0 && !ladjust && padc == ' ') { + while (n + 2 < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + if(altfmt) (*putc)(putc_arg, '['); + + if( length > 0 && !ladjust && padc == '0') { + while (n + 2 < length) { + putc(putc_arg, '0'); + n++; + } + } + + printnum(tid.id.task, 16, putc, putc_arg); + putc(putc_arg, '.'); + + if(length > 0 && !ladjust) { + while (n+m < length){ + putc(putc_arg, padc); + n++; + } + } + printnum(tid.id.lthread, 16, putc, putc_arg); + + if(altfmt) putc(putc_arg, ']'); + + if (n + m < length && ladjust) { + while (n + m < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + } + + break; + } + + case 's': + { + register char *p; + register char *p2; + + if (prec == -1) + prec = 0x7fffffff; /* MAXINT */ + + p = va_arg(args, char *); + + if (p == (char *)0) + p = ""; + + if (length > 0 && !ladjust) { + n = 0; + p2 = p; + + for (; *p != '\0' && n < prec; p++) + n++; + + p = p2; + + while (n < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + n = 0; + + while (*p != '\0') { + if (++n > prec) + break; + + (*putc)(putc_arg, *p++); + } + + if (n < length && ladjust) { + while (n < length) { + (*putc)(putc_arg, ' '); + n++; + } + } + + break; + } + + + case 'o': + truncate = _doprnt_truncates; + case 'O': + base = 8; + goto print_unsigned; + + case 'd': + truncate = _doprnt_truncates; + case 'D': + base = 10; + goto print_signed; + + case 'u': + truncate = _doprnt_truncates; + case 'U': + base = 10; + goto print_unsigned; + + case 'p': + padc = '0'; + length = 8; + /* + * We do this instead of just setting altfmt to TRUE + * because we want 0 to have a 0x in front, and we want + * eight digits after the 0x -- not just 6. + */ + (*putc)(putc_arg, '0'); + (*putc)(putc_arg, 'x'); + case 'x': + truncate = _doprnt_truncates; + base = 16; + goto print_unsigned; + case 'X': + base = 16; + upcase = TRUE; + goto print_unsigned; + + case 'z': + truncate = _doprnt_truncates; + base = 16; + goto print_signed; + case 'Z': + base = 16; + upcase = TRUE; + goto print_signed; + + case 'r': + truncate = _doprnt_truncates; + case 'R': + base = radix; + goto print_signed; + + case 'n': + truncate = _doprnt_truncates; + case 'N': + base = radix; + goto print_unsigned; + + print_signed: + if (longopt>1) + n = va_arg(args, long long); + else + n = va_arg(args, long); + if (n >= 0) { + u = n; + sign_char = plus_sign; + } + else { + u = -n; + sign_char = '-'; + } + goto print_num; + + print_unsigned: + if (longopt>1) + u = va_arg(args, unsigned long long); + else + u = va_arg(args, unsigned long); + goto print_num; + + print_num: + { + char buf[MAXBUF]; /* build number here */ + register char * p = &buf[MAXBUF-1]; + static char ldigits[] = "0123456789abcdef"; + static char udigits[] = "0123456789ABCDEF"; + char *digits = ldigits; + char *prefix = 0; + + if (truncate) u = (long)((int)(u)); + if (upcase) digits = udigits; + + if (u != 0 && altfmt) { + if (base == 8) + prefix = "0"; + else if (base == 16) + prefix = "0x"; + } + + do { + *p-- = digits[u % base]; + u /= base; + } while (u != 0); + + length -= (&buf[MAXBUF-1] - p); + if (sign_char) + length--; + if (prefix) + length -= strlen(prefix); + + if (padc == ' ' && !ladjust) { + /* blank padding goes before prefix */ + while (--length >= 0) + (*putc)(putc_arg, ' '); + } + if (sign_char) + (*putc)(putc_arg, sign_char); + if (prefix) + while (*prefix) + (*putc)(putc_arg, *prefix++); + if (padc == '0') { + /* zero padding goes after sign and prefix */ + while (--length >= 0) + (*putc)(putc_arg, '0'); + } + while (++p != &buf[MAXBUF]) + (*putc)(putc_arg, *p); + + if (ladjust) { + while (--length >= 0) + (*putc)(putc_arg, ' '); + } + break; + } + + case '\0': + fmt--; + break; + + default: + (*putc)(putc_arg, *fmt); + } + fmt++; + } +} diff --git a/410user/libstdio/doprnt.h b/410user/libstdio/doprnt.h new file mode 100644 index 0000000..d2bc0f5 --- /dev/null +++ b/410user/libstdio/doprnt.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef __DOPRNT_H_INCLUDED__ +#define __DOPRNT_H_INCLUDED__ + +#include + +void _doprnt( + register const char *fmt, + va_list args, + int radix, /* default radix - for '%r' */ + void (*putc)(), /* character output */ + char *putc_arg); /* argument for putc */ + +#endif /* __DOPRNT_H_INCLUDED__ */ diff --git a/410user/libstdio/doscan.c b/410user/libstdio/doscan.c new file mode 100644 index 0000000..f4c0a30 --- /dev/null +++ b/410user/libstdio/doscan.c @@ -0,0 +1,181 @@ +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: sscanf.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 3/93 + * + * Parse trivially simple strings + */ + +#include +#include +#include +#include +#include "doscan.h" + +/* + * All I need is a miracle ... + * to keep this from growing like all the other sscanf! + */ +int +_doscan(const char *fmt, va_list vp, + int (*getc)(void *getc_arg), + void (*ungetc)(int c, void *getc_arg), + void *getc_arg) +{ + register int c; + boolean_t neg; + boolean_t discard; + boolean_t invalid; + int vals = 0; + + while ((c = *fmt++) != 0) { + + if (c != '%') { + if (isspace(c)) + { + while (isspace(c = getc(getc_arg))); + if (c == 0) break; + ungetc(c, getc_arg); + continue; + } + else if (c == getc(getc_arg)) + continue; + else + break; /* mismatch */ + } + + discard = 0; + invalid = 1; + + more_fmt: + + c = getc(getc_arg); + if (c == 0) + break; /* end of input */ + + switch (*fmt++) { + + case 'd': + { + long n = 0; + + neg = c == '-'; + if (neg) c = getc(getc_arg); + + while (c >= '0' && c <= '9') { + n = n * 10 + (c - '0'); + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); + + if (neg) n = -n; + + /* done, store it away */ + if (!discard) + { + int *p = va_arg(vp, int *); + *p = n; + } + + break; + } + + case 'x': + { + long n = 0; + + neg = c == '-'; + if (neg) c = getc(getc_arg); + + while (1) + { + if ((c >= '0') && (c <= '9')) + n = n * 16 + (c - '0'); + else if ((c >= 'a') && (c <= 'f')) + n = n * 16 + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'F')) + n = n * 16 + (c - 'A' + 10); + else + break; + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); /* retract lookahead */ + + if (neg) n = -n; + + /* done, store it away */ + if (!discard) + { + int *p = va_arg(vp, int *); + *p = n; + } + + break; + } + + case 's': + { + char *buf = NULL; + + if (!discard) + buf = va_arg(vp, char *); + + while (c && !isspace(c)) + { + if (!discard) + *buf++ = c; + c = getc(getc_arg); + invalid = 0; + } + ungetc(c, getc_arg); /* retract lookahead */ + + if (!discard) + *buf = 0; + + break; + } + + case '*': + discard = 1; + goto more_fmt; + + default: + break; + } + + if (invalid) + break; + else if (!discard) + vals++; + } + + return vals; +} + diff --git a/410user/libstdio/doscan.h b/410user/libstdio/doscan.h new file mode 100644 index 0000000..4973186 --- /dev/null +++ b/410user/libstdio/doscan.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#ifndef __DOSCAN_H_INCLUDED__ +#define __DOSCAN_H_INCLUDED__ + +int _doscan(const char *fmt, va_list vp, + int (*getc)(void *getc_arg), + void (*ungetc)(int c, void *getc_arg), + void *getc_arg); + +#endif /* __DOSCAN_H_INCLUDED__ */ diff --git a/410user/libstdio/hexdump.c b/410user/libstdio/hexdump.c new file mode 100644 index 0000000..636f21c --- /dev/null +++ b/410user/libstdio/hexdump.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +/* + * Print a buffer hexdump style. Example: + * + * .---------------------------------------------------------------------------. + * | 00000000 2e2f612e 6f757400 5445524d 3d787465 ./a.out.TERM=xte | + * | 00000010 726d0048 4f4d453d 2f616673 2f63732e rm.HOME=/afs/cs. | + * | 00000020 75746168 2e656475 2f686f6d 652f6c6f utah.edu/home/lo | + * | 00000030 6d657700 5348454c 4c3d2f62 696e2f74 mew.SHELL=/bin/t | + * | 00000040 63736800 4c4f474e 414d453d 6c6f6d65 csh.LOGNAME=lome | + * | 00000050 77005553 45523d6c 6f6d6577 00504154 w.USER=lomew.PAT | + * | 00000060 483d2f61 66732f63 732e7574 61682e65 H=/afs/cs.utah.e | + * | 00000070 64752f68 6f6d652f 6c6f6d65 772f6269 du/home/lomew/bi | + * | 00000080 6e2f4073 79733a2f 6166732f 63732e75 n/@sys:/afs/cs.u | + * | 00000090 7461682e 6564 tah.ed | + * `---------------------------------------------------------------------------' + * + * It might be useful to have an option for printing out little-endianly. + * Adapted from Godmar's hook.c. + */ +void +hexdump(void *buf, int len) +{ + int i, j; + char *b = (char *)buf; + + printf(".---------------------------------------------------------------------------.\n"); + for (i = 0; i < len; i += 16) { + printf("| %08x ", i); + for (j = i; j < i+16; j++) { + if (j % 4 == 0) + printf(" "); + if (j >= len) + printf(" "); + else + printf("%02x", (unsigned char)b[j]); + } + + printf(" "); + for (j = i; j < i+16; j++) + if (j >= len) + printf(" "); + else + printf("%c", isgraph(b[j]) ? b[j] : '.'); + printf(" |\n"); + } + printf("`---------------------------------------------------------------------------'\n"); +} diff --git a/410user/libstdio/printf.c b/410user/libstdio/printf.c new file mode 100644 index 0000000..0a4a4db --- /dev/null +++ b/410user/libstdio/printf.c @@ -0,0 +1,97 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1989 Carnegie Mellon University. + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF + * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY + * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF + * THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include +#include +#include "doprnt.h" + +/* This version of printf is implemented in terms of putchar and puts. */ + +#define PRINTF_BUFMAX 128 + +struct printf_state { + char buf[PRINTF_BUFMAX]; + unsigned int index; +}; + +static void +flush(struct printf_state *state) +{ + print(state->index, state->buf); + state->index = 0; +} + +static void +printf_char(char *arg, int c) +{ + struct printf_state *state = (struct printf_state *) arg; + + if (state->index >= PRINTF_BUFMAX) { + flush(state); + } + + state->buf[state->index] = c; + state->index++; + if (c == '\n') { + flush(state); + } +} + +/* + * Printing (to console) + */ +int vprintf(const char *fmt, va_list args) +{ + struct printf_state state; + + state.index = 0; + _doprnt(fmt, args, 0, (void (*)())printf_char, (char *) &state); + + if (state.index != 0) + flush(&state); + + /* _doprnt currently doesn't pass back error codes, + so just assume nothing bad happened. */ + return 0; +} + +int +printf(const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vprintf(fmt, args); + va_end(args); + + return err; +} + diff --git a/410user/libstdio/putchar.c b/410user/libstdio/putchar.c new file mode 100644 index 0000000..4dd8421 --- /dev/null +++ b/410user/libstdio/putchar.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +/* 15-410 mods by de0u 2008-09-02 ... */ +#include +#include + +int putchar(int c) +{ + print( 1, (char *)&c ); + return c; +} + diff --git a/410user/libstdio/puts.c b/410user/libstdio/puts.c new file mode 100644 index 0000000..d27a070 --- /dev/null +++ b/410user/libstdio/puts.c @@ -0,0 +1,14 @@ +/** @file 410user/libstdio/puts.c + * @author elly1 S2010 + * @brief The puts() libc function + */ + +#include +#include +#include + +int puts(const char *s) { + print(strlen(s), (char *)s); + putchar('\n'); + return 0; +} diff --git a/410user/libstdio/sprintf.c b/410user/libstdio/sprintf.c new file mode 100644 index 0000000..c667837 --- /dev/null +++ b/410user/libstdio/sprintf.c @@ -0,0 +1,104 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include "doprnt.h" + +#define SPRINTF_UNLIMITED -1 +struct sprintf_state { + char *buf; + unsigned int len; + unsigned int max; +}; + +static void +savechar(char *arg, int c) +{ + struct sprintf_state *state = (struct sprintf_state *)arg; + + if (state->max != (unsigned int)SPRINTF_UNLIMITED) + { + if (state->len >= state->max) { + state->len++; + return; + } + } + + state->len++; + *state->buf = c; + state->buf++; +} + +int vsprintf(char *s, const char *fmt, va_list args) +{ + struct sprintf_state state; + state.max = SPRINTF_UNLIMITED; + state.len = 0; + state.buf = s; + + _doprnt(fmt, args, 0, (void (*)()) savechar, (char *) &state); + *(state.buf) = '\0'; + + return state.len; +} + +int vsnprintf(char *s, int size, const char *fmt, va_list args) +{ + struct sprintf_state state; + state.max = size - 1; + state.len = 0; + state.buf = s; + + _doprnt(fmt, args, 0, (void (*)()) savechar, (char *) &state); + *(state.buf) = '\0'; + + return state.len; +} + +int sprintf(char *s, const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vsprintf(s, fmt, args); + va_end(args); + + return err; +} + +int snprintf(char *s, int size, const char *fmt, ...) +{ + va_list args; + int err; + + va_start(args, fmt); + err = vsnprintf(s, size, fmt, args); + va_end(args); + + return err; +} + diff --git a/410user/libstdio/sscanf.c b/410user/libstdio/sscanf.c new file mode 100644 index 0000000..7f48ea9 --- /dev/null +++ b/410user/libstdio/sscanf.c @@ -0,0 +1,65 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include "doscan.h" + +static int +readchar(arg) + void *arg; +{ + return *(*(unsigned char**)arg)++; +} + +static void +unchar(c, arg) + int c; + void *arg; +{ + (void)c; + (*(unsigned char**)arg)--; +} + +int vsscanf(s, fmt, args) + char *s; + char *fmt; + va_list args; +{ + return _doscan(fmt, args, readchar, unchar, &s); +} + +int sscanf(char *s, char *fmt, ...) +{ + va_list args; + int vals; + + va_start(args, fmt); + vals = vsscanf(s, fmt, args); + va_end(args); + + return vals; +} + diff --git a/410user/libstdio/stdio.h b/410user/libstdio/stdio.h new file mode 100644 index 0000000..b25b899 --- /dev/null +++ b/410user/libstdio/stdio.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_STDIO_H +#define _FLUX_MC_STDIO_H + +#ifndef ASSEMBLER +#include /* For size_t, NULL */ +#include +#include + +int putchar(int __c); +int puts(const char *__str); +int printf(const char *__format, ...) + __attribute__((__format__ (__printf__, 1, 2))); +int vprintf(const char *__format, va_list __vl); +int sprintf(char *__dest, const char *__format, ...) + __attribute__((__format__ (__printf__, 2, 3))); +int snprintf(char *__dest, size_t __size, const char *__format, ...) + __attribute__((__format__ (__printf__, 3, 4))); +int vsprintf(char *__dest, const char *__format, va_list __vl); +int vsnprintf(char *__dest, size_t __size, const char *__format, va_list __vl); +int sscanf(const char *__str, const char *__format, ...) + __attribute__((__format__ (__scanf__, 2, 3))); +void hexdump(void *buf, int len); + +#endif /* !ASSEMBLER */ + +#endif /* _FLUX_MC_STDIO_H */ diff --git a/410user/libstdio/user.mk b/410user/libstdio/user.mk new file mode 100644 index 0000000..f9bdcf0 --- /dev/null +++ b/410user/libstdio/user.mk @@ -0,0 +1,16 @@ +410ULIB_STDIO_OBJS := \ + doprnt.o \ + doscan.o \ + hexdump.o \ + printf.o \ + putchar.o \ + puts.o \ + sprintf.o \ + sscanf.o \ + +410ULIB_STDIO_OBJS := $(410ULIB_STDIO_OBJS:%=$(410UDIR)/libstdio/%) + +ALL_410UOBJS += $(410ULIB_STDIO_OBJS) +410UCLEANS += $(410UDIR)/libstdio.a + +$(410UDIR)/libstdio.a: $(410ULIB_STDIO_OBJS) diff --git a/410user/libstdlib/abs.c b/410user/libstdlib/abs.c new file mode 100644 index 0000000..3892eec --- /dev/null +++ b/410user/libstdlib/abs.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +#undef abs + +int abs(int val) +{ + return val >= 0 ? val : -val; +} + diff --git a/410user/libstdlib/atol.c b/410user/libstdlib/atol.c new file mode 100644 index 0000000..30f976d --- /dev/null +++ b/410user/libstdlib/atol.c @@ -0,0 +1,9 @@ +#include +#include + +long +atol(const char *str) +{ + return strtol(str, NULL, 10); +} + diff --git a/410user/libstdlib/ctype.c b/410user/libstdlib/ctype.c new file mode 100644 index 0000000..2159f5a --- /dev/null +++ b/410user/libstdlib/ctype.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +int isascii(int c) +{ + return ((c) >= 0) && ((c) <= 126); +} + +int iscntrl(int c) +{ + return ((c) < ' ') || ((c) > 126); +} + +int isdigit(int c) +{ + return ((c) >= '0') && ((c) <= '9'); +} + +int isgraph(int c) +{ + return ((c) > ' ') && ((c) <= 126); +} + +int islower(int c) +{ + return (c >= 'a') && (c <= 'z'); +} + +int isprint(int c) +{ + return ((c) >= ' ') && ((c) <= 126); +} + +int isspace(int c) +{ + return ((c) == ' ') || ((c) == '\f') + || ((c) == '\n') || ((c) == '\r') + || ((c) == '\t') || ((c) == '\v'); +} + +int isupper(int c) +{ + return (c >= 'A') && (c <= 'Z'); +} + +int isxdigit(int c) +{ + return isdigit(c) || + ((c >= 'A') && (c <= 'F')) || + ((c >= 'a') && (c <= 'f')); +} + +int isalpha(int c) +{ + return islower(c) || isupper(c); +} + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +int ispunct(int c) +{ + return isgraph(c) && !isalnum(c); +} + +int toupper(int c) +{ + return ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 'A') : c; +} + +int tolower(int c) +{ + return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c; +} diff --git a/410user/libstdlib/ctype.h b/410user/libstdlib/ctype.h new file mode 100644 index 0000000..72eaa20 --- /dev/null +++ b/410user/libstdlib/ctype.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1996-1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_CTYPE_H_ +#define _FLUX_MC_CTYPE_H_ + +int isascii(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int isalpha(int c); +int isalnum(int c); +int ispunct(int c); +int toupper(int c); +int tolower(int c); + + +#endif /* _FLUX_MC_CTYPE_H_ */ diff --git a/410user/libstdlib/exit.c b/410user/libstdlib/exit.c new file mode 100644 index 0000000..4fab152 --- /dev/null +++ b/410user/libstdlib/exit.c @@ -0,0 +1,15 @@ +/* + * exit.c + * For new set_status()/vanish() interface, Spring 2007 + * @author Dave Eckhardt (de0u) + */ + +#include + +void set_status(int status); +void vanish(void) NORETURN; + +void exit(int status) +{ + task_vanish(status); +} diff --git a/410user/libstdlib/qsort.c b/410user/libstdlib/qsort.c new file mode 100644 index 0000000..3c00eb6 --- /dev/null +++ b/410user/libstdlib/qsort.c @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +static inline char *med3(char *, char *, char *, int (*)()); +static inline void swapfunc(char *, char *, int, int); + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static inline void +swapfunc(a, b, n, swaptype) + char *a, *b; + int n, swaptype; +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static inline char * +med3(a, b, c, cmp) + char *a, *b, *c; + int (*cmp)(); +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void +qsort(a, n, es, cmp) + void *a; + size_t n, es; + int (*cmp)(); +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = a + es; + + pc = pd = a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/410user/libstdlib/rand.c b/410user/libstdlib/rand.c new file mode 100644 index 0000000..fcff0b5 --- /dev/null +++ b/410user/libstdlib/rand.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +static unsigned seed[2]; + +int +rand(void) +{ + seed[0] += 0xa859c317; + seed[0] += (seed[1] << 13) | (seed[1] >> 19); + seed[1] += seed[0]; + return seed[0] & 0x7FFFFFFF; +} + +void +srand(unsigned new_seed) +{ + seed[0] = seed[1] = new_seed; +} + +#if 0 /* test code */ + +#define CYCLES 100000000 + +void main(int argc, char **argv) +{ + unsigned orig_seed = atol(argv[1]); + int i; + + srand(orig_seed); + for(i = 0; i < CYCLES; i++) + { + int r = rand(); + /*printf("%08x\n", r);*/ + if ((seed[0] == orig_seed) && (seed[1] == orig_seed)) + { + printf("repeates after %d cycles\n", i); + exit(0); + } + } + printf("still not repeating after %d cycles\n", CYCLES); +} + +#endif + diff --git a/410user/libstdlib/stdlib.h b/410user/libstdlib/stdlib.h new file mode 100644 index 0000000..a30aa65 --- /dev/null +++ b/410user/libstdlib/stdlib.h @@ -0,0 +1,30 @@ +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include /* For size_t, NULL */ +#include /* "Listen to what the man says" */ + +/* start user-land only */ + +/* Apologies for the gcc-ism, but gcc gets angry w/o it */ +void exit(int status) __attribute__((__noreturn__)); + +/* end user-land only */ + +long atol(const char *__str); +#define atoi(str) ((int)atol(str)) + +long strtol(const char *__p, char **__out_p, int __base); +unsigned long strtoul(const char *__p, char **__out_p, int __base); + +#define RAND_MAX ((signed int)0x7fffffff) +int rand(void); +void srand(unsigned new_seed); + +int abs(int val); + +void qsort(void *a, size_t n, size_t es, int (*cmp)(char*, char*)); + +void panic(const char *, ...); + +#endif diff --git a/410user/libstdlib/strtol.c b/410user/libstdlib/strtol.c new file mode 100644 index 0000000..90c4ef4 --- /dev/null +++ b/410user/libstdlib/strtol.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +long strtol(const char *p, char **out_p, int base) +{ + long v = 0; + int is_neg = 0; + + while (isspace(*p)) + p++; + if (*p == '-') + is_neg = 1, p++; + else if (*p == '+') + is_neg = 0; + if (((base == 16) || (base == 0)) && + ((*p == '0') && ((p[1] == 'x') || (p[1] == 'X')))) + { + p += 2; + base = 16; + } + if (base == 0) + { + if (*p == '0') + base = 8; + else + base = 10; + } + while (1) + { + char c = *p; + if ((c >= '0') && (c <= '9') && (c - '0' < base)) + v = (v * base) + (c - '0'); + else if ((c >= 'a') && (c <= 'z') && (c - 'a' + 10 < base)) + v = (v * base) + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'Z') && (c - 'A' + 10 < base)) + v = (v * base) + (c - 'A' + 10); + else + break; + p++; + } + if (is_neg) + v = -v; + if (out_p) *out_p = (char*)p; + return v; +} + diff --git a/410user/libstdlib/strtoul.c b/410user/libstdlib/strtoul.c new file mode 100644 index 0000000..59d8f2a --- /dev/null +++ b/410user/libstdlib/strtoul.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995-1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include +#include + +unsigned long strtoul(const char *p, char **out_p, int base) +{ + unsigned long v = 0; + + while (isspace(*p)) + p++; + if (((base == 16) || (base == 0)) && + ((*p == '0') && ((p[1] == 'x') || (p[1] == 'X')))) + { + p += 2; + base = 16; + } + if (base == 0) + { + if (*p == '0') + base = 8; + else + base = 10; + } + while (1) + { + char c = *p; + if ((c >= '0') && (c <= '9') && (c - '0' < base)) + v = (v * base) + (c - '0'); + else if ((c >= 'a') && (c <= 'z') && (c - 'a' + 10 < base)) + v = (v * base) + (c - 'a' + 10); + else if ((c >= 'A') && (c <= 'Z') && (c - 'A' + 10 < base)) + v = (v * base) + (c - 'A' + 10); + else + break; + p++; + } + + if (out_p) *out_p = (char*)p; + return v; +} + diff --git a/410user/libstdlib/user.mk b/410user/libstdlib/user.mk new file mode 100644 index 0000000..e1ed87f --- /dev/null +++ b/410user/libstdlib/user.mk @@ -0,0 +1,17 @@ +410ULIB_STDLIB_OBJS := \ + abs.o \ + atol.o \ + ctype.o \ + exit.o \ + qsort.o \ + rand.o \ + strtol.o \ + strtoul.o \ + + +410ULIB_STDLIB_OBJS := $(410ULIB_STDLIB_OBJS:%=$(410UDIR)/libstdlib/%) + +ALL_410UOBJS += $(410ULIB_STDLIB_OBJS) +410UCLEANS += $(410UDIR)/libstdlib.a + +$(410UDIR)/libstdlib.a: $(410ULIB_STDLIB_OBJS) diff --git a/410user/libstring/memcmp.c b/410user/libstring/memcmp.c new file mode 100644 index 0000000..204fd4b --- /dev/null +++ b/410user/libstring/memcmp.c @@ -0,0 +1,53 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/memcmp.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcmp (s1, s2) compares the strings "s1" and "s2". + * It returns 0 if the strings are identical. It returns + * > 0 if the first character that differs into two strings + * is larger in s1 than in s2 or if s1 is longer than s2 and + * the contents are identical up to the length of s2. + * It returns < 0 if the first differing character is smaller + * in s1 than in s2 or if s1 is shorter than s2 and the + * contents are identical upto the length of s1. + */ + +int +memcmp(const void *s1v, const void *s2v, int size) +{ + register const char *s1 = s1v, *s2 = s2v; + register unsigned int a, b; + + while (size-- > 0) { + if ((a = *s1++) != (b = *s2++)) + return (a-b); + } + + return 0; +} diff --git a/410user/libstring/memset.c b/410user/libstring/memset.c new file mode 100644 index 0000000..6a40159 --- /dev/null +++ b/410user/libstring/memset.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +void * +memset(void *tov, int c, size_t len) +{ + register char *to = tov; + + while (len-- > 0) + *to++ = c; + + return tov; +} + diff --git a/410user/libstring/rindex.c b/410user/libstring/rindex.c new file mode 100644 index 0000000..847b3dc --- /dev/null +++ b/410user/libstring/rindex.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +char *rindex(const char *s, int c) +{ + char *it = 0; + + while (1) + { + if (*s == c) + it = (char *)s; + if (*s == 0) + return it; + s++; + } +} + diff --git a/410user/libstring/strcat.c b/410user/libstring/strcat.c new file mode 100644 index 0000000..b0906a0 --- /dev/null +++ b/410user/libstring/strcat.c @@ -0,0 +1,38 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +char * +strcat(s, add) +register char *s, *add; +{ +register char *ret = s; + + while (*s) s++; + + while ((*s++ = *add++) != 0); + + return ret; +} diff --git a/410user/libstring/strchr.c b/410user/libstring/strchr.c new file mode 100644 index 0000000..5eff9e5 --- /dev/null +++ b/410user/libstring/strchr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1995 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +char *strchr(const char *s, int c) +{ + while (1) + { + if (*s == c) + return (char*)s; + if (*s == 0) + return 0; + s++; + } +} + diff --git a/410user/libstring/strcmp.c b/410user/libstring/strcmp.c new file mode 100644 index 0000000..77cd82d --- /dev/null +++ b/410user/libstring/strcmp.c @@ -0,0 +1,55 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/strcmp.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcmp (s1, s2) compares the strings "s1" and "s2". + * It returns 0 if the strings are identical. It returns + * > 0 if the first character that differs into two strings + * is larger in s1 than in s2 or if s1 is longer than s2 and + * the contents are identical up to the length of s2. + * It returns < 0 if the first differing character is smaller + * in s1 than in s2 or if s1 is shorter than s2 and the + * contents are identical upto the length of s1. + */ + +int +strcmp(s1,s2) +register unsigned char *s1, *s2; +{ +register unsigned int a, b; + + + + while ( (a = *s1++), (b = *s2++), a && b) { + if (a != b) + return (a-b); + } + + return a-b; +} diff --git a/410user/libstring/strcpy.c b/410user/libstring/strcpy.c new file mode 100644 index 0000000..66df3b9 --- /dev/null +++ b/410user/libstring/strcpy.c @@ -0,0 +1,45 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: libmach_sa/strcpy.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strcpy copies the contents of the string "from" including + * the null terminator to the string "to". A pointer to "to" + * is returned. + */ + +char * +strcpy(to,from) +register char *to, *from; +{ +register char *ret = to; + + while ((*to++ = *from++) != 0); + + return ret; +} diff --git a/410user/libstring/strcspn.c b/410user/libstring/strcspn.c new file mode 100644 index 0000000..97b2c91 --- /dev/null +++ b/410user/libstring/strcspn.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Span the complement of string s2. + */ +size_t +strcspn(s1, s2) + const char *s1; + register const char *s2; +{ + register const char *p, *spanp; + register char c, sc; + + /* + * Stop as soon as we find any character from s2. Note that there + * must be a NUL in s2; it suffices to stop when we find that, too. + */ + for (p = s1;;) { + c = *p++; + spanp = s2; + do { + if ((sc = *spanp++) == c) + return (p - 1 - s1); + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/410user/libstring/strdup.c b/410user/libstring/strdup.c new file mode 100644 index 0000000..7275355 --- /dev/null +++ b/410user/libstring/strdup.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + + + +char *strdup(const char *src) +{ + char *buf = malloc(strlen(src)+1); + if (buf) + strcpy(buf, src); + return buf; +} + diff --git a/410user/libstring/string.h b/410user/libstring/string.h new file mode 100644 index 0000000..e47934a --- /dev/null +++ b/410user/libstring/string.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ +#ifndef _FLUX_MC_STRING_H_ +#define _FLUX_MC_STRING_H_ + +#include + +size_t strlen(const char *__s); +char *strcpy(char *__dest, const char *__src); +char *strncpy(char *__dest, const char *__src, size_t __n); +char *strdup(const char *__s); +char *strcat(char *__dest, const char *__src); +char *strncat(char *__dest, const char *__src, size_t __n); +int strcmp(const char *__a, const char *__b); +int strncmp(const char *__a, const char *__b, size_t __n); +char *strchr(const char *__s, int __c); +char *strrchr(const char *__s, int __c); +char *strstr(const char *__haystack, const char *__needle); +char *strtok(char *__s, const char *__delim); +char *strpbrk(const char *__s1, const char *__s2); +size_t strspn(const char *__s1, const char *__s2); +size_t strcspn(const char *__s1, const char *__s2); + +void *memset(void *__to, int __ch, unsigned int __n); +int memcmp(const void *s1v, const void *s2v, int size); + +/* FIXME These are defined here only by tradition... we should move them. */ +void *memcpy(void *__to, const void *__from, unsigned int __n); +void *memmove(void *__to, const void *__from, unsigned int __n); + +/*** BSD compatibility functions; do not use in new code ***/ + +char *index(const char *__s, int __c); +char *rindex(const char *__s, int __c); + +void bcopy(const void *__from, void *__to, unsigned int __n); +void bzero(void *__to, unsigned int __n); + +#endif /* _FLUX_MC_STRING_H_ */ diff --git a/410user/libstring/strlen.c b/410user/libstring/strlen.c new file mode 100644 index 0000000..089b028 --- /dev/null +++ b/410user/libstring/strlen.c @@ -0,0 +1,45 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: limach/strlen.c + * Author: Robert V. Baron at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strlen returns the number of characters in "string" preceeding + * the terminating null character. + */ + +int +strlen(string) + register char *string; +{ +register char *ret = string; + + while (*string++); + + return string - 1 - ret; + +} diff --git a/410user/libstring/strncat.c b/410user/libstring/strncat.c new file mode 100644 index 0000000..480b3b5 --- /dev/null +++ b/410user/libstring/strncat.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes + * are written at dst (at most n+1 bytes being appended). Return dst. + */ +char * +strncat(dst, src, n) + char *dst; + const char *src; + register size_t n; +{ + if (n != 0) { + register char *d = dst; + register const char *s = src; + + while (*d != 0) + d++; + do { + if ((*d = *s++) == 0) + break; + d++; + } while (--n != 0); + *d = 0; + } + return (dst); +} diff --git a/410user/libstring/strncmp.c b/410user/libstring/strncmp.c new file mode 100644 index 0000000..6ce3f30 --- /dev/null +++ b/410user/libstring/strncmp.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + while (1) + { + if (n <= 0) + return 0; + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + + s1++; + s2++; + n--; + } +} + diff --git a/410user/libstring/strncpy.c b/410user/libstring/strncpy.c new file mode 100644 index 0000000..19cf89a --- /dev/null +++ b/410user/libstring/strncpy.c @@ -0,0 +1,51 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: libmach_sa/strncpy.c + * Author: Mary R. Thompson at Carnegie Mellon + * Date: Oct 13, 1992 + * Abstract: + * strncpy copies "count" characters from the "from" string to + * the "to" string. If "from" contains less than "count" characters + * "to" will be padded with null characters until exactly "count" + * characters have been written. The return value is a pointer + * to the "to" string. + */ + +char * +strncpy(to, from, count) + register char *to, *from; + register int count; +{ + register char *ret = to; + + while (count-- > 0 && (*to++ = *from++)); + + while (count-- > 0) + *to++ = '\0'; + + return ret; +} diff --git a/410user/libstring/strpbrk.c b/410user/libstring/strpbrk.c new file mode 100644 index 0000000..12ddef9 --- /dev/null +++ b/410user/libstring/strpbrk.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(s1, s2) + register const char *s1, *s2; +{ + register const char *scanp; + register int c, sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != 0;) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} diff --git a/410user/libstring/strrchr.c b/410user/libstring/strrchr.c new file mode 100644 index 0000000..e7b5792 --- /dev/null +++ b/410user/libstring/strrchr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1996 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +char * +strrchr(const char *s, int c) +{ + char *save; + + for (save = NULL; *s != '\0'; s++) + if (*s == c) + save = (char *)s; + + return save; +} diff --git a/410user/libstring/strspn.c b/410user/libstring/strspn.c new file mode 100644 index 0000000..a493f8f --- /dev/null +++ b/410user/libstring/strspn.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Span the string s2 (skip characters that are in s2). + */ +size_t +strspn(s1, s2) + const char *s1; + register const char *s2; +{ + register const char *p = s1, *spanp; + register char c, sc; + + /* + * Skip any characters in s2, excluding the terminating \0. + */ +cont: + c = *p++; + for (spanp = s2; (sc = *spanp++) != 0;) + if (sc == c) + goto cont; + return (p - 1 - s1); +} diff --git a/410user/libstring/strstr.c b/410user/libstring/strstr.c new file mode 100644 index 0000000..7c2fb55 --- /dev/null +++ b/410user/libstring/strstr.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory (CSL). All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + */ + +#include +#include + +char *strstr(const char *haystack, const char *needle) +{ + int hlen = strlen(haystack); + int nlen = strlen(needle); + + while (hlen >= nlen) + { + if (!memcmp(haystack, needle, nlen)) + return (void*)haystack; + + haystack++; + hlen--; + } + return 0; +} + diff --git a/410user/libstring/strtok.c b/410user/libstring/strtok.c new file mode 100644 index 0000000..ba4f85d --- /dev/null +++ b/410user/libstring/strtok.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +char * +strtok(s, delim) + register char *s; + register const char *delim; +{ + register char *spanp; + register int c, sc; + char *tok; + static char *last; + + + if (s == NULL && (s = last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/410user/libstring/user.mk b/410user/libstring/user.mk new file mode 100644 index 0000000..60f0a39 --- /dev/null +++ b/410user/libstring/user.mk @@ -0,0 +1,27 @@ +410ULIB_STRING_OBJS:= \ + memcmp.o \ + memset.o \ + rindex.o \ + strcat.o \ + strchr.o \ + strcmp.o \ + strcpy.o \ + strcspn.o \ + strdup.o \ + strlen.o \ + strncat.o \ + strncmp.o \ + strncpy.o \ + strpbrk.o \ + strrchr.o \ + strspn.o \ + strstr.o \ + strtok.o \ + + +410ULIB_STRING_OBJS:= $(410ULIB_STRING_OBJS:%=$(410UDIR)/libstring/%) + +ALL_410UOBJS += $(410ULIB_STRING_OBJS) +410UCLEANS += $(410UDIR)/libstring.a + +$(410UDIR)/libstring.a: $(410ULIB_STRING_OBJS) diff --git a/410user/libtest/report.c b/410user/libtest/report.c new file mode 100644 index 0000000..96d29a3 --- /dev/null +++ b/410user/libtest/report.c @@ -0,0 +1,98 @@ +/** @file 410user/libtest/report.c + * @brief Test reporting implementation + * @author elly1 U2009 + */ + +#include /* snprintf */ +#include /* exit */ +#include + +#include "410_tests.h" /* TEST_START_*, TEST_END_*, TEST_PFX */ + +/* This is a GNUism used for the sake of maintainability. This way nothing + * horrible will happen if someone reorders the START_* constants in the header + * file. */ +const char *start_msgs[] = { + [START_CMPLT] = TEST_START_CMPLT, + [START_ABORT] = TEST_START_ABORT, + [START_4EVER] = TEST_START_4EVER, +}; + +const char *end_msgs[] = { + [END_SUCCESS] = TEST_END_SUCCESS, + [END_FAIL] = TEST_END_FAIL, +}; + +void format_start(char *buf, int len, int type) { + snprintf(buf, len, "%s%s%s", TEST_PFX, test_name, start_msgs[type]); +} + +void format_end(char *buf, int len, int type) { + snprintf(buf, len, "%s%s%s", TEST_PFX, test_name, end_msgs[type]); +} + +void format_misc(char *buf, int len, const char *msg) { + snprintf(buf, len, "%s%s%s", TEST_PFX, test_name, msg); +} + +void format_err(char *buf, int len, const char *msg, int code) { + snprintf(buf, len, "%s%s%s%d", TEST_PFX, test_name, msg, code); +} + +void report_start(int type) { + char buf[256]; + format_start(buf, sizeof(buf), type); + sim_puts(buf); +} + +void report_end(int type) { + char buf[256]; + format_end(buf, sizeof(buf), type); + sim_puts(buf); + + int success = (type == END_SUCCESS) ? 1 : 0; + sim_update_scoreboard((char *)test_name, success); +} + +void report_misc(const char *msg) { + char buf[256]; + format_misc(buf, sizeof(buf), msg); + sim_puts(buf); +} + +void report_fmt(const char *fmt, ...) { + va_list ap; + char b[256]; + char buf[256]; + va_start(ap, fmt); + vsnprintf(b, sizeof(b), fmt, ap); + va_end(ap); + snprintf(buf, sizeof(buf), "%s%s%s", TEST_PFX, test_name, b); + sim_puts(buf); +} + +void report_err(const char *msg, int code) { + char buf[256]; + format_err(buf, sizeof(buf), msg, code); + sim_puts(buf); +} + +void report_fatal(const char *msg, int code) { + report_err(msg, code); + report_end(END_FAIL); +} + +void report_on_err(const char *exp, int line, int v) { + char buf[256]; + if (v >= 0) { return; } + snprintf(buf, sizeof(buf), "%s%sErr %d on line %d: `%s'", + TEST_PFX, test_name, v, line, exp); + sim_puts(buf); +} + +void fatal_on_err(const char *exp, int line, int v) { + report_on_err(exp, line, v); + if (v >= 0) { return; } + report_end(END_FAIL); + exit(v); +} diff --git a/410user/libtest/report.h b/410user/libtest/report.h new file mode 100644 index 0000000..496754b --- /dev/null +++ b/410user/libtest/report.h @@ -0,0 +1,109 @@ +/** @file 410user/libtest/report.h + * @brief Test reporting interface + * @author elly1 U2009 + */ + +#ifndef LIBTEST_REPORT_H +#define LIBTEST_REPORT_H + +extern const char* test_name; /* Defined by the test in question with + * DEF_TEST_NAME() */ + +enum { + START_CMPLT = 0, + START_ABORT = 1, + START_4EVER = 2, +}; + +/** @brief Formats a test start message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param type Type of test start. + * @return Void. + */ +extern void format_start(char *buf, int len, int type); + +/** @brief Reports the start of a test. + * @param type Type of test start. + */ +extern void report_start(int type); + +enum { + END_SUCCESS = 0, + END_FAIL = 1, +}; + +/** @brief Formats a test end message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param type Type of test ending. + * @return Void. + */ +extern void format_end(char *buf, int len, int type); + +/** @brief Reports the end of a test. + * @param type Type of test end. + */ +extern void report_end(int type); + +/** @brief Formats a miscellaneous message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param msg Message to format. + * @return Void. + */ +extern void format_misc(char *buf, int len, const char *msg); + +/** @brief Report a miscellaneous happenstance. + * @param msg Happenstance. + * @return Void. + */ +extern void report_misc(const char *msg); + +/** @brief Report an arbitrary formatted message. + * @param fmt Format. + * @param ... Varargs. + * @return Void. + */ +extern void report_fmt(const char *fmt, ...); + +/** @brief Formats an error message into a buffer. + * @param buf Buffer to format into. + * @param len Length of the buffer. + * @param msg Message to format. + * @param code Error code. + * @return Void. + */ +extern void format_err(char *buf, int len, const char *msg, int code); + +/** @brief Report an error. + * @param msg Error message. + * @param code Error code. + * @return Void. + */ +extern void report_err(const char *msg, int code); + +/** @brief Report an error, and fail out. + * @param msg Error message. + * @param code Error code. + * @return Void. + */ +extern void report_fatal(const char *msg, int code); + +/** @brief Require that an expression succeed. + * @param exp Expression, as a string. + * @param line Line number of the expression. + * @param v Expression value. + * @return Void. + */ +extern void report_on_err(const char *exp, int line, int v); + +/** @brief Fail the test if an expression fails. + * @param exp Expression, as a string. + * @param line Line number of the expression. + * @param v Expression value. + * @return Void. + */ +extern void fatal_on_err(const char *exp, int line, int v); + +#endif /* !LIBTEST_REPORT_H */ diff --git a/410user/libtest/test.c b/410user/libtest/test.c new file mode 100644 index 0000000..e69de29 diff --git a/410user/libtest/test.h b/410user/libtest/test.h new file mode 100644 index 0000000..e47bfb5 --- /dev/null +++ b/410user/libtest/test.h @@ -0,0 +1,52 @@ +/** @file 410user/libtest/test.h + * @brief Test library. + * @author elly1 U2009 + */ + +#ifndef LIBTEST_TEST_H +#define LIBTEST_TEST_H + +/** @brief Jump to 'func' with the system under low-memory conditions. + * The reason why this takes a function pointer may not be immediately clear. + * Once exhaustion() returns to C, the compiler is immediately free to save off + * all the registers and generally touch the stack; this could cause a failed + * stack page allocation and lead to the thread being killed, which would fail + * the test. As such, exhaustion guarantees that once you are out of memory, it + * will not touch the stack on your behalf. + * + * @param func Function to jump to. + * @param arg Argument passed to func in %ebx. + * @return Does not return. + */ +extern void exhaustion(void (*func)(void *), void *arg) __attribute__((noreturn)); + +/** @brief Fork, and exit immediately, printing success regardless of what + * happened. Does not touch the stack at all. + * @param arg Argument passed in *in %ebx*. + * @return Does not return. + * + * NOTE: + * Do not call this function directly. It is designed to be passed into + * exhaustion(). + */ +extern void fork_and_exit(void *arg) __attribute__((noreturn)); + +/** @brief Exit immediately, with a success message. + * @param arg Argument passed in *in %ebx*. + * @return Does not return. + * + * See the note attached to fork_and_exit(). + */ +extern void exit_success(void *arg) __attribute__((noreturn)); + +/** @brief Execute an illegal instruction. + * @return Void. + */ +extern void illegal(void); + +/** @brief Assuredly invoke the misbehave() system call + * @return Void ("you are not expected to understand this") + */ +extern void assuredly_misbehave(int mode); + +#endif /* !LIBTEST_TEST_H */ diff --git a/410user/libtest/testasm.S b/410user/libtest/testasm.S new file mode 100644 index 0000000..d0179ab --- /dev/null +++ b/410user/libtest/testasm.S @@ -0,0 +1,82 @@ +/** @file 410user/libtest/testasm.S + * @brief Test library. + * @author elly1 U2009 + */ + +#include +#include + +.global exhaustion + +#define EX_BASE 0x20000000 +#define EX_SIZE 1024 * 1024 * 1024 + +/* %edi - continuation + * %esi - syscall arg frame + * %ebx - argument + */ +exhaustion: + mov 4(%esp), %edi + mov 8(%esp), %ebx + lea -8(%esp), %esi /* argument frame space */ + mov $EX_BASE, %ecx + mov $EX_SIZE, %edx + mov $4, %esp /* don't tempt the user to think that their stack is + * still live */ +loop: + cmp $4096, %edx + jb 1f + mov %ecx, (%esi) + mov %edx, 4(%esi) + int $NEW_PAGES_INT + test %eax, %eax + jnz smaller + add %edx, %ecx + jmp loop +smaller: + shr $1, %edx + jmp loop +1: + jmp *%edi + +.global fork_and_exit + +fork_and_exit: + mov %ebx, %ecx + int $FORK_INT + test %eax, %eax + jz 1f + INLINE_SIMCALL(SIM_PUTS, %ecx, $0) +1: + mov $0, %esi + int $SET_STATUS_INT + int $VANISH_INT + +.global exit_success + +exit_success: + mov %ebx, %ecx + INLINE_SIMCALL(SIM_PUTS, %ecx, $0) + INLINE_SIMCALL(SIM_TEST_REPORT, %ecx, $1) + mov $0, %esi + int $SET_STATUS_INT + int $VANISH_INT + +.global illegal + +illegal: + xor %eax, %eax + mov %eax, %cr0 + ret + +/* Don't code like this: "authorized personnel only". */ +.global assuredly_misbehave +assuredly_misbehave: + pushl %ebp + movl %esp, %ebp + pusha + movl 8(%ebp), %esi + int $MISBEHAVE_INT + popa + leave + ret diff --git a/410user/libtest/user.mk b/410user/libtest/user.mk new file mode 100644 index 0000000..a302d02 --- /dev/null +++ b/410user/libtest/user.mk @@ -0,0 +1,6 @@ +410U_TEST_OBJS := test.o testasm.o report.o +410U_TEST_OBJS := $(410U_TEST_OBJS:%=$(410UDIR)/libtest/%) +ALL_410UOBJS += $(410U_TEST_OBJS) +410UCLEANS += $(410UDIR)/libtest.a + +$(410UDIR)/libtest.a: $(410U_TEST_OBJS) diff --git a/410user/libthrgrp/thrgrp.c b/410user/libthrgrp/thrgrp.c new file mode 100644 index 0000000..ecd124a --- /dev/null +++ b/410user/libthrgrp/thrgrp.c @@ -0,0 +1,201 @@ +/* @file thrgrp.c + * @brief This file contains the implementation of the wrapper for the + * thread library. This wrapper allows explicit control over what threads + * get joined on by what other threads. + * + * @author Matthew Brewer (mbrewer) + * + * The user allocates groups, and then initializes them. + * They can then spawn threads into these groups with thrgrp_create() + * When the threads exit (via returning.. NOT thr_exit()), they can be + * joined on using thrgrp_join(). A call to thrgrp_join() with group tg + * will reap any one thread to exit from that group, and then return. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Initializes a thread group + * + * This function basically just initializes mutexes etc. + * + * @param eg An unitialized, but allocated, thread group to be initialized + * @return 0 on success, nonzero otherwise + * + * @pre thr_init should have been called + * @post eg is initialized + */ +int thrgrp_init_group(thrgrp_group_t *eg) { + int ret; + + eg->zombie_in = NULL; + eg->zombie_out = NULL; + if ((ret = mutex_init(&(eg->lock)))) + return ret; + if ((ret = cond_init(&(eg->cv)))) { + mutex_destroy(&(eg->lock)); + return ret; + } + return 0; +} + +/** + * @brief Destroys an initialized thrgroup + * + * Destroys the mutexes and other related stuff + * + * @param eg An initialized thread group to be destroyed + * @return 0 on success, nonzero otherwise + * + * @pre thrgrp_init_group(eg) has been called + * @post eg is uninitialized (but still allocated) + */ +int thrgrp_destroy_group(thrgrp_group_t *eg) { + int ret = 0; + + mutex_lock(&(eg->lock)); + + /* make sure that the queues are empty */ + if (eg->zombie_in || eg->zombie_out) + ret = 1; + + mutex_unlock(&(eg->lock)); + + if (ret == 0) { + mutex_destroy(&(eg->lock)); + cond_destroy(&(eg->cv)); + } + return ret; +} + +/** + * @brief Function to sit on the bottom of the thread stack + * + * @param in_data is a thrgrp_data_t, with tmp loaded with the function + * the user wants to run, the argument to call the function on, and + * the thread group this new thread is to be spawned in + * @return doesn't + */ +static void *thrgrp_bottom(void *in_data) { + thrgrp_data_t *data = (thrgrp_data_t *)in_data; + void *(*func)(void *) = data->tmp.func; + void *arg = data->tmp.arg; + thrgrp_group_t *tg = data->tmp.tg; + void *ret; + + /* now that we have all of the data out of data, + we'll use it as our queueing element */ + data->qel.next = NULL; + data->qel.tid = thr_getid(); + + /* run the code we were asked to run */ + ret = func(arg); + + /* insert ourselves into the zombie queue */ + mutex_lock(&(tg->lock)); + if (tg->zombie_in) + tg->zombie_in->next = &(data->qel); + tg->zombie_in = &(data->qel); + if (tg->zombie_out == NULL) + tg->zombie_out = &(data->qel); + + /* signal a waiter to come clean up our zombie */ + cond_signal(&(tg->cv)); + mutex_unlock(&(tg->lock)); + + /* if we return with ret, should exit with ret */ + return ret; +} + +/** @brief spawns a new thread in the thread group + * + * @param tg, an initialized thread group to spawn the new thread in + * @param func, function to run in the new thread + * @param arg, argument to pass the function to func + * @return 0 on success, nonzero otherwise + */ +int thrgrp_create(thrgrp_group_t *tg, void *(*func)(void *), void *arg) { + int tid; + thrgrp_data_t *data; + + /* setup a hunk of data + this is used both to get the arguments into the other thread, + and then as the memory to go on the zombie queue, this way we + malloc only once */ + data = malloc(sizeof(thrgrp_data_t)); + if (data == NULL) + return -1; + data->tmp.func = func; + data->tmp.arg = arg; + data->tmp.tg = tg; + + /* spawn the thread */ + tid = thr_create(thrgrp_bottom, data); + + /* tid < 0 indicates error */ + if (tid < 0) { + free(data); + return tid; + } + + /* we don't return the tid, because you're not supposed to join on it + must be joined with thrgrp_join(), not thr_join() */ + return 0; +} + +/** @brief joins on any thread in the group which exits + * + * like thr_join(), but will join on any exited thread which was spawned into + * this thread group via thrgrp_create() + * + * throughout this function thrgrp_queue_el_t is a LIE! in reality this is + * thrgrp_data_t, a union including thrgrp_queue_el_t as a subtype. this is + * only important because one should realize "free" is freeing thrgrp_data_t + * of memory, not thrgrp_queue_el_t of memory + * + * @param eg, an initialized thread group to join on threads in + * @param depared, a pointer to some memory, the TID of the exited + * thread will be placed here before thrgrp_join returns + * @param status, a pointer to a void *, where the return status of + * the thread we join on (i.e., what's returned from that thread's first function + * @return returns the result of thr_join + */ +int thrgrp_join(thrgrp_group_t *eg, void **status) { + thrgrp_queue_el_t *thr_data; + int tid; + + mutex_lock(&(eg->lock)); + /* check to see if there's someone to join on */ + while (eg->zombie_out == NULL) { + /* wait until there is someone to join on */ + cond_wait(&(eg->cv), &(eg->lock)); + /* inside of cond_wait, someone can sneek in + * i.e., even if condition variables are implemented in-order + * we do not have guaranteed in-order joins */ + } + + /* get our zombie from the queue */ + thr_data = eg->zombie_out; + if (eg->zombie_out == eg->zombie_in) { + eg->zombie_in = NULL; + eg->zombie_out = NULL; + } else { + eg->zombie_out = eg->zombie_out->next; + } + mutex_unlock(&(eg->lock)); + + /* grab the tid out before we free it */ + tid = thr_data->tid; + /* free the memory from the queue */ + free(thr_data); + /* join on the tid, and return the result */ + return thr_join(tid, status); +} diff --git a/410user/libthrgrp/thrgrp.h b/410user/libthrgrp/thrgrp.h new file mode 100644 index 0000000..73e9e2d --- /dev/null +++ b/410user/libthrgrp/thrgrp.h @@ -0,0 +1,71 @@ +/* @file thrgrp.h + * @brief This file defines the interface for the thread library wrapper. + * This wrapper allows explicit control over what exiting threads get joined + * on by what joining threads. + * @author Matthew Brewer (mbrewer) + */ + +#ifndef THRGRP_H +#define THRGRP_H +#include + +/** + * @brief This is an element of a thread group queue, used for storing + * exited threads. + */ +typedef struct thrgrp_queue_el { + /** @brief the next element in the queue */ + struct thrgrp_queue_el *next; + /** @brief the tid of the thread to exit */ + int tid; +} thrgrp_queue_el_t; + +/** + * @brief This is a structure holding information for joining and exiting + * threads. The idea is that threads exiting on this exitgroup can be joined + * on by threads joining on this exitgroup. + */ +typedef struct { + /* @brief a condition variable holding joiners waiting on exiters */ + cond_t cv; + /* @brief a list of zombie threads waiting to be reaped */ + thrgrp_queue_el_t *zombie_in; + thrgrp_queue_el_t *zombie_out; + /* @brief a mutex for protecting the rest of this data */ + mutex_t lock; +} thrgrp_group_t; + +/** + * @brief This is a temporary structure used for passing data into a spawned + * thread + */ +typedef struct thrgrp_tmp_data { + /** @brief function to call in newly spaned thread */ + void *(*func)(void *); + /** @brief argument to func */ + void *arg; + /** @brief thread group to spawn the new thread in */ + thrgrp_group_t *tg; +} thrgrp_tmp_data_t; + +/** + * @brief This is a union for malloc purposes, so it can be used for + * either a queue element, or temporary data, this way we only have to + * malloc once per thread spawn + */ +typedef union thrgrp_data { + /** @brief a queue element */ + thrgrp_queue_el_t qel; + /** @brief a temporary data structure */ + thrgrp_tmp_data_t tmp; +} thrgrp_data_t; + +int thrgrp_init_group(thrgrp_group_t *eg); + +int thrgrp_destroy_group(thrgrp_group_t *eg); + +int thrgrp_create(thrgrp_group_t *tg, void *(*func)(void *), void *args); + +int thrgrp_join(thrgrp_group_t *tg, void **status); + +#endif /* WRAPTH_H */ diff --git a/410user/libthrgrp/user.mk b/410user/libthrgrp/user.mk new file mode 100644 index 0000000..b35ea3a --- /dev/null +++ b/410user/libthrgrp/user.mk @@ -0,0 +1,7 @@ +410ULIB_THRGRP_OBJS := thrgrp.o +410ULIB_THRGRP_OBJS := $(410ULIB_THRGRP_OBJS:%=$(410UDIR)/libthrgrp/%) + +ALL_410UOBJS += $(410ULIB_THRGRP_OBJS) +410UCLEANS += $(410UDIR)/libthrgrp.a + +$(410UDIR)/libthrgrp.a: $(410ULIB_THRGRP_OBJS) diff --git a/410user/libx86/bcopy.S b/410user/libx86/bcopy.S new file mode 100644 index 0000000..f687231 --- /dev/null +++ b/410user/libx86/bcopy.S @@ -0,0 +1,135 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include + + +#if 0 /* is this useful? */ + +/* l2rbcopy(from, to, bcount) */ + +ENTRY(l2rbcopy) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG2,%edx + movl B_ARG1,%edi + movl B_ARG0,%esi +/* move longs */ +0: cld + movl %edx,%ecx + sarl $2,%ecx + js 1f + rep + movsl +/* move bytes */ + movl %edx,%ecx + andl $3,%ecx + rep + movsb +1: + popl %esi + popl %edi + leave + ret +#endif + + + +/* + * bcopy - like l2rbcopy, but recognizes overlapping ranges and handles + * them correctly. + * bcopy(from, to, bytes) + * char *from, *to; + * int bytes; + */ +ENTRY(bcopy) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG0,%esi + movl B_ARG1,%edi +bcopy_common: + movl B_ARG2,%edx + leal (%esi,%edx), %eax /* from + bytes */ + cmpl %eax, %edi /* <= to */ + jae 0f + leal (%edi,%edx), %eax /* to + bytes */ + cmpl %eax, %esi /* <= from */ + jae 0f + cmpl %esi, %edi /* from > to */ + jb 0f + je 1f + + addl %edx, %esi; decl %esi + addl %edx, %edi; decl %edi + std + movl %edx,%ecx +/* move bytes backwards */ + rep + movsb + cld +1: +/* memcpy: return dest pointer */ + movl B_ARG0,%eax + popl %esi + popl %edi + leave + ret +/* move words forwards */ +0: cld + movl %edx,%ecx + sarl $2,%ecx + js 2f + rep + movsl +/* move bytes forwards */ + movl %edx,%ecx + andl $3,%ecx + rep + movsb +2: +/* memcpy: return dest pointer */ + movl B_ARG0,%eax + popl %esi + popl %edi + leave + ret + +/* memcpy(to, from, count) */ + +ENTRY(memcpy) +ENTRY(memmove) + pushl %ebp + movl %esp,%ebp + pushl %edi + pushl %esi + movl B_ARG0,%edi + movl B_ARG1,%esi + jmp bcopy_common + diff --git a/410user/libx86/bzero.S b/410user/libx86/bzero.S new file mode 100644 index 0000000..6675745 --- /dev/null +++ b/410user/libx86/bzero.S @@ -0,0 +1,47 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bzero.S,v 1.8 1995/04/28 22:57:58 jtc Exp $") +#endif + + +ENTRY(bzero) + pushl %edi + movl S_ARG1,%edi + movl S_ARG2,%edx + + cld /* set fill direction forward */ + xorl %eax,%eax /* set fill data to 0 */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpl $16,%edx + jb L1 + + movl %edi,%ecx /* compute misalignment */ + negl %ecx + andl $3,%ecx + subl %ecx,%edx + rep /* zero until word aligned */ + stosb + + movl %edx,%ecx /* zero by words */ + shrl $2,%ecx + andl $3,%edx + rep + stosl + +L1: movl %edx,%ecx /* zero remainder by bytes */ + rep + stosb + + popl %edi + ret diff --git a/410user/libx86/gccisms.c b/410user/libx86/gccisms.c new file mode 100644 index 0000000..fea7c5b --- /dev/null +++ b/410user/libx86/gccisms.c @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ------------ + * + * Lovingly ripped, slashed, mangled, and mutilated into one file by nwf@, + * 20080814 to fit inside the CS410 universe; in some places this has resulted + * in very carefully constructed, portable code becoming x86 specific. Sorry. + * + * Taken from ftp://ftp.openbsd.org/pub/OpenBSD/3.9/sys.tar.gz + */ + +#define HALF_BITS (sizeof(int)*8/2) +#define B ((int)1 << HALF_BITS) /* digit base */ +#define H 1 /* Endianness matters */ +#define L 0 + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((quad_t)(x) << (number_of_bits_in_int/2)). (`x' must actually be u_int.) + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a quad_t, shifted left + * (sizeof(int)*CHAR_BIT/2). + */ +#define HHALF(x) ((u_int)(x) >> HALF_BITS) +#define LHALF(x) ((u_int)(x) & (((int)1 << HALF_BITS) - 1)) + +typedef unsigned int u_int; + +typedef u_int digit; +typedef long long quad_t; /* 64 bits, signed */ +typedef unsigned long long u_quad_t; /* 64 bits, unsigned */ + +/* + * Depending on the desired operation, we view a `long long' (aka quad_t) in + * one or more of the following formats. + */ +union uu { + quad_t q; /* as a (signed) quad */ + u_quad_t uq; /* as an unsigned quad */ + int sl[2]; /* as two signed ints */ + u_int ul[2]; /* as two unsigned ints */ +}; + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b)) + + +static void shl(digit *p, int len, int sh); + +/* + * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate products + * fit within u_int. As a consequence, the maximum length dividend and + * divisor are 4 `digits' in this base (they are shorter if they have + * leading zeros). + */ +u_quad_t +__qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq) +{ + union uu tmp; + digit *u, *v, *q; + digit v1, v2; + u_int qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vq == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ul[H] = tmp.ul[L] = 1 / zero; + if (arq) + *arq = uq; + return (tmp.q); + } + if (uq < vq) { + if (arq) + *arq = uq; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.uq = uq; + u[0] = 0; + u[1] = (digit)HHALF(tmp.ul[H]); + u[2] = (digit)LHALF(tmp.ul[H]); + u[3] = (digit)HHALF(tmp.ul[L]); + u[4] = (digit)LHALF(tmp.ul[L]); + tmp.uq = vq; + v[1] = (digit)HHALF(tmp.ul[H]); + v[2] = (digit)LHALF(tmp.ul[H]); + v[3] = (digit)HHALF(tmp.ul[L]); + v[4] = (digit)LHALF(tmp.ul[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + u_int rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = (digit)(u[1] / t); + rbj = COMBINE(u[1] % t, u[2]); + q2 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[3]); + q3 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[4]); + q4 = (digit)(rbj / t); + if (arq) + *arq = rbj % t; + tmp.ul[H] = COMBINE(q1, q2); + tmp.ul[L] = COMBINE(q3, q4); + return (tmp.q); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + shl(&u[0], m + n, d); /* u <<= d */ + shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + u_int nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = (digit)LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = (digit)LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = (digit)LHALF(t); + t = HHALF(t); + } + u[j] = (digit)LHALF(u[j] + t); + } + q[j] = (digit)qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (digit)(((u_int)u[i] >> d) | + LHALF((u_int)u[i - 1] << (HALF_BITS - d))); + u[i] = 0; + } + tmp.ul[H] = COMBINE(uspace[1], uspace[2]); + tmp.ul[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.q; + } + + tmp.ul[H] = COMBINE(qspace[1], qspace[2]); + tmp.ul[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.q); +} + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +shl(digit *p, int len, int sh) +{ + int i; + + for (i = 0; i < len; i++) + p[i] = (digit)(LHALF((u_int)p[i] << sh) | + ((u_int)p[i + 1] >> (HALF_BITS - sh))); + p[i] = (digit)(LHALF((u_int)p[i] << sh)); +} + + +/* + * Return remainder after dividing two unsigned quads. + */ +u_quad_t +__umoddi3(u_quad_t a, u_quad_t b) +{ + u_quad_t r; + + (void)__qdivrem(a, b, &r); + return (r); +} + +/* + * Divide two unsigned quads. + */ +u_quad_t +__udivdi3(u_quad_t a, u_quad_t b) +{ + + return (__qdivrem(a, b, (u_quad_t *)0)); +} + +/* + * Divide two signed quads. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +quad_t +__divdi3(quad_t a, quad_t b) +{ + u_quad_t ua, ub, uq; + int neg = 0; + + ua = a; + ub = b; + + if (a < 0) + ua = -ua, neg ^= 1; + if (b < 0) + ub = -ub, neg ^= 1; + + uq = __qdivrem(ua, ub, (u_quad_t *)0); + if (neg) + uq = - uq; + return uq; +} diff --git a/410user/libx86/user.mk b/410user/libx86/user.mk new file mode 100644 index 0000000..a583822 --- /dev/null +++ b/410user/libx86/user.mk @@ -0,0 +1,11 @@ +410U_X86_OBJS := \ + bcopy.o \ + bzero.o \ + gccisms.o \ + +410U_X86_OBJS := $(410U_X86_OBJS:%=$(410UDIR)/libx86/%) + +ALL_410UOBJS += $(410U_X86_OBJS) +410UCLEANS += $(410UDIR)/libx86.a + +$(410UDIR)/libx86.a: $(410U_X86_OBJS) diff --git a/410user/progs/ack.c b/410user/progs/ack.c new file mode 100644 index 0000000..2375ad9 --- /dev/null +++ b/410user/progs/ack.c @@ -0,0 +1,56 @@ +/** @file 410user/progs/ack.c + * @author acrichto + * @brief Computes Ackermann function in multiple threads + * @public yes + * @for p4-smp + * @status done + */ + +/* "Because not all total computable functions are primitive recursive" */ + +#include +#include +#include <410_tests.h> +#include +#include + +DEF_TEST_NAME("ack:"); + +#define ACKN 8 +#define THREADS 8 + +typedef void*(thr_func)(void*); + +int ack(int m, int n) { + if (m == 0) return n + 1; + if (n == 0) return ack(m - 1, 1); + return ack(m - 1, ack(m, n - 1)); +} + +void* ackstart(void *n) { + return (void*) ack(3, (int) n); +} + +int main() { + thr_init(1024 * 128); + int ticks = get_ticks(); + int i, answer, guess; + thrgrp_group_t group; + + REPORT_ON_ERR(thrgrp_init_group(&group)); + for (i = 0; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_create(&group, (thr_func*) ackstart, (void*) ACKN)); + } + + REPORT_ON_ERR(thrgrp_join(&group, (void*) &answer)); + for (i = 1; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_join(&group, (void*) &guess)); + if (guess != answer) { + REPORT_END_FAIL; + } + } + printf("ack(3, %d) = %d\n", ACKN, answer); + printf("ticks taken: %d\n", get_ticks() - ticks); + + thr_exit(0); +} diff --git a/410user/progs/actual_wait.c b/410user/progs/actual_wait.c new file mode 100644 index 0000000..983ddb2 --- /dev/null +++ b/410user/progs/actual_wait.c @@ -0,0 +1,131 @@ +/** @file 410user/progs/actual_wait.c + * @author de0u + * @brief Exercises wait() and vanish(). + * @public yes + * @for p2 p3 + * @covers wait vanish fork yield set_status + * @status done + */ + +#include +#include +#include +#include + +#include "410_tests.h" +DEF_TEST_NAME("actual_wait:"); + +#define NCHILD 40 /* must be < 255 */ +#define PRESERVE (1024*1024) + +void child(int); + +int main(void) +{ + char buf[4096]; + int pid, pids[NCHILD]; + int c, preserve; + char msg[128]; + + buf[0] = buf[sizeof (buf) - 1] = 'q'; + + REPORT_START_CMPLT; + + for (c = 0; c < NCHILD; ++c) + switch(((pid = fork()) < 0) ? -1 : pid) { + case -1: + REPORT_MISC("cannot fork"); + goto fail; + case 0: + child(c); + break; + default: + pids[c] = pid; + + snprintf(msg, sizeof (msg), "slot %d pid %d", c, pid); + printf("%s\n", msg); + REPORT_MISC(msg); + + if (c & 1) + yield(-1); + break; + } + + for (c = 0; c < NCHILD; ++c) { + int slot; + char msg[128]; + + if ((c & 8) == 8) + yield(-1); + + pid = wait(&slot); + + snprintf(msg, sizeof (msg), "slot %d pid %d", slot, pid); + printf("%s\n", msg); + REPORT_MISC(msg); + + if ((slot < 0) || (slot >= NCHILD)) { + REPORT_MISC("invalid slot"); + goto fail; + } + if (pids[slot] != pid) { + REPORT_MISC("pid/slot mismatch"); + goto fail; + } + pids[slot] = -1; + } + + preserve = PRESERVE; + pid = wait(&preserve); + if (pid >= 0) { + REPORT_MISC("phantom menace"); + goto fail; + } + if (preserve != PRESERVE) { + REPORT_MISC("obliteration"); + goto fail; + } + + REPORT_END_SUCCESS; + exit(0); + +fail: + REPORT_END_FAIL; + exit(9); +} + +void +child(int which) +{ + int wpid, gpid; + char msg[128]; + + snprintf(msg, sizeof (msg), "child %d", which); + printf("%s\n", msg); + REPORT_MISC(msg); + + switch(((gpid = fork()) < 0) ? -1 : gpid) { + case -1: + REPORT_MISC("child cannot fork"); + goto fail; + break; + case 0: + if (which & 1) { + yield(-1); + yield(-1); + } + exit(0); + default: + if ((which & 4) != 4) { + if ((wpid = wait(0)) != gpid) { + REPORT_MISC("grandchild??"); + goto fail; + } + } + exit(which); + break; + } + +fail: + exit(-1); +} diff --git a/410user/progs/bg.c b/410user/progs/bg.c new file mode 100644 index 0000000..feccf37 --- /dev/null +++ b/410user/progs/bg.c @@ -0,0 +1,39 @@ +/** @file 410user/progs/bg.c + * @author mjsulliv (2009) + * @brief runs a command in the background + * @public yes + * @for p3,p4 + * @covers fork + * @bug This should arguably be done by the shell. + */ + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int pid; + + if (argv[argc]) printf("*** fsck: %p!\n", argv[argc]); + + if (argc < 2) { + printf("usage: %s program [arguments]\n", argv[0]); + return 1; + } + + if ((pid = fork()) > 0) { + printf("Child pid: %d\n", pid); + return 0; + } else if (pid < 0) { + return 1; + } + + /* Now we are a child, our parent is exiting, so we will be owned by init. + * The shell was waiting on our parent and doesn't give a hoot about us. */ + + int ret = exec(argv[1], &argv[1]); + panic("exec failed: %d!", ret); + + return 0; +} diff --git a/410user/progs/bistromath.c b/410user/progs/bistromath.c new file mode 100644 index 0000000..9b63047 --- /dev/null +++ b/410user/progs/bistromath.c @@ -0,0 +1,7711 @@ +/****************************************************************************** + * This is a port of the chess engine "bistromath" to the Pebbles kernel. + * Both the original and the port are copyright Ben Blum + * 2013, all rights reserved. + * + * Readers interested in the inner workings of the chess engine will be much + * happier navigating the original codebase, where the files are not all + * concatenated together. + * + * ====> http://bblum.net/bistromath.tar.bz2 <==== + * + * The pebbles glue / console interface (which are obviously not present in the + * original version) are at the bottom of this file, around line 7050. + * + * This program incidentally tests for the following Pebbles functionalities: + * - Loading very large ELFs (.bss comes out to be about 192MB) + * - Stack growth (each ply searched takes a little over 32KB of stack) + * - Simple threading -- another thread is used for the search timer + * + * Please direct all questions/bugs to Ben Blum . + * + ****************************************************************************** + * + * This code is licensed under the GNU Library GPL: + * + * 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 Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "rand.h" +#include "thread.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) ((sizeof(a))/(sizeof(a[0]))) +#endif + +/**************************************************************************** + * attacks.h - precomputed attack-/move-mask tables + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef ATTACKS_H +#define ATTACKS_H + +#define U64(x) ((uint64_t)(x ## ull)) +#define U32(x) ((uint32_t)(x)) + +extern uint64_t knightattacks[64]; +extern uint64_t kingattacks[64]; +extern uint64_t pawnattacks[2][64]; +extern uint64_t pawnmoves[2][64]; + +extern uint64_t rowattacks[256][8]; +extern uint64_t colattacks[256][8]; + +extern int rot45diagindex[64]; +extern int rot315diagindex[64]; + +extern int rot45index_shiftamountright[15]; +extern int rot315index_shiftamountright[15]; +extern int rot315index_shiftamountleft[15]; + +extern int rotresult_shiftamountleft[15]; +extern int rotresult_shiftamountright[15]; + +uint64_t rot45attacks[256][8]; +uint64_t rot315attacks[256][8]; + +#endif +/**************************************************************************** + * bitscan.h - useful for switching bitscan implementations + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef BITSCAN_H +#define BITSCAN_H + +#define BITSCAN(x) (ffsll(x)-1) + +#endif + +// Below are ffs.c and ffsll.c from a standard glibc distribution, since 410user +// doesn't have them. + +/* Copyright (C) 1991, 1992, 1997, 1998, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#define ffs(x) __ffs(x) + +/* Find the first bit set in I. */ +int +__ffs (i) + int i; +{ + static const unsigned char table[] = + { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + unsigned int a; + unsigned int x = i & -i; + + a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24); + + return table[x >> a] + a; +} +/* Copyright (C) 1991, 1992, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* Find the first bit set in I. */ +int +ffsll (i) + long long int i; +{ + unsigned long long int x = i & -i; + + if (x <= 0xffffffff) + return ffs (i); + else + return 32 + ffs (i >> 32); +} + +/**************************************************************************** + * popcnt.h - various population-count implementations + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef POPCNT_H +#define POPCNT_H + +/* Can be used to change which implementation we use */ +//#define POPCOUNT(x) popcnt3(x) +#define POPCOUNT(x) popcnt2(x) + +/** + * Returns a count of how many bits are set in the argument. + */ +int popcnt(uint64_t); + +/** + * Alternative implementations + */ +int popcnt2(uint64_t); +int popcnt3(uint64_t); + +#endif +/**************************************************************************** + * rand.h - wrappers for random number generation utilities + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* Set up the random number generator */ +void rand_init(); +/* A "random" 32-bit integer as provided by GSL's mersenne twister */ +uint32_t rand32(); +/* A "random" 64-bit integer as provided by GSL's mersenne twister */ +uint64_t rand64(); + +/**************************************************************************** + * movelist.h - data structure for move sorting in move generation/iteration + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ +#ifndef MOVELIST_H +#define MOVELIST_H + + +#define MOVELIST_NUM_BUCKETS 64 +#define MOVELIST_SUBLIST_LENGTH 128 + +/**************************************************************************** + * Our move ordering scheme will look something like this: + * + * 00-08: Moves that lose material + * 00: -9 (Q hang) + * 01: -8 (Qx protected P) + * 02: -7 (None) + * 03: -6 (Qx protected B/N) + * 04: -5 (R hang) + * 05: -4 (Qx protected R) + * 06: -3 (B/N hang) + * 07: -2 (Bx/Nx protected P, Rx protected B/N) + * 08: -1 (P hang) + * 9-41: Regular moves, indexed by piecetable[dest] - piecetable[src] + 25 + * 42: Minor promotions + * 43: O-O-O + * 44: O-O + * 45-49: Neutral captures + * 45: PxP + * 46: NxN + * 47: BxB + * 48: RxR + * 49: QxQ + * 50-58: Moves that win material + * 50: +1 (P unhang, *x hung P) + * 51: +2 (Px protected B/N, Bx/Nx protected R) + * 52: +3 (B/N unhang, *x hung B/N) + * 53: +4 (Px protected R) + * 54: +5 (R unhang, *x hung B/N) + * 55: +6 (Bx/Nx protected Q) + * 56: +7 (None) + * 57: +8 (Px protected Q) + * 58: +9 (Q unhang, *x hung Q) + * 59: Promotions to queen + * 60: Promotions to queen with capture + * 61: K unhang + ****************************************************************************/ + +/* starting index for moves that lose material - subtract how much is lost */ +#define MOVELIST_INDEX_MAT_LOSS 9 +/* regular move - add the piece/square table difference */ +#define MOVELIST_INDEX_REGULAR 25 +/* minor promotion - the thought behind this is if the Q promotion is wrong, + * probably this will be too, so try other moves first */ +#define MOVELIST_INDEX_PROM_MINOR 42 +/* castle - add 1 if kingside */ +#define MOVELIST_INDEX_CASTLE 43 +/* neutral capture - add the piece number (P=0 ... Q=4) */ +#define MOVELIST_INDEX_NEUTRAL 45 +/* moves that win material - add how much is gained */ +#define MOVELIST_INDEX_MAT_GAIN 49 +/* promotion to queen - add one if it's also a capture */ +#define MOVELIST_INDEX_PROM_QUEEN 59 + +/** + * The movelist_t data structure is a generalization of maintaining multiple + * linkedlists and appending them at the end for O(n) pseudo-sorting - it + * allows an arbitrary number of lists for sorting into that many buckets, + * with the only constraints being 1) space and 2) time to move the "max" + * index to point to the next bucket when one bucket is empty. The result is + * O(n) sorting during creation (beating O(n^2 logn)), but an additional O(m) + * coefficient for both space and time complexity, so choose a small m! + */ +typedef struct { + uint32_t array[MOVELIST_NUM_BUCKETS][MOVELIST_SUBLIST_LENGTH]; + int sublist_count[MOVELIST_NUM_BUCKETS]; + /* highest index of a bucket which contains elements; note, if + * array[max] is empty, that means the whole movelist is empty */ + unsigned long max; +} movelist_inner_t; + +typedef movelist_inner_t *movelist_t; + +/* Movelist's max should be zero, each array should be zero, and each +* array should have a count of zero. */ +static inline void movelist_init(movelist_t *ml) +{ + *ml = malloc(sizeof(movelist_inner_t)); + affirm_msg(*ml, "Couldn't allocate memory to generate moves"); + memset((*ml)->sublist_count, 0, MOVELIST_NUM_BUCKETS*sizeof(int)); + (*ml)->max = 0; +} + +#define movelist_destroy(mlp) do { free(*mlp); } while (0) + +void movelist_add(movelist_t *, uint64_t[2], uint32_t); +void movelist_addtohead(movelist_t *, uint32_t, unsigned long); +int movelist_isempty(movelist_t *); +uint32_t movelist_remove_max(movelist_t *); + +#endif + +/**************************************************************************** + * board.h - rotated bitboard library; move generation and board state + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef BOARD_H +#define BOARD_H + +/** + * Piece/color constants. Used as indices to get the position bitboard of a + * given piece of a given color, among other things. + */ +#define WHITE 0 +#define BLACK 1 + +/* The color not thise one. Equivalent to "x == WHITE ? BLACK : WHITE" */ +#define OTHERCOLOR(x) (1^(x)) +/* This player's home-rank (0 for white, 7 for black) */ +#define HOMEROW(x) ((x == WHITE) ? 0 : 7) + +/* Piece types */ +#define PAWN 0x0 +#define KNIGHT 0x1 +#define BISHOP 0x2 +#define ROOK 0x3 +#define QUEEN 0x4 +#define KING 0x5 +#define PIECE_SLIDES(p) (((p) > KNIGHT) && ((p) < KING)) +typedef uint8_t piece_t; + +extern char *piecename[2][6]; + +/** + * Square constants. 6 lowest bits: |0|0|r|o|w|c|o|l| + * These can serve as indexes to get bits out of a bitboard. Also used to get + * masks for sliding pieces by row/etc + */ +#define A1 0x00 +#define B1 0x01 +#define C1 0x02 +#define D1 0x03 +#define E1 0x04 +#define F1 0x05 +#define G1 0x06 +#define H1 0x07 +#define A2 0x08 +#define B2 0x09 +#define C2 0x0a +#define D2 0x0b +#define E2 0x0c +#define F2 0x0d +#define G2 0x0e +#define H2 0x0f +#define A3 0x10 +#define B3 0x11 +#define C3 0x12 +#define D3 0x13 +#define E3 0x14 +#define F3 0x15 +#define G3 0x16 +#define H3 0x17 +#define A4 0x18 +#define B4 0x19 +#define C4 0x1a +#define D4 0x1b +#define E4 0x1c +#define F4 0x1d +#define G4 0x1e +#define H4 0x1f +#define A5 0x20 +#define B5 0x21 +#define C5 0x22 +#define D5 0x23 +#define E5 0x24 +#define F5 0x25 +#define G5 0x26 +#define H5 0x27 +#define A6 0x28 +#define B6 0x29 +#define C6 0x2a +#define D6 0x2b +#define E6 0x2c +#define F6 0x2d +#define G6 0x2e +#define H6 0x2f +#define A7 0x30 +#define B7 0x31 +#define C7 0x32 +#define D7 0x33 +#define E7 0x34 +#define F7 0x35 +#define G7 0x36 +#define H7 0x37 +#define A8 0x38 +#define B8 0x39 +#define C8 0x3a +#define D8 0x3b +#define E8 0x3c +#define F8 0x3d +#define G8 0x3e +#define H8 0x3f +typedef uint8_t square_t; + +/* Converts int to string. Better than using malloc for 3-length strings. */ +extern char *squarename[64]; + +#define RANK_1 0 +#define RANK_2 1 +#define RANK_3 2 +#define RANK_4 3 +#define RANK_5 4 +#define RANK_6 5 +#define RANK_7 6 +#define RANK_8 7 +#define COL_A 0 +#define COL_B 1 +#define COL_C 2 +#define COL_D 3 +#define COL_E 4 +#define COL_F 5 +#define COL_G 6 +#define COL_H 7 + +/* converting square <--> (column,row) */ +#define COL(s) ((s) & 0x7) /* 0<=s<64 */ +#define ROW(s) ((s) >> 3) /* 0<=s<64 */ +#define SQUARE(c,r) ((square_t)((c) | ((r) << 3))) /* 0<=c,r<8 */ +/* what color is the square - 1 or 0, not necessarily BLACK or WHITE */ +#define PARITY(s) ((COL(s) + ROW(s)) & 0x1) + +/* Used mostly as array indices, especially for castling */ +#define QUEENSIDE 0 +#define KINGSIDE 1 +/* Given the side of the board, which column will the king end up on */ +#define CASTLE_DEST_COL(x) (((x) == QUEENSIDE) ? COL_C : COL_G) + +/* Constants for board_mated return values */ +#define BOARD_CHECKMATED 1 +#define BOARD_STALEMATED 2 + +/** + * move_t will contain a src square (lowest 6 bits), a dest square (next 6 + * bits), and several flags - is check, isenpassant, iscapture (and what + * piece type is captured), ispromotion (and what is promoted to), and + * also which color made the move. + * 000000 JJJ III HHH G F E D C BBBBBB AAAAAA + * 26 23 20 17 16 15 14 13 12 6 0 + * A: Source square + * B: Dest square + * C: Color (which side is making this move) + * D: Castle + * E: En passant + * F: Capture + * G: Promotion + * H: Captured piece type (color will be the opposite of C) + * I: Promotion result piece type (color indicated by C) + * J: Which piece type is moving (color indicated by C) + * 0: Unused bits + * Note: Bits 25 and up are used for the repetition count in the transposition + * table; see transposition.{h,c} + */ +typedef uint32_t move_t; +#define MOV_INDEX_SRC 0 +#define MOV_INDEX_DEST 6 +#define MOV_INDEX_COLOR 12 +#define MOV_INDEX_CASTLE 13 +#define MOV_INDEX_EP 14 +#define MOV_INDEX_CAPT 15 +#define MOV_INDEX_PROM 16 +#define MOV_INDEX_CAPTPC 17 +#define MOV_INDEX_PROMPC 20 +#define MOV_INDEX_PIECE 23 +#define MOV_INDEX_UNUSED 26 + +#define MOV_SRC(m) ((square_t)(((m) >> MOV_INDEX_SRC) & 0x3f)) +#define MOV_DEST(m) ((square_t)(((m) >> MOV_INDEX_DEST) & 0x3f)) +#define MOV_COLOR(m) (((m) >> MOV_INDEX_COLOR) & 0x1) +#define MOV_CASTLE(m) (((m) >> MOV_INDEX_CASTLE) & 0x1) +#define MOV_EP(m) (((m) >> MOV_INDEX_EP) & 0x1) +#define MOV_CAPT(m) (((m) >> MOV_INDEX_CAPT) & 0x1) +#define MOV_PROM(m) (((m) >> MOV_INDEX_PROM) & 0x1) +#define MOV_CAPTPC(m) ((piece_t)(((m) >> MOV_INDEX_CAPTPC) & 0x7)) +#define MOV_PROMPC(m) ((piece_t)(((m) >> MOV_INDEX_PROMPC) & 0x7)) +#define MOV_PIECE(m) ((piece_t)(((m) >> MOV_INDEX_PIECE) & 0x7)) + +/** + * 64-bit representation of a board's state for one set of piece, also used + * for representing attacks, regions of the board, ... + */ +typedef uint64_t bitboard_t; + +/** + * Zobrist hash key + */ +typedef uint64_t zobrist_t; + +/* Upper bound on how many halfmoves a game should take. Memory is cheap. */ +#define HISTORY_STACK_SIZE 2048 + +/** + * Nonrecomputable state stored on the history stack when a move is made + */ +typedef struct { + zobrist_t hash; + bitboard_t attackedby[2]; + unsigned char castle[2][2]; + square_t ep; + unsigned char halfmoves; + unsigned char reps; + move_t move; +} history_t; + +/**************************************************************************** + * Representation of an entire board state. + * The pos[][] array represents standard normal-oriented setups, accessed by + * piece and color. Normally oriented bitboards look like this: + * + * (64-bit format by square) + * H8 G8 F8 E8 D8 C8 B8 A8 H7 G7 ... A2 H1 G1 F1 E1 D1 C1 B1 A1 + * 63 62 61 60 59 58 57 56 55 54 ... 8 7 6 5 4 3 2 1 0 + * + * (8x8 format by index (from the least significant bit)) + * ------------------------- + * 8 | 56 57 58 59 60 61 62 63 | + * 7 | ... 54 55 | + * | ... | + * 3 | 16 17 ... | + * 2 | 8 9 10 11 12 13 14 15 | + * 1 | 0 1 2 3 4 5 6 7 | + * ------------------------- + * a b c d e f g h + * + * The n-th index row (0 for 1, 7 for 8) can be extracted by + * "(bitboard >> (8*n)) & 0xFF". The rotated boards are slightly different. + * Rot90, used for rook attacks, looks like this: + * + * H8 H7 H6 H5 H4 H3 H2 H1 G8 G7 ... B1 A8 A7 A6 A5 A4 A3 A2 A1 + * 63 62 61 60 59 58 57 56 55 54 ... 8 7 6 5 4 3 2 1 0 + * + * ------------------------- + * h | 56 57 58 59 60 61 62 63 | + * g | ... 54 55 | + * | ... | + * c | 16 17 ... | + * b | 8 9 10 11 12 13 14 15 | + * a | 0 1 2 3 4 5 6 7 | + * ------------------------- + * 1 2 3 4 5 6 7 8 + * + * So the n-th index file (0 for a, 7 for h) can be obtained easily. Note that + * "rot90" is a lie, it's actually flipped across the a1-h8 diagonal. For + * bishops, we rotate so squares on a single diagonal are adjacent. + * rot45: rot315: + * ,--, 8 ,--, + * ,' 63 ', 7 ,' 63 ', + * ,' 61 62 ', 6 ,' 61 62 ', + * ,' 58 59 60 ', 5 ,' 58 59 60 ', + * ,' 54 55 56 57 ', 4 ,' 54 55 56 57 ', + * ,' 49 50 51 52 53 ', 3 ,' 49 50 51 52 53 ', + * ,' 43 44 45 46 47 48 ', 2 ,' 43 44 45 46 47 48 ', + * ,' 36 37 38 39 40 41 42 ', 1 ,' 36 37 38 39 40 41 42 ', + * ( 28 29 30 31 32 33 34 35 ) ( 28 29 30 31 32 33 34 35 ) + * 8 ', 21 22 23 24 25 26 27 ,' h a ', 21 22 23 24 25 26 27 ,' + * 7 ', 15 16 17 18 19 20 ,' g b ', 15 16 17 18 19 20 ,' + * 6 ', 10 11 12 13 14 ,' f c ', 10 11 12 13 14 ,' + * 5 ', 06 07 08 09 ,' e d ', 06 07 08 09 ,' + * 4 ', 03 04 05 ,' d e ', 03 04 05 ,' + * 3 ', 01 02 ,' c f ', 01 02 ,' + * 2 ', 00 ,' b g ', 00 ,' + * 1 '--' a h '--' + * Diagonals are "numbered" 0 to 14 (15 in total); in each diagram the diag + * on the bottom will be #0, the major diagonal will be #7, and the top #14. + * See precomputed.h for values and macros relating to this implementation. + ****************************************************************************/ +typedef struct { + /* These arrays contain basic information about where the pieces are + * on the board. Used generally for masking with attack bitboards. */ + bitboard_t pos[2][6]; /* Positions of each PIECE of COLOR */ + bitboard_t piecesofcolor[2]; /* All squares occupied by COLOR */ + bitboard_t attackedby[2]; /* All squares attacked by COLOR */ + /* Maintain the occupancy status of every square on the board in four + * rotated boards, for easy generation of sliding attacks. */ + bitboard_t occupied; + bitboard_t occupied90; + bitboard_t occupied45; + bitboard_t occupied315; + /* The zobrist hash key for the current position */ + zobrist_t hash; + /* Stores nonrecomputable state for undo. Index into with ->moves. */ + history_t history[HISTORY_STACK_SIZE]; + /* Various flags relating to the current position. Note for the ep + * flag that the capture square will always be on the 3rd (2-index) + * row, or the 6th (5-index) row. A value of zero means no enpassant + * is possible in this position. */ + square_t ep; /* The square on which an ep capture + * could occur */ + unsigned char castle[2][2]; /* Can {WHITE,BLACK} castle {KINGSIDE, + * QUEENSIDE} */ + unsigned char hascastled[2]; /* has {WHITE,BLACK} castled yet */ + unsigned char tomove; /* Who has the move (WHITE, BLACK) */ + unsigned char halfmoves; /* The halfmove clock. A draw occurs when + * this hits 100. */ + unsigned int moves; /* The game move clock. This also counts + * halfmoves, but is never reset. */ + unsigned char reps; /* how many times has this position + * appeared before? if 2, draw */ + int16_t material[2]; /* keeps track of material; see eval.c */ +} board_t; + +/**************************************************************************** + * Some special macros and precomputed bitboards + ****************************************************************************/ +#define BB(b) ((bitboard_t)(b ## ull)) +#define BB_FILEA BB(0x0101010101010101) +#define BB_FILEB BB(0x0202020202020202) +#define BB_FILEC BB(0x0404040404040404) +#define BB_FILED BB(0x0808080808080808) +#define BB_FILEE BB(0x1010101010101010) +#define BB_FILEF BB(0x2020202020202020) +#define BB_FILEG BB(0x4040404040404040) +#define BB_FILEH BB(0x8080808080808080) +#define BB_FILE(c) (BB_FILEA << (c)) +#define BB_RANK1 BB(0x00000000000000ff) +#define BB_RANK2 BB(0x000000000000ff00) +#define BB_RANK3 BB(0x0000000000ff0000) +#define BB_RANK4 BB(0x00000000ff000000) +#define BB_RANK5 BB(0x000000ff00000000) +#define BB_RANK6 BB(0x0000ff0000000000) +#define BB_RANK7 BB(0x00ff000000000000) +#define BB_RANK8 BB(0xff00000000000000) +#define BB_RANK(r) (BB_RANK1 << (8 * (r))) +#define BB_HALF_RANKS(s) (((s) == WHITE) ? BB(0x00000000ffffffff) : BB(0xffffffff00000000)) +#define BB_HALF_FILES(s) (((s) == QUEENSIDE) ? BB(0x0f0f0f0f0f0f0f0f) : BB(0xf0f0f0f0f0f0f0f0)) + + +/* pawnstructure needs these */ +extern bitboard_t bb_adjacentcols[8]; +extern bitboard_t bb_passedpawnmask[2][64]; + +/* BB_SQUARE: Get a bitboard with only one bit set, on a specified square + * Bb_ALLEXCEPT: The bitwise negation of BB_SQUARE(x) */ +//#define BB_SHIFTFLIP /* prefer shift/flip to cached memory lookups */ +#ifdef BB_SHIFTFLIP + #define BB_SQUARE(x) BB((BB(0x1))<<(x)) + #define BB_ALLEXCEPT(x) BB(~(BB_SQUARE(x))) +#else + #define BB_SQUARE(x) bb_square[x] + #define BB_ALLEXCEPT(x) bb_allexcept[x] + extern bitboard_t bb_square[64]; + extern bitboard_t bb_allexcept[64]; +#endif + +/* If you are {white,black}, you ep-capture with a pawn on rank {5,4} */ +#define BB_EP_FROMRANK(c) (((c) == WHITE) ? BB_RANK5 : BB_RANK4) +/* If you are {white,black}, your pawn will be ep-captured on {3,6} */ +#define BB_EP_TORANK(c) (((c) == WHITE) ? BB_RANK3 : BB_RANK6) + +/**************************************************************************** + * Function declarations + ****************************************************************************/ +void init_zobrist(); +void zobrist_gen(board_t *); + +board_t *board_init(); +void board_destroy(board_t *); +char *board_fen(board_t *); +piece_t board_pieceatsquare(board_t *, square_t, unsigned char *); +int board_incheck(board_t *); +int board_colorincheck(board_t *, unsigned char); +int board_mated(board_t *); +int board_pawnpassed(board_t *, square_t, unsigned char); +int board_squareisattacked(board_t *, square_t, unsigned char); +int board_squaresareattacked(board_t *, bitboard_t, unsigned char); +bitboard_t board_attacksfrom(board_t *, square_t, piece_t, unsigned char); +bitboard_t board_pawnpushesfrom(board_t *, square_t, unsigned char); +void board_generatemoves(board_t *, movelist_t *); +void board_generatecaptures(board_t *, movelist_t *); +void board_applymove(board_t *, move_t); +void board_undomove(board_t *, move_t); +bitboard_t board_pawnattacks(bitboard_t pawns, unsigned char); +int board_threefold_draw(board_t *); + +move_t move_fromstring(char *); +move_t move_islegal(board_t *, char *, char **); +char *move_tostring(move_t); + +#endif +/**************************************************************************** + * eval.h - evaluation function to tell how good a position is + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef EVAL_H +#define EVAL_H + +#ifndef EVAL_LAZY_THRESHHOLD +#define EVAL_LAZY_THRESHHOLD 250 +#endif + +/** + * Is this board an endgame position + */ +int eval_isendgame(board_t *); + +/** + * Evaluation function. Given a board, returns an int value representing how + * good this position is for whoever has the move. A positive score means the + * player to move has the advantage; a negative score means the player to move + * has the disadvantage; a zero score means both sides have equal chances. + */ +int16_t eval(board_t *); + +/** + * Lazy eval - just the material difference + */ +int16_t eval_lazy(board_t *); + +#endif +/**************************************************************************** + * pawnstructure.h - evaluation helpers to judge pawn structure quality + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ +#ifndef PAWNSTRUCTURE_H +#define PAWNSTRUCTURE_H + +/** + * Evaluate the pawn structure given the position bitboard for the pawns. We + * don't want to consider anything besides the position of the pawns relative + * to each other - this just assigns rewards and penalties for pawn-related + * issues such as doubled pawns, isolated pawns, etcetera. + * Pass in the pawn position bitboard and the color to whom these pwans belong + */ +int16_t eval_pawnstructure(board_t *, unsigned char, bitboard_t *); + +#endif +/**************************************************************************** + * quiescent.h - captures-only search to avoid evaluating unstable position + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef QUIESCENT_H +#define QUIESCENT_H + +int16_t quiesce(board_t *board, int16_t alpha, int16_t beta); + +#endif +/**************************************************************************** + * transposition.h - avoid re-searching already searched positions + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef TRANSPOSITION_H +#define TRANSPOSITION_H + +/** + * Transposition table - keyed by zobrist hash, stores info about a node. We + * keep track of the following data: + * 1) The best move at this position (possibly 0, if a fail-low occurred) + * 2) The evaluated (or approximate) value of the position + * 3) The depth this node was searched to, or -1 if this was {check,stale}mate + * Note we use -1 (as an unsigned depth value) so that we will always use + * transposition information for terminal nodes rather than wasting time + * figuring out how big the movelist is. + * 4) How far into the game (not search tree) this position is. This data lets + * us always evict nodes beyond which the state of the game has gone. Note, + * 5) What type of values these are: + * Exact value + * Beta cutoff - failed high (storedval is lower bound) + * Alpha cutoff - failed low (storedval is upper bound) + * + * Note: The "depth" should not be simply the depth to which this node was + * searched. It should be instead that depth plus how far into the game we are + * (i.e., the game clock). This will help us replace nodes that are behind our + * search tree entirely - otherwise, the table will fill with high-depth nodes + * that we'll never use because they were back in the beginning of the game. + * When comparing for replacement, use the gamedepth of the root node (the + * position currently on the board), but when adding, use the gamedepth of + * the current node (the position a few moves in the future). Because of + * this the searcher needs to pass both values to trans_add(). + * Definitions: "search depth" refers to how deep this node will be searched; + * "game depth" refer's to THIS NODE's depth in the whole game tree; "root + * depth" refers to how deep the position the searcher started at is. + */ +typedef struct trans_data_t { + /* gcc -O3 optimizes all this into a register; + * note, the element ordering is critical */ + uint8_t flags; + uint8_t gamedepth; + int16_t value; + uint32_t move; +} trans_data_t; +/* The 'flags' field stores the alpha/beta/exact flags in two bits and the + * searched-depth of the node + * BBBBBB AA + * 2 0 + * A: Alpha/beta/exact + * B: searchdepth + * If we search deeper than 63 plies then we're in trouble. + * */ +#define TRANS_FLAG_EXACT 0x2 +#define TRANS_FLAG_BETA 0x1 +#define TRANS_FLAG_ALPHA 0x0 +/* Conversion macros - see trans_data() in trans.c for the other direction */ +#define TRANS_INDEX_FLAG 0 +#define TRANS_INDEX_SEARCHDEPTH 2 +#define TRANS_FLAG(t) (((t).flags >> TRANS_INDEX_FLAG) & 0x3) +#define TRANS_SEARCHDEPTH(t) (((t).flags >> TRANS_INDEX_SEARCHDEPTH) & 0x3f) +#define TRANS_GAMEDEPTH(t) ((t).gamedepth) +#define TRANS_VALUE(t) ((t).value) +#define TRANS_MOVE(t) ((t).move & ((1 << MOV_INDEX_UNUSED) - 1)) +#define TRANS_REPS(t) ((t).move >> MOV_INDEX_UNUSED) + +/* Add an entry. On collision, will succeed only if it's better information */ +void trans_add(zobrist_t, move_t, uint8_t, int16_t, uint8_t, uint8_t, uint8_t, + unsigned char); +/* Find a value from the table. Returns -1 if none exists - you can trust this + * value because a trans_data_t will never be -1 due to the blank bits */ +trans_data_t trans_get(zobrist_t); +/* Check if the return value from get() was valid */ +int trans_data_valid(trans_data_t); + +#endif +/**************************************************************************** + * book.h - simple interface for retrieving moves from a plaintext book + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ +#ifndef BOOK_H +#define BOOK_H + +#define BOOK_LINE_MAX_LENGTH 256 + +move_t book_move(char *line, board_t *board); + +#endif +/**************************************************************************** + * search.h - traverse the game tree looking for the best position + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef SEARCH_H +#define SEARCH_H + +/** + * A search function will require the following arguments: + * 1) Board state + * 2) How many seconds we should think before moving + * 3) int * - if nonnull, lets you know how many nodes were searched + * 4) int * - if nonnull, lets you know the alpha value of the position + */ +typedef move_t (*search_fn)(board_t *, unsigned int, int *, int16_t *); + +move_t getbestmove(board_t *, unsigned int, int *, int16_t *); + +#endif +/**************************************************************************** + * engine.c - wrapper functions for managing computer vs human play + * copyright (C) 2008 Ben Blum + ****************************************************************************/ +#ifndef ENGINE_H +#define ENGINE_H + + +#define ENGINE_NAME "bistromath" + +typedef struct engine_t { + board_t *board; + search_fn search; + char line[BOOK_LINE_MAX_LENGTH]; + unsigned int line_moves; + unsigned char inbook; +} engine_t; + +engine_t *engine_init(search_fn); +char *engine_generatemove(engine_t *); +int engine_applymove(engine_t *, char *, char **); +void engine_destroy(engine_t *); + +#endif +/**************************************************************************** + * attacks.c - precomputed attack-/move-mask tables + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* Bitmasks for attackable squares given a square a certain piece is on. Use + * the predefined constants (A1 to H8, 0-63) from bitboard.h, or some other + * way of getting the square in the same format, to index into these arrays */ +uint64_t knightattacks[64] = { + /* A1 to H1 */ + U64(0x0000000000020400), U64(0x0000000000050800), U64(0x00000000000a1100), U64(0x0000000000142200), + U64(0x0000000000284400), U64(0x0000000000508800), U64(0x0000000000a01000), U64(0x0000000000402000), + /* A2 to H2 */ + U64(0x0000000002040004), U64(0x0000000005080008), U64(0x000000000a110011), U64(0x0000000014220022), + U64(0x0000000028440044), U64(0x0000000050880088), U64(0x00000000a0100010), U64(0x0000000040200020), + /* A3 to H3 */ + U64(0x0000000204000402), U64(0x0000000508000805), U64(0x0000000a1100110a), U64(0x0000001422002214), + U64(0x0000002844004428), U64(0x0000005088008850), U64(0x000000a0100010a0), U64(0x0000004020002040), + /* A4 to H4 */ + U64(0x0000020400040200), U64(0x0000050800080500), U64(0x00000a1100110a00), U64(0x0000142200221400), + U64(0x0000284400442800), U64(0x0000508800885000), U64(0x0000a0100010a000), U64(0x0000402000204000), + /* A5 to H5 */ + U64(0x0002040004020000), U64(0x0005080008050000), U64(0x000a1100110a0000), U64(0x0014220022140000), + U64(0x0028440044280000), U64(0x0050880088500000), U64(0x00a0100010a00000), U64(0x0040200020400000), + /* A6 to H6 */ + U64(0x0204000402000000), U64(0x0508000805000000), U64(0x0a1100110a000000), U64(0x1422002214000000), + U64(0x2844004428000000), U64(0x5088008850000000), U64(0xa0100010a0000000), U64(0x4020002040000000), + /* A7 to H7 */ + U64(0x0400040200000000), U64(0x0800080500000000), U64(0x1100110a00000000), U64(0x2200221400000000), + U64(0x4400442800000000), U64(0x8800885000000000), U64(0x100010a000000000), U64(0x2000204000000000), + /* A8 to H8 */ + U64(0x0004020000000000), U64(0x0008050000000000), U64(0x00110a0000000000), U64(0x0022140000000000), + U64(0x0044280000000000), U64(0x0088500000000000), U64(0x0010a00000000000), U64(0x0020400000000000) +}; +uint64_t kingattacks[64] = { + /* A1 to H1 */ + U64(0x0000000000000302), U64(0x0000000000000705), U64(0x0000000000000e0a), U64(0x0000000000001c14), + U64(0x0000000000003828), U64(0x0000000000007050), U64(0x000000000000e0a0), U64(0x000000000000c040), + /* A2 to H2 */ + U64(0x0000000000030203), U64(0x0000000000070507), U64(0x00000000000e0a0e), U64(0x00000000001c141c), + U64(0x0000000000382838), U64(0x0000000000705070), U64(0x0000000000e0a0e0), U64(0x0000000000c040c0), + /* A3 to H3 */ + U64(0x0000000003020300), U64(0x0000000007050700), U64(0x000000000e0a0e00), U64(0x000000001c141c00), + U64(0x0000000038283800), U64(0x0000000070507000), U64(0x00000000e0a0e000), U64(0x00000000c040c000), + /* A4 to H4 */ + U64(0x0000000302030000), U64(0x0000000705070000), U64(0x0000000e0a0e0000), U64(0x0000001c141c0000), + U64(0x0000003828380000), U64(0x0000007050700000), U64(0x000000e0a0e00000), U64(0x000000c040c00000), + /* A5 to H5 */ + U64(0x0000030203000000), U64(0x0000070507000000), U64(0x00000e0a0e000000), U64(0x00001c141c000000), + U64(0x0000382838000000), U64(0x0000705070000000), U64(0x0000e0a0e0000000), U64(0x0000c040c0000000), + /* A6 to H6 */ + U64(0x0003020300000000), U64(0x0007050700000000), U64(0x000e0a0e00000000), U64(0x001c141c00000000), + U64(0x0038283800000000), U64(0x0070507000000000), U64(0x00e0a0e000000000), U64(0x00c040c000000000), + /* A7 to H7 */ + U64(0x0302030000000000), U64(0x0705070000000000), U64(0x0e0a0e0000000000), U64(0x1c141c0000000000), + U64(0x3828380000000000), U64(0x7050700000000000), U64(0xe0a0e00000000000), U64(0xc040c00000000000), + /* A8 to H8 */ + U64(0x0203000000000000), U64(0x0507000000000000), U64(0x0a0e000000000000), U64(0x141c000000000000), + U64(0x2838000000000000), U64(0x5070000000000000), U64(0xa0e0000000000000), U64(0x40c0000000000000) +}; +uint64_t pawnattacks[2][64] = { + { /* WHITE */ + /* A1 to H1 */ + U64(0x0000000000000200), U64(0x0000000000000500), U64(0x0000000000000a00), U64(0x0000000000001400), + U64(0x0000000000002800), U64(0x0000000000005000), U64(0x000000000000a000), U64(0x0000000000004000), + /* A2 to H2 */ + U64(0x0000000000020000), U64(0x0000000000050000), U64(0x00000000000a0000), U64(0x0000000000140000), + U64(0x0000000000280000), U64(0x0000000000500000), U64(0x0000000000a00000), U64(0x0000000000400000), + /* A3 to H3 */ + U64(0x0000000002000000), U64(0x0000000005000000), U64(0x000000000a000000), U64(0x0000000014000000), + U64(0x0000000028000000), U64(0x0000000050000000), U64(0x00000000a0000000), U64(0x0000000040000000), + /* A4 to H4 */ + U64(0x0000000200000000), U64(0x0000000500000000), U64(0x0000000a00000000), U64(0x0000001400000000), + U64(0x0000002800000000), U64(0x0000005000000000), U64(0x000000a000000000), U64(0x0000004000000000), + /* A5 to H5 */ + U64(0x0000020000000000), U64(0x0000050000000000), U64(0x00000a0000000000), U64(0x0000140000000000), + U64(0x0000280000000000), U64(0x0000500000000000), U64(0x0000a00000000000), U64(0x0000400000000000), + /* A6 to H6 */ + U64(0x0002000000000000), U64(0x0005000000000000), U64(0x000a000000000000), U64(0x0014000000000000), + U64(0x0028000000000000), U64(0x0050000000000000), U64(0x00a0000000000000), U64(0x0040000000000000), + /* A7 to H7 */ + U64(0x0200000000000000), U64(0x0500000000000000), U64(0x0a00000000000000), U64(0x1400000000000000), + U64(0x2800000000000000), U64(0x5000000000000000), U64(0xa000000000000000), U64(0x4000000000000000), + /* A8 to H8 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000) + }, + { /* BLACK */ + /* A1 to H1 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + /* A2 to H2 */ + U64(0x0000000000000002), U64(0x0000000000000005), U64(0x000000000000000a), U64(0x0000000000000014), + U64(0x0000000000000028), U64(0x0000000000000050), U64(0x00000000000000a0), U64(0x0000000000000040), + /* A3 to H3 */ + U64(0x0000000000000200), U64(0x0000000000000500), U64(0x0000000000000a00), U64(0x0000000000001400), + U64(0x0000000000002800), U64(0x0000000000005000), U64(0x000000000000a000), U64(0x0000000000004000), + /* A4 to H4 */ + U64(0x0000000000020000), U64(0x0000000000050000), U64(0x00000000000a0000), U64(0x0000000000140000), + U64(0x0000000000280000), U64(0x0000000000500000), U64(0x0000000000a00000), U64(0x0000000000400000), + /* A5 to H5 */ + U64(0x0000000002000000), U64(0x0000000005000000), U64(0x000000000a000000), U64(0x0000000014000000), + U64(0x0000000028000000), U64(0x0000000050000000), U64(0x00000000a0000000), U64(0x0000000040000000), + /* A6 to H6 */ + U64(0x0000000200000000), U64(0x0000000500000000), U64(0x0000000a00000000), U64(0x0000001400000000), + U64(0x0000002800000000), U64(0x0000005000000000), U64(0x000000a000000000), U64(0x0000004000000000), + /* A7 to H7 */ + U64(0x0000020000000000), U64(0x0000050000000000), U64(0x00000a0000000000), U64(0x0000140000000000), + U64(0x0000280000000000), U64(0x0000500000000000), U64(0x0000a00000000000), U64(0x0000400000000000), + /* A8 to H8 */ + U64(0x0002000000000000), U64(0x0005000000000000), U64(0x000a000000000000), U64(0x0014000000000000), + U64(0x0028000000000000), U64(0x0050000000000000), U64(0x00a0000000000000), U64(0x0040000000000000) + } +}; +/* Don't account for the double-pawn-pushes; the pawn moves generator takes + * care of that */ +uint64_t pawnmoves[2][64] = { + { /* WHITE */ + /* A1 to H1 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + /* A2 to H2 */ + U64(0x0000000000010000), U64(0x0000000000020000), U64(0x0000000000040000), U64(0x0000000000080000), + U64(0x0000000000100000), U64(0x0000000000200000), U64(0x0000000000400000), U64(0x0000000000800000), + /* A3 to H3 */ + U64(0x0000000001000000), U64(0x0000000002000000), U64(0x0000000004000000), U64(0x0000000008000000), + U64(0x0000000010000000), U64(0x0000000020000000), U64(0x0000000040000000), U64(0x0000000080000000), + /* A4 to H4 */ + U64(0x0000000100000000), U64(0x0000000200000000), U64(0x0000000400000000), U64(0x0000000800000000), + U64(0x0000001000000000), U64(0x0000002000000000), U64(0x0000004000000000), U64(0x0000008000000000), + /* A5 to H5 */ + U64(0x0000010000000000), U64(0x0000020000000000), U64(0x0000040000000000), U64(0x0000080000000000), + U64(0x0000100000000000), U64(0x0000200000000000), U64(0x0000400000000000), U64(0x0000800000000000), + /* A6 to H6 */ + U64(0x0001000000000000), U64(0x0002000000000000), U64(0x0004000000000000), U64(0x0008000000000000), + U64(0x0010000000000000), U64(0x0020000000000000), U64(0x0040000000000000), U64(0x0080000000000000), + /* A7 to H7 */ + U64(0x0100000000000000), U64(0x0200000000000000), U64(0x0400000000000000), U64(0x0800000000000000), + U64(0x1000000000000000), U64(0x2000000000000000), U64(0x4000000000000000), U64(0x8000000000000000), + /* A8 to H8 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000) + }, + { /* BLACK */ + /* A1 to H1 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + /* A2 to H2 */ + U64(0x0000000000000001), U64(0x0000000000000002), U64(0x0000000000000004), U64(0x0000000000000008), + U64(0x0000000000000010), U64(0x0000000000000020), U64(0x0000000000000040), U64(0x0000000000000080), + /* A3 to H3 */ + U64(0x0000000000000100), U64(0x0000000000000200), U64(0x0000000000000400), U64(0x0000000000000800), + U64(0x0000000000001000), U64(0x0000000000002000), U64(0x0000000000004000), U64(0x0000000000008000), + /* A4 to H4 */ + U64(0x0000000000010000), U64(0x0000000000020000), U64(0x0000000000040000), U64(0x0000000000080000), + U64(0x0000000000100000), U64(0x0000000000200000), U64(0x0000000000400000), U64(0x0000000000800000), + /* A5 to H5 */ + U64(0x0000000001000000), U64(0x0000000002000000), U64(0x0000000004000000), U64(0x0000000008000000), + U64(0x0000000010000000), U64(0x0000000020000000), U64(0x0000000040000000), U64(0x0000000080000000), + /* A6 to H6 */ + U64(0x0000000100000000), U64(0x0000000200000000), U64(0x0000000400000000), U64(0x0000000800000000), + U64(0x0000001000000000), U64(0x0000002000000000), U64(0x0000004000000000), U64(0x0000008000000000), + /* A7 to H7 */ + U64(0x0000010000000000), U64(0x0000020000000000), U64(0x0000040000000000), U64(0x0000080000000000), + U64(0x0000100000000000), U64(0x0000200000000000), U64(0x0000400000000000), U64(0x0000800000000000), + /* A8 to H8 */ + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), + U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000), U64(0x0000000000000000) + } +}; + +/** + * For rook attacks along a row. Uses the 'occupied' status of the row (e.g. + * if there are pieces on the columns a, d, e, f, h , the bitmask will be + * (binary) 00111001) as the first index, and the position of the rook (0-7 + * for columns 1-8 (right to left on the mask)) as the second index. + * + * It returns a row mask appropriate for a rook on the 1st (0 index) row's + * attacks; note that the bit at the end of the attack ray will overlap the + * first blocking piece (a rook on d-column with rowblock mask 11010011 (note + * the 1 in the d-col indicates the rook itself) will get move mask 01101110 + * (note again the 0 on the d-column; the rook cannot move to itself)). + * + * Because the return is suitable for a rook on row-1 (0 index), it must be + * shifted left by 8*ROW(square) - for example, on the 8th row, the shift by + * 8*7 will put it in the MSBs of the uint64_t. + */ +uint64_t rowattacks[256][8] = { + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x00 */ + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x01 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x02 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x03 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x04 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x05 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x06 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x07 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x08 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x09 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x0f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x10 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x11 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x12 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x13 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x14 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x15 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x16 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x17 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x18 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x19 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x1f */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0x20 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0x21 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0x22 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0x23 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x24 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x25 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x26 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0x27 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x28 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x29 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0x2f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x30 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x31 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x32 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x33 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x34 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x35 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x36 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x37 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x38 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x39 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0x3f */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0x40 */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0x41 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0x42 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0x43 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x44 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x45 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x46 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0x47 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x48 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x49 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0x4f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x50 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x51 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x52 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x53 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x54 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x55 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x56 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x57 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x58 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x59 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0x5f */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0x60 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0x61 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0x62 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0x63 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x64 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x65 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x66 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0x67 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x68 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x69 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0x6f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x70 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x71 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x72 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x73 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x74 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x75 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x76 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x77 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x78 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x79 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0x7f */ + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x80 */ + { U64(0xfe), U64(0xfd), U64(0xfb), U64(0xf7), U64(0xef), U64(0xdf), U64(0xbf), U64(0x7f) }, /* 0x81 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x82 */ + { U64(0x02), U64(0xfd), U64(0xfa), U64(0xf6), U64(0xee), U64(0xde), U64(0xbe), U64(0x7e) }, /* 0x83 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x84 */ + { U64(0x06), U64(0x05), U64(0xfb), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x85 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x86 */ + { U64(0x02), U64(0x05), U64(0xfa), U64(0xf4), U64(0xec), U64(0xdc), U64(0xbc), U64(0x7c) }, /* 0x87 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x88 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0xf7), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x89 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0xf6), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0xf4), U64(0xe8), U64(0xd8), U64(0xb8), U64(0x78) }, /* 0x8f */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x90 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0xef), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x91 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x92 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0xee), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x93 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x94 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x95 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x96 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0xec), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x97 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x98 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x99 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9a */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9b */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9c */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9d */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9e */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0xe8), U64(0xd0), U64(0xb0), U64(0x70) }, /* 0x9f */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0xa0 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0xdf), U64(0xa0), U64(0x60) }, /* 0xa1 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0xa2 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0xde), U64(0xa0), U64(0x60) }, /* 0xa3 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa4 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa5 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa6 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0xdc), U64(0xa0), U64(0x60) }, /* 0xa7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xa8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xa9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xaa */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xab */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xac */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xad */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xae */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0xd8), U64(0xa0), U64(0x60) }, /* 0xaf */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb0 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb1 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb2 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb3 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb4 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb5 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb6 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xb9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xba */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbe */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0xd0), U64(0xa0), U64(0x60) }, /* 0xbf */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0xc0 */ + { U64(0x7e), U64(0x7d), U64(0x7b), U64(0x77), U64(0x6f), U64(0x5f), U64(0xbf), U64(0x40) }, /* 0xc1 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0xc2 */ + { U64(0x02), U64(0x7d), U64(0x7a), U64(0x76), U64(0x6e), U64(0x5e), U64(0xbe), U64(0x40) }, /* 0xc3 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc4 */ + { U64(0x06), U64(0x05), U64(0x7b), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc5 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc6 */ + { U64(0x02), U64(0x05), U64(0x7a), U64(0x74), U64(0x6c), U64(0x5c), U64(0xbc), U64(0x40) }, /* 0xc7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xc8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x77), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xc9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xca */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x76), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xce */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x74), U64(0x68), U64(0x58), U64(0xb8), U64(0x40) }, /* 0xcf */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd0 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x6f), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd1 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd2 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x6e), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd3 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd4 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd5 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd6 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x6c), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xd9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xda */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xde */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x68), U64(0x50), U64(0xb0), U64(0x40) }, /* 0xdf */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0xe0 */ + { U64(0x3e), U64(0x3d), U64(0x3b), U64(0x37), U64(0x2f), U64(0x5f), U64(0xa0), U64(0x40) }, /* 0xe1 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0xe2 */ + { U64(0x02), U64(0x3d), U64(0x3a), U64(0x36), U64(0x2e), U64(0x5e), U64(0xa0), U64(0x40) }, /* 0xe3 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe4 */ + { U64(0x06), U64(0x05), U64(0x3b), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe5 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe6 */ + { U64(0x02), U64(0x05), U64(0x3a), U64(0x34), U64(0x2c), U64(0x5c), U64(0xa0), U64(0x40) }, /* 0xe7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xe8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x37), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xe9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xea */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x36), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xeb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xec */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xed */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xee */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x34), U64(0x28), U64(0x58), U64(0xa0), U64(0x40) }, /* 0xef */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf0 */ + { U64(0x1e), U64(0x1d), U64(0x1b), U64(0x17), U64(0x2f), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf1 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf2 */ + { U64(0x02), U64(0x1d), U64(0x1a), U64(0x16), U64(0x2e), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf3 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf4 */ + { U64(0x06), U64(0x05), U64(0x1b), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf5 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf6 */ + { U64(0x02), U64(0x05), U64(0x1a), U64(0x14), U64(0x2c), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf7 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf8 */ + { U64(0x0e), U64(0x0d), U64(0x0b), U64(0x17), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xf9 */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfa */ + { U64(0x02), U64(0x0d), U64(0x0a), U64(0x16), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfb */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfc */ + { U64(0x06), U64(0x05), U64(0x0b), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfd */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) }, /* 0xfe */ + { U64(0x02), U64(0x05), U64(0x0a), U64(0x14), U64(0x28), U64(0x50), U64(0xa0), U64(0x40) } /* 0xff */ +}; + + +/**************************************************************************** + * For rook attacks along a column. Using the 'occupied' status of the column + * passed in from the rot90 bitboard, shifted to the 8 least-significant bits + * (a-column), returns a NON-ROTATED bitmask of attacks for the a-column. You + * will want to shift this result over by COL(square) bits to get it in the + * right place - think about the way the bitboard works; each row is a byte + * (major index, times 8), and each column is a bit (minor index, times 1). + * You will want to use whatever ROW the piece is on in a normal bitboard as + * the second index. + ****************************************************************************/ + +uint64_t colattacks[256][8] = { + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x00 */ + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x01 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x02 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x03 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x04 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x05 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x06 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x07 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x08 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x09 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x0f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x10 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x11 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x12 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x13 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x14 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x15 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x16 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x17 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x18 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x19 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x1f */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x20 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x21 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x22 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x23 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x24 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x25 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x26 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x27 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x28 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x29 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x2f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x30 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x31 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x32 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x33 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x34 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x35 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x36 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x37 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x38 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x39 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0x3f */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0x40 */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0x41 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0x42 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0x43 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x44 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x45 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x46 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0x47 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x48 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x49 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0x4f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x50 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x51 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x52 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x53 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x54 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x55 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x56 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x57 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x58 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x59 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0x5f */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x60 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x61 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x62 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x63 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x64 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x65 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x66 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x67 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x68 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x69 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x6f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x70 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x71 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x72 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x73 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x74 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x75 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x76 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x77 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x78 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x79 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0x7f */ + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x80 */ + { U64(0x0101010101010100), U64(0x0101010101010001), U64(0x0101010101000101), U64(0x0101010100010101), U64(0x0101010001010101), U64(0x0101000101010101), U64(0x0100010101010101), U64(0x0001010101010101) }, /* 0x81 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x82 */ + { U64(0x0000000000000100), U64(0x0101010101010001), U64(0x0101010101000100), U64(0x0101010100010100), U64(0x0101010001010100), U64(0x0101000101010100), U64(0x0100010101010100), U64(0x0001010101010100) }, /* 0x83 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x84 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0101010101000101), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x85 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x86 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0101010101000100), U64(0x0101010100010000), U64(0x0101010001010000), U64(0x0101000101010000), U64(0x0100010101010000), U64(0x0001010101010000) }, /* 0x87 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x88 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0101010100010101), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x89 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0101010100010100), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0101010100010000), U64(0x0101010001000000), U64(0x0101000101000000), U64(0x0100010101000000), U64(0x0001010101000000) }, /* 0x8f */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x90 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0101010001010101), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x91 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x92 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0101010001010100), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x93 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x94 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x95 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x96 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0101010001010000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x97 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x98 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x99 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9a */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9b */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9c */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9d */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9e */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0101010001000000), U64(0x0101000100000000), U64(0x0100010100000000), U64(0x0001010100000000) }, /* 0x9f */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa0 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0101000101010101), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa1 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa2 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0101000101010100), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0101000101010000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xa9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xaa */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xab */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xac */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xad */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xae */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0101000101000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xaf */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb0 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb1 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb2 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xb9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xba */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbe */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0101000100000000), U64(0x0100010000000000), U64(0x0001010000000000) }, /* 0xbf */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0xc0 */ + { U64(0x0001010101010100), U64(0x0001010101010001), U64(0x0001010101000101), U64(0x0001010100010101), U64(0x0001010001010101), U64(0x0001000101010101), U64(0x0100010101010101), U64(0x0001000000000000) }, /* 0xc1 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0xc2 */ + { U64(0x0000000000000100), U64(0x0001010101010001), U64(0x0001010101000100), U64(0x0001010100010100), U64(0x0001010001010100), U64(0x0001000101010100), U64(0x0100010101010100), U64(0x0001000000000000) }, /* 0xc3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0001010101000101), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0001010101000100), U64(0x0001010100010000), U64(0x0001010001010000), U64(0x0001000101010000), U64(0x0100010101010000), U64(0x0001000000000000) }, /* 0xc7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xc8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0001010100010101), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xc9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xca */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0001010100010100), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xce */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0001010100010000), U64(0x0001010001000000), U64(0x0001000101000000), U64(0x0100010101000000), U64(0x0001000000000000) }, /* 0xcf */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd0 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0001010001010101), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd1 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd2 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0001010001010100), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0001010001010000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xd9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xda */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xde */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0001010001000000), U64(0x0001000100000000), U64(0x0100010100000000), U64(0x0001000000000000) }, /* 0xdf */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe0 */ + { U64(0x0000010101010100), U64(0x0000010101010001), U64(0x0000010101000101), U64(0x0000010100010101), U64(0x0000010001010101), U64(0x0001000101010101), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe1 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe2 */ + { U64(0x0000000000000100), U64(0x0000010101010001), U64(0x0000010101000100), U64(0x0000010100010100), U64(0x0000010001010100), U64(0x0001000101010100), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000010101000101), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000010101000100), U64(0x0000010100010000), U64(0x0000010001010000), U64(0x0001000101010000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000010100010101), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xe9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xea */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000010100010100), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xeb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xec */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xed */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xee */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000010100010000), U64(0x0000010001000000), U64(0x0001000101000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xef */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf0 */ + { U64(0x0000000101010100), U64(0x0000000101010001), U64(0x0000000101000101), U64(0x0000000100010101), U64(0x0000010001010101), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf1 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf2 */ + { U64(0x0000000000000100), U64(0x0000000101010001), U64(0x0000000101000100), U64(0x0000000100010100), U64(0x0000010001010100), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf3 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf4 */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000101000101), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf5 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf6 */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000101000100), U64(0x0000000100010000), U64(0x0000010001010000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf7 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf8 */ + { U64(0x0000000001010100), U64(0x0000000001010001), U64(0x0000000001000101), U64(0x0000000100010101), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xf9 */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfa */ + { U64(0x0000000000000100), U64(0x0000000001010001), U64(0x0000000001000100), U64(0x0000000100010100), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfb */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfc */ + { U64(0x0000000000010100), U64(0x0000000000010001), U64(0x0000000001000101), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfd */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) }, /* 0xfe */ + { U64(0x0000000000000100), U64(0x0000000000010001), U64(0x0000000001000100), U64(0x0000000100010000), U64(0x0000010001000000), U64(0x0001000100000000), U64(0x0100010000000000), U64(0x0001000000000000) } /* 0xff */ +}; + +/**************************************************************************** + * For bishop attacks along a diagonal parallel to a8-h1 (rot45). This is + * kind of special, because each diagonal is a different length you need to + * think carefully about how the shifting works. This will give the move mask + * for a bishop on the a8-h1 diagonal (the longest one) in NON-ROTATED format. + * + * Think carefully about how you want to shift. When you get the result back, + * you will want to shift it forward or backward exactly 8 times N, where N is + * the number of diagonals the one your bishop is on is away from a8-h1 (a + * bishop on a8-h1 will be shifted 0. For a bishop on a7-g1 you will shift + * RIGHT by 8 bits; a6-f1 RIGHT by 16 bits, a1-a1 RIGHT by 56 bits. On the + * other hand, for a bishop on b8-h2 you will shift LEFT 8 bits, c8-h3 LEFT by + * 16 bits, h8-h8 LEFT by 56 bits. + * + * The other important thing to consider is how you go into the table. Because + * the diagonals are not all the same length, you need to aligh one edge of + * your diagonal to either the 0 index OR the other edge to the 7 index. The + * way you want to do it is if your diagonal touches the left side of the + * board (aX-x1), shift so the square on the a-file is in the 0th index; if + * your diagonal touches the right side (x8-hX), shift so the square on the + * h-file will be in the 7th index. Either way, this means there will be some + * garbage not related to your diagonal in the remaining slots - it will + * affect the resulting move mask, but when you bitshift it (according to the + * previous paragraph) the nonrelevant squares in the mask will overflow out. + * + * To get a piece's position on the diagonal (the second index in the array), + * we consider alignment described above, and realize that because essentially + * we're projecting the diagonal down to the first (0-index) row, plus some + * garbage, the position index is simply the column the piece is on! + ****************************************************************************/ + +/* Use these to get the number used to index into the next few arrays. Indexed + * by square (A1 0, H8 63) for both rotation directions. Use the result from + * these arrays as an index into the "shiftamount" arrays following. */ +int rot45diagindex[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 1, 2, 3, 4, 5, 6, 7, 8, + 2, 3, 4, 5, 6, 7, 8, 9, + 3, 4, 5, 6, 7, 8, 9, 10, + 4, 5, 6, 7, 8, 9, 10, 11, + 5, 6, 7, 8, 9, 10, 11, 12, + 6, 7, 8, 9, 10, 11, 12, 13, + 7, 8, 9, 10, 11, 12, 13, 14 +}; +int rot315diagindex[64] = { + 7, 6, 5, 4, 3, 2, 1, 0, + 8, 7, 6, 5, 4, 3, 2, 1, + 9, 8, 7, 6, 5, 4, 3, 2, + 10, 9, 8, 7, 6, 5, 4, 3, + 11, 10, 9, 8, 7, 6, 5, 4, + 12, 11, 10, 9, 8, 7, 6, 5, + 13, 12, 11, 10, 9, 8, 7, 6, + 14, 13, 12, 11, 10, 9, 8, 7 +}; + +/* The amount you want to shift the rotated bitboard by (then mask with 0xFF) + * to get the correct index. Index into this with the diagonal's number. For + * rot45, you want to align >7 diagonals against the 7th index, with garbage + * in the bottom, or <7 diagonals against the 0th index, with garbage in the + * top, so that when shifting the garbage goes out of the top/bottom of the + * board. For rot315 it's the opposite case - >7 diags get aligned to the 0th + * index, and <7 diags aligned to the 7th index; this way, the garbage will + * still go out the top/bottom of the board. For the lowest diagonals, this + * means we might have to shift backwards. (note: The numbers for aligning to + * the top bits are generated by "extending" the row backwards.) */ +int rot45index_shiftamountright[15] = { 0, 1, 3, 6, 10, 15, 21, 28, 35, 41, 46, 50, 53, 55, 56 }; +int rot315index_shiftamountright[15] = { 0, 0, 0, 2, 7, 13, 20, 28, 36, 43, 49, 54, 58, 61, 63 }; +int rot315index_shiftamountleft[15] = { 7, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* The amount you want to shift the result by. Use the number of the diagonal + * (0 for a1-a1, 7 for a8-h1, 14 for h8-h8) to index into these. */ +int rotresult_shiftamountleft[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 32, 40, 48, 56 }; +int rotresult_shiftamountright[15] = { 56, 48, 40, 32, 24, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0 }; + +uint64_t rot45attacks[256][8] = { + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x00 */ + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x01 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x02 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x03 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x04 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x05 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x06 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x07 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x08 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x09 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x0f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x10 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x11 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x12 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x13 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x14 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x15 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x16 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x17 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x18 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x19 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x1f */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x20 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x21 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x22 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x23 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x24 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x25 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x26 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x27 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x28 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x29 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x2f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x30 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x31 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x32 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x33 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x34 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x35 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x36 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x37 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x38 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x39 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0x3f */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0x40 */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0x41 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0x42 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0x43 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x44 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x45 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x46 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0x47 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x48 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x49 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0x4f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x50 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x51 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x52 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x53 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x54 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x55 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x56 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x57 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x58 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x59 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0x5f */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x60 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x61 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x62 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x63 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x64 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x65 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x66 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x67 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x68 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x69 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x6f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x70 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x71 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x72 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x73 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x74 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x75 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x76 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x77 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x78 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x79 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0x7f */ + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x80 */ + { U64(0x0002040810204080), U64(0x0100040810204080), U64(0x0102000810204080), U64(0x0102040010204080), U64(0x0102040800204080), U64(0x0102040810004080), U64(0x0102040810200080), U64(0x0102040810204000) }, /* 0x81 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x82 */ + { U64(0x0002000000000000), U64(0x0100040810204080), U64(0x0002000810204080), U64(0x0002040010204080), U64(0x0002040800204080), U64(0x0002040810004080), U64(0x0002040810200080), U64(0x0002040810204000) }, /* 0x83 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x84 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x85 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x86 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204080), U64(0x0000040010204080), U64(0x0000040800204080), U64(0x0000040810004080), U64(0x0000040810200080), U64(0x0000040810204000) }, /* 0x87 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x88 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x89 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204080), U64(0x0000000800204080), U64(0x0000000810004080), U64(0x0000000810200080), U64(0x0000000810204000) }, /* 0x8f */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x90 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x91 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x92 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x93 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x94 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x95 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x96 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x97 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x98 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x99 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9a */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9b */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9c */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9d */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9e */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204080), U64(0x0000000010004080), U64(0x0000000010200080), U64(0x0000000010204000) }, /* 0x9f */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa0 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa1 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa2 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xa9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xaa */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xab */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xac */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xad */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xae */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xaf */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb0 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb1 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb2 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xb9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xba */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbe */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004080), U64(0x0000000000200080), U64(0x0000000000204000) }, /* 0xbf */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0xc0 */ + { U64(0x0002040810204000), U64(0x0100040810204000), U64(0x0102000810204000), U64(0x0102040010204000), U64(0x0102040800204000), U64(0x0102040810004000), U64(0x0102040810200080), U64(0x0000000000004000) }, /* 0xc1 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0xc2 */ + { U64(0x0002000000000000), U64(0x0100040810204000), U64(0x0002000810204000), U64(0x0002040010204000), U64(0x0002040800204000), U64(0x0002040810004000), U64(0x0002040810200080), U64(0x0000000000004000) }, /* 0xc3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810204000), U64(0x0000040010204000), U64(0x0000040800204000), U64(0x0000040810004000), U64(0x0000040810200080), U64(0x0000000000004000) }, /* 0xc7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xc8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xc9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xca */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xce */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010204000), U64(0x0000000800204000), U64(0x0000000810004000), U64(0x0000000810200080), U64(0x0000000000004000) }, /* 0xcf */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd0 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd1 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd2 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xd9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xda */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xde */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800204000), U64(0x0000000010004000), U64(0x0000000010200080), U64(0x0000000000004000) }, /* 0xdf */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe0 */ + { U64(0x0002040810200000), U64(0x0100040810200000), U64(0x0102000810200000), U64(0x0102040010200000), U64(0x0102040800200000), U64(0x0102040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe1 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe2 */ + { U64(0x0002000000000000), U64(0x0100040810200000), U64(0x0002000810200000), U64(0x0002040010200000), U64(0x0002040800200000), U64(0x0002040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810200000), U64(0x0000040010200000), U64(0x0000040800200000), U64(0x0000040810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xe9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xea */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xeb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xec */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xed */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xee */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010200000), U64(0x0000000800200000), U64(0x0000000810004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xef */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf0 */ + { U64(0x0002040810000000), U64(0x0100040810000000), U64(0x0102000810000000), U64(0x0102040010000000), U64(0x0102040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf1 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf2 */ + { U64(0x0002000000000000), U64(0x0100040810000000), U64(0x0002000810000000), U64(0x0002040010000000), U64(0x0002040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf3 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf4 */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf5 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf6 */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000810000000), U64(0x0000040010000000), U64(0x0000040800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf7 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf8 */ + { U64(0x0002040800000000), U64(0x0100040800000000), U64(0x0102000800000000), U64(0x0102040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xf9 */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfa */ + { U64(0x0002000000000000), U64(0x0100040800000000), U64(0x0002000800000000), U64(0x0002040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfb */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfc */ + { U64(0x0002040000000000), U64(0x0100040000000000), U64(0x0102000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfd */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) }, /* 0xfe */ + { U64(0x0002000000000000), U64(0x0100040000000000), U64(0x0002000800000000), U64(0x0000040010000000), U64(0x0000000800200000), U64(0x0000000010004000), U64(0x0000000000200080), U64(0x0000000000004000) } /* 0xff */ +}; + +uint64_t rot315attacks[256][8] = { + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x00 */ + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x01 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x02 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x03 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x04 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x05 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x06 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x07 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x08 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x09 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x0f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x10 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x11 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x12 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x13 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x14 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x15 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x16 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x17 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x18 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x19 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x1f */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x20 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x21 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x22 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x23 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x24 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x25 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x26 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x27 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x28 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x29 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x2f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x30 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x31 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x32 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x33 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x34 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x35 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x36 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x37 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x38 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x39 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0x3f */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0x40 */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0x41 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0x42 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0x43 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x44 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x45 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x46 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0x47 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x48 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x49 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0x4f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x50 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x51 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x52 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x53 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x54 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x55 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x56 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x57 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x58 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x59 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0x5f */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x60 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x61 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x62 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x63 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x64 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x65 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x66 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x67 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x68 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x69 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x6f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x70 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x71 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x72 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x73 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x74 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x75 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x76 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x77 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x78 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x79 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0x7f */ + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x80 */ + { U64(0x8040201008040200), U64(0x8040201008040001), U64(0x8040201008000201), U64(0x8040201000040201), U64(0x8040200008040201), U64(0x8040001008040201), U64(0x8000201008040201), U64(0x0040201008040201) }, /* 0x81 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x82 */ + { U64(0x0000000000000200), U64(0x8040201008040001), U64(0x8040201008000200), U64(0x8040201000040200), U64(0x8040200008040200), U64(0x8040001008040200), U64(0x8000201008040200), U64(0x0040201008040200) }, /* 0x83 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x84 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x8040201008000201), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x85 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x86 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x8040201008000200), U64(0x8040201000040000), U64(0x8040200008040000), U64(0x8040001008040000), U64(0x8000201008040000), U64(0x0040201008040000) }, /* 0x87 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x88 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x8040201000040201), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x89 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x8040201000040200), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x8040201000040000), U64(0x8040200008000000), U64(0x8040001008000000), U64(0x8000201008000000), U64(0x0040201008000000) }, /* 0x8f */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x90 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x8040200008040201), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x91 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x92 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x8040200008040200), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x93 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x94 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x95 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x96 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x8040200008040000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x97 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x98 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x99 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9a */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9b */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9c */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9d */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9e */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x8040200008000000), U64(0x8040001000000000), U64(0x8000201000000000), U64(0x0040201000000000) }, /* 0x9f */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa0 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x8040001008040201), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa1 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa2 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x8040001008040200), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x8040001008040000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xa9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xaa */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xab */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xac */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xad */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xae */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x8040001008000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xaf */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb0 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb1 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb2 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xb9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xba */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbe */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x8040001000000000), U64(0x8000200000000000), U64(0x0040200000000000) }, /* 0xbf */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0xc0 */ + { U64(0x0040201008040200), U64(0x0040201008040001), U64(0x0040201008000201), U64(0x0040201000040201), U64(0x0040200008040201), U64(0x0040001008040201), U64(0x8000201008040201), U64(0x0040000000000000) }, /* 0xc1 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0xc2 */ + { U64(0x0000000000000200), U64(0x0040201008040001), U64(0x0040201008000200), U64(0x0040201000040200), U64(0x0040200008040200), U64(0x0040001008040200), U64(0x8000201008040200), U64(0x0040000000000000) }, /* 0xc3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0040201008000201), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0040201008000200), U64(0x0040201000040000), U64(0x0040200008040000), U64(0x0040001008040000), U64(0x8000201008040000), U64(0x0040000000000000) }, /* 0xc7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xc8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0040201000040201), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xc9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xca */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0040201000040200), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xce */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0040201000040000), U64(0x0040200008000000), U64(0x0040001008000000), U64(0x8000201008000000), U64(0x0040000000000000) }, /* 0xcf */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd0 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0040200008040201), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd1 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd2 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0040200008040200), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0040200008040000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xd9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xda */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xde */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0040200008000000), U64(0x0040001000000000), U64(0x8000201000000000), U64(0x0040000000000000) }, /* 0xdf */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe0 */ + { U64(0x0000201008040200), U64(0x0000201008040001), U64(0x0000201008000201), U64(0x0000201000040201), U64(0x0000200008040201), U64(0x0040001008040201), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe1 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe2 */ + { U64(0x0000000000000200), U64(0x0000201008040001), U64(0x0000201008000200), U64(0x0000201000040200), U64(0x0000200008040200), U64(0x0040001008040200), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000201008000201), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000201008000200), U64(0x0000201000040000), U64(0x0000200008040000), U64(0x0040001008040000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000201000040201), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xe9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xea */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000201000040200), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xeb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xec */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xed */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xee */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000201000040000), U64(0x0000200008000000), U64(0x0040001008000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xef */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf0 */ + { U64(0x0000001008040200), U64(0x0000001008040001), U64(0x0000001008000201), U64(0x0000001000040201), U64(0x0000200008040201), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf1 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf2 */ + { U64(0x0000000000000200), U64(0x0000001008040001), U64(0x0000001008000200), U64(0x0000001000040200), U64(0x0000200008040200), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf3 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf4 */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000001008000201), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf5 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf6 */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000001008000200), U64(0x0000001000040000), U64(0x0000200008040000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf7 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf8 */ + { U64(0x0000000008040200), U64(0x0000000008040001), U64(0x0000000008000201), U64(0x0000001000040201), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xf9 */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfa */ + { U64(0x0000000000000200), U64(0x0000000008040001), U64(0x0000000008000200), U64(0x0000001000040200), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfb */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfc */ + { U64(0x0000000000040200), U64(0x0000000000040001), U64(0x0000000008000201), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfd */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) }, /* 0xfe */ + { U64(0x0000000000000200), U64(0x0000000000040001), U64(0x0000000008000200), U64(0x0000001000040000), U64(0x0000200008000000), U64(0x0040001000000000), U64(0x8000200000000000), U64(0x0040000000000000) } /* 0xff */ +}; +/**************************************************************************** + * board.c - rotated bitboard library; move generation and board state + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* For FEN conversion, and move->string conversion */ +char *piecename[2][6] = { + { "P", "N", "B", "R", "Q", "K" }, + { "p", "n", "b", "r", "q", "k" } +}; +/* Converts int to string. Better than using malloc for 3-length strings. */ +char *squarename[64] = { + "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", + "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", + "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", + "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", + "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", + "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", + "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", + "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8" +}; +#ifndef BB_SHIFTFLIP /* see board.h */ +/* Get a bitboard with only one bit set, on a specified square */ +bitboard_t bb_square[64] = { + BB(0x0000000000000001), BB(0x0000000000000002), BB(0x0000000000000004), BB(0x0000000000000008), + BB(0x0000000000000010), BB(0x0000000000000020), BB(0x0000000000000040), BB(0x0000000000000080), + BB(0x0000000000000100), BB(0x0000000000000200), BB(0x0000000000000400), BB(0x0000000000000800), + BB(0x0000000000001000), BB(0x0000000000002000), BB(0x0000000000004000), BB(0x0000000000008000), + BB(0x0000000000010000), BB(0x0000000000020000), BB(0x0000000000040000), BB(0x0000000000080000), + BB(0x0000000000100000), BB(0x0000000000200000), BB(0x0000000000400000), BB(0x0000000000800000), + BB(0x0000000001000000), BB(0x0000000002000000), BB(0x0000000004000000), BB(0x0000000008000000), + BB(0x0000000010000000), BB(0x0000000020000000), BB(0x0000000040000000), BB(0x0000000080000000), + BB(0x0000000100000000), BB(0x0000000200000000), BB(0x0000000400000000), BB(0x0000000800000000), + BB(0x0000001000000000), BB(0x0000002000000000), BB(0x0000004000000000), BB(0x0000008000000000), + BB(0x0000010000000000), BB(0x0000020000000000), BB(0x0000040000000000), BB(0x0000080000000000), + BB(0x0000100000000000), BB(0x0000200000000000), BB(0x0000400000000000), BB(0x0000800000000000), + BB(0x0001000000000000), BB(0x0002000000000000), BB(0x0004000000000000), BB(0x0008000000000000), + BB(0x0010000000000000), BB(0x0020000000000000), BB(0x0040000000000000), BB(0x0080000000000000), + BB(0x0100000000000000), BB(0x0200000000000000), BB(0x0400000000000000), BB(0x0800000000000000), + BB(0x1000000000000000), BB(0x2000000000000000), BB(0x4000000000000000), BB(0x8000000000000000), +}; +/* The bitwise negation of SINGLESQUARE(x) */ +bitboard_t bb_allexcept[64] = { + BB(0xfffffffffffffffe), BB(0xfffffffffffffffd), BB(0xfffffffffffffffb), BB(0xfffffffffffffff7), + BB(0xffffffffffffffef), BB(0xffffffffffffffdf), BB(0xffffffffffffffbf), BB(0xffffffffffffff7f), + BB(0xfffffffffffffeff), BB(0xfffffffffffffdff), BB(0xfffffffffffffbff), BB(0xfffffffffffff7ff), + BB(0xffffffffffffefff), BB(0xffffffffffffdfff), BB(0xffffffffffffbfff), BB(0xffffffffffff7fff), + BB(0xfffffffffffeffff), BB(0xfffffffffffdffff), BB(0xfffffffffffbffff), BB(0xfffffffffff7ffff), + BB(0xffffffffffefffff), BB(0xffffffffffdfffff), BB(0xffffffffffbfffff), BB(0xffffffffff7fffff), + BB(0xfffffffffeffffff), BB(0xfffffffffdffffff), BB(0xfffffffffbffffff), BB(0xfffffffff7ffffff), + BB(0xffffffffefffffff), BB(0xffffffffdfffffff), BB(0xffffffffbfffffff), BB(0xffffffff7fffffff), + BB(0xfffffffeffffffff), BB(0xfffffffdffffffff), BB(0xfffffffbffffffff), BB(0xfffffff7ffffffff), + BB(0xffffffefffffffff), BB(0xffffffdfffffffff), BB(0xffffffbfffffffff), BB(0xffffff7fffffffff), + BB(0xfffffeffffffffff), BB(0xfffffdffffffffff), BB(0xfffffbffffffffff), BB(0xfffff7ffffffffff), + BB(0xffffefffffffffff), BB(0xffffdfffffffffff), BB(0xffffbfffffffffff), BB(0xffff7fffffffffff), + BB(0xfffeffffffffffff), BB(0xfffdffffffffffff), BB(0xfffbffffffffffff), BB(0xfff7ffffffffffff), + BB(0xffefffffffffffff), BB(0xffdfffffffffffff), BB(0xffbfffffffffffff), BB(0xff7fffffffffffff), + BB(0xfeffffffffffffff), BB(0xfdffffffffffffff), BB(0xfbffffffffffffff), BB(0xf7ffffffffffffff), + BB(0xefffffffffffffff), BB(0xdfffffffffffffff), BB(0xbfffffffffffffff), BB(0x7fffffffffffffff), +}; +#endif + +/* Which squares must be unoccupied for COLOR (1st) to castle on SIDE (2nd) */ +static bitboard_t castle_clearsquares[2][2] = { + /* queenside kingside */ + { BB(0x000000000000000e), BB(0x0000000000000060) }, /* white */ + { BB(0x0e00000000000000), BB(0x6000000000000000) } /* black */ +}; +/* Which squares must be unthreatened for COLOR to castle on SIDE */ +static bitboard_t castle_safesquares[2][2] = { + /* queenside kingside */ + { BB(0x000000000000001c), BB(0x0000000000000070) }, /* white */ + { BB(0x1c00000000000000), BB(0x7000000000000000) } /* black */ +}; +/* A mask for the cols adjacent to a given col - for pawn captures, AND with a + * row-mask for the rank you need the pawns to be on */ +bitboard_t bb_adjacentcols[8] = { + BB_FILEB, + BB_FILEA | BB_FILEC, + BB_FILEB | BB_FILED, + BB_FILEC | BB_FILEE, + BB_FILED | BB_FILEF, + BB_FILEE | BB_FILEG, + BB_FILEF | BB_FILEH, + BB_FILEG +}; +/* used for determining when a pawn is passed */ +bitboard_t bb_passedpawnmask[2][64] = { + /* WHITE */ + { + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0303030303030000), BB(0x0707070707070000), BB(0x0e0e0e0e0e0e0000), BB(0x1c1c1c1c1c1c0000), BB(0x3838383838380000), BB(0x7070707070700000), BB(0xe0e0e0e0e0e00000), BB(0xc0c0c0c0c0c00000), + BB(0x0303030303000000), BB(0x0707070707000000), BB(0x0e0e0e0e0e000000), BB(0x1c1c1c1c1c000000), BB(0x3838383838000000), BB(0x7070707070000000), BB(0xe0e0e0e0e0000000), BB(0xc0c0c0c0c0000000), + BB(0x0303030300000000), BB(0x0707070700000000), BB(0x0e0e0e0e00000000), BB(0x1c1c1c1c00000000), BB(0x3838383800000000), BB(0x7070707000000000), BB(0xe0e0e0e000000000), BB(0xc0c0c0c000000000), + BB(0x0303030000000000), BB(0x0707070000000000), BB(0x0e0e0e0000000000), BB(0x1c1c1c0000000000), BB(0x3838380000000000), BB(0x7070700000000000), BB(0xe0e0e00000000000), BB(0xc0c0c00000000000), + BB(0x0303000000000000), BB(0x0707000000000000), BB(0x0e0e000000000000), BB(0x1c1c000000000000), BB(0x3838000000000000), BB(0x7070000000000000), BB(0xe0e0000000000000), BB(0xc0c0000000000000), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000) + }, + /* BLACK */ + { + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), + BB(0x0000000000000303), BB(0x0000000000000707), BB(0x0000000000000e0e), BB(0x0000000000001c1c), BB(0x0000000000003838), BB(0x0000000000007070), BB(0x000000000000e0e0), BB(0x000000000000c0c0), + BB(0x0000000000030303), BB(0x0000000000070707), BB(0x00000000000e0e0e), BB(0x00000000001c1c1c), BB(0x0000000000383838), BB(0x0000000000707070), BB(0x0000000000e0e0e0), BB(0x0000000000c0c0c0), + BB(0x0000000003030303), BB(0x0000000007070707), BB(0x000000000e0e0e0e), BB(0x000000001c1c1c1c), BB(0x0000000038383838), BB(0x0000000070707070), BB(0x00000000e0e0e0e0), BB(0x00000000c0c0c0c0), + BB(0x0000000303030303), BB(0x0000000707070707), BB(0x0000000e0e0e0e0e), BB(0x0000001c1c1c1c1c), BB(0x0000003838383838), BB(0x0000007070707070), BB(0x000000e0e0e0e0e0), BB(0x000000c0c0c0c0c0), + BB(0x0000030303030303), BB(0x0000070707070707), BB(0x00000e0e0e0e0e0e), BB(0x00001c1c1c1c1c1c), BB(0x0000383838383838), BB(0x0000707070707070), BB(0x0000e0e0e0e0e0e0), BB(0x0000c0c0c0c0c0c0), + BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000), BB(0x0000000000000000) + } +}; + +/* Rotation translation from normal-oriented square indices to square indices + * suitable for setting bits on board_t->occupied{90,45,315}. Note that we + * don't use these for move generation at all, just for setting/clearing bits + * on the occupied boards. */ +#define ROT90SQUAREINDEX(s) rot90squareindex[s] /*(SQUARE(ROW(s),COL(s))) - slower*/ +static int rot90squareindex[64] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 1, 9, 17, 25, 33, 41, 49, 57, + 2, 10, 18, 26, 34, 42, 50, 58, + 3, 11, 19, 27, 35, 43, 51, 59, + 4, 12, 20, 28, 36, 44, 52, 60, + 5, 13, 21, 29, 37, 45, 53, 61, + 6, 14, 22, 30, 38, 46, 54, 62, + 7, 15, 23, 31, 39, 47, 55, 63 +}; +#define ROT45SQUAREINDEX(s) rot45squareindex[s] +static int rot45squareindex[64] = { + 0, 2, 5, 9, 14, 20, 27, 35, + 1, 4, 8, 13, 19, 26, 34, 42, + 3, 7, 12, 18, 25, 33, 41, 48, + 6, 11, 17, 24, 32, 40, 47, 53, + 10, 16, 23, 31, 39, 46, 52, 57, + 15, 22, 30, 38, 45, 51, 56, 60, + 21, 29, 37, 44, 50, 55, 59, 62, + 28, 36, 43, 49, 54, 58, 61, 63 +}; +#define ROT315SQUAREINDEX(s) rot315squareindex[s] +static int rot315squareindex[64] = { + 28, 21, 15, 10, 6, 3, 1, 0, + 36, 29, 22, 16, 11, 7, 4, 2, + 43, 37, 30, 23, 17, 12, 8, 5, + 49, 44, 38, 31, 24, 18, 13, 9, + 54, 50, 45, 39, 32, 25, 19, 14, + 58, 55, 51, 46, 40, 33, 26, 20, + 61, 59, 56, 52, 47, 41, 34, 27, + 63, 62, 60, 57, 53, 48, 42, 35, +}; + +/* for material count */ +extern int16_t eval_piecevalue[6]; + + + +#define ZOBRIST_DEFAULT_HASH 0 +/* Table of random numbers used to generate the zobrist hash. The indices are + * first the color (WHITE/BLACK), then the piece type (PAWN-KING), then the + * square the piece is on (A1-H8) */ +zobrist_t zobrist_piece[2][6][64]; +/* Whose move is it (WHITE/BLACK)? The value present if white has the move. */ +zobrist_t zobrist_tomove; +/* Which square (A1-H8) is the enpassant square? If enpassant is not possible, + * use the key at index 0. */ +zobrist_t zobrist_ep[64]; +/* Can (WHITE/BLACK, first) castle on the (KINGSIDE/QUEENSIDE, second)? If so, + * the value here is xored into the hash. */ +zobrist_t zobrist_castle[2][2]; +/* Have the arrays been initialized? If you reinitialize them in the middle of + * play, the keys will get screwed up. */ +char zobrist_initialized = 0; + +/** + * Initialize the zobrist tables. + */ +void init_zobrist() +{ + int i, j, k; + + /* just in case... */ + if (zobrist_initialized) + { + return; + } + + /* Init the piece position array */ + for (i = 0; i < 2; i++) + { + for (j = 0; j < 6; j++) + { + for (k = 0; k < 64; k++) + { + zobrist_piece[i][j][k] = (zobrist_t)rand64(); + } + } + } + + /* Init the whose-move-is-it value */ + zobrist_tomove = (zobrist_t)rand64(); + + /* Init the enpassant square array */ + for (i = 0; i < 64; i++) + { + zobrist_ep[i] = (zobrist_t)rand64(); + } + + /* Init the castling rights array */ + zobrist_castle[0][0] = (zobrist_t)rand64(); + zobrist_castle[0][1] = (zobrist_t)rand64(); + zobrist_castle[1][0] = (zobrist_t)rand64(); + zobrist_castle[1][1] = (zobrist_t)rand64(); + + zobrist_initialized = 1; + return; +} + +/** + * (Re)generate the zobrist hash for a board, store it in board->hash + * This shouldn't be used every time you change the zobrist, only when + * initializing the board. + */ +void zobrist_gen(board_t *board) +{ + unsigned char color; + piece_t piece; + square_t square; + + int i, j; + bitboard_t pos; + zobrist_t hash = ZOBRIST_DEFAULT_HASH; + + if (board == NULL) + { + return; + } + if (!zobrist_initialized) + { + init_zobrist(); + } + + /* XOR in the zobrist for each piece on the board */ + for (color = 0; color < 2; color++) + { + for (piece = 0; piece < 6; piece++) + { + pos = board->pos[color][piece]; + while (pos) + { + /* Find the first bit */ + square = BITSCAN(pos); + /* throw in the hash */ + hash ^= zobrist_piece[color][piece][square]; + /* and clear the bit */ + pos &= BB_ALLEXCEPT(square); + } + } + } + /* Have the hash reflect special conditions on the board */ + /* En passant */ + hash ^= zobrist_ep[board->ep]; + /* Castling rights */ + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (board->castle[i][j]) + { + hash ^= zobrist_castle[i][j]; + } + } + } + /* Who has the move */ + if (board->tomove == WHITE) + { + hash ^= zobrist_tomove; + } + + board->hash = hash; + return; +} + +/**************************************************************************** + * BITBOARD FUNCTIONS + ****************************************************************************/ +static void board_addmoves_pawn(board_t *, square_t, unsigned char, movelist_t *); +static void board_addmoves_ep(board_t *, unsigned char, movelist_t *); +static void board_addmoves_king(board_t *, square_t, unsigned char, movelist_t *); +static void board_addmoves(board_t *, square_t, piece_t, unsigned char, movelist_t *); + +static void board_addcaptures_pawn(board_t *, square_t, unsigned char, movelist_t *); +static void board_addcaptures_king(board_t *, square_t, unsigned char, movelist_t *); +static void board_addcaptures(board_t *, square_t, piece_t, unsigned char, movelist_t *); +static void board_togglepiece(board_t *, square_t, unsigned char, piece_t); +static void board_regeneratethreatened(board_t *); + +/** + * Generate a fresh board with the default initial starting position. + */ +board_t *board_init() +{ + board_t *board = malloc(sizeof(board_t)); + affirm_msg(board, "Couldn't allocate board"); + + board->pos[WHITE][PAWN] = BB_RANK2; + board->pos[WHITE][KNIGHT] = BB_SQUARE(B1) | BB_SQUARE(G1); + board->pos[WHITE][BISHOP] = BB_SQUARE(C1) | BB_SQUARE(F1); + board->pos[WHITE][ROOK] = BB_SQUARE(A1) | BB_SQUARE(H1); + board->pos[WHITE][QUEEN] = BB_SQUARE(D1); + board->pos[WHITE][KING] = BB_SQUARE(E1); + board->pos[BLACK][PAWN] = BB_RANK7; + board->pos[BLACK][KNIGHT] = BB_SQUARE(B8) | BB_SQUARE(G8); + board->pos[BLACK][BISHOP] = BB_SQUARE(C8) | BB_SQUARE(F8); + board->pos[BLACK][ROOK] = BB_SQUARE(A8) | BB_SQUARE(H8); + board->pos[BLACK][QUEEN] = BB_SQUARE(D8); + board->pos[BLACK][KING] = BB_SQUARE(E8); + + board->piecesofcolor[WHITE] = BB_RANK1 | BB_RANK2; + board->piecesofcolor[BLACK] = BB_RANK8 | BB_RANK7; + + board->attackedby[WHITE] = BB_RANK3 | BB_RANK2 | (BB_RANK1 ^ BB_SQUARE(A1) ^ BB_SQUARE(H1)); + board->attackedby[BLACK] = BB_RANK6 | BB_RANK7 | (BB_RANK8 ^ BB_SQUARE(A8) ^ BB_SQUARE(H8)); + + board->occupied = BB_RANK1 | BB_RANK2 | BB_RANK7 | BB_RANK8; + board->occupied90 = BB_FILEA | BB_FILEB | BB_FILEG | BB_FILEH; + /* These ugly numbers, in contrast to the beautifully simple code + * above, are in fact correct. Check with ./bbtools/rotvisualizer */ + board->occupied45 = BB(0xecc61c3c3c386337); + board->occupied315 = BB(0xfb31861c38618cdf); + + board->ep = 0; + board->castle[WHITE][QUEENSIDE] = 1; + board->castle[WHITE][KINGSIDE] = 1; + board->castle[BLACK][QUEENSIDE] = 1; + board->castle[BLACK][KINGSIDE] = 1; + board->hascastled[WHITE] = 0; + board->hascastled[BLACK] = 0; + board->tomove = WHITE; + board->halfmoves = 0; + board->moves = 0; + board->reps = 0; + + board->material[WHITE] = (8 * eval_piecevalue[PAWN]) + + (2 * eval_piecevalue[KNIGHT]) + + (2 * eval_piecevalue[BISHOP]) + + (2 * eval_piecevalue[ROOK]) + + (eval_piecevalue[QUEEN]) + + (eval_piecevalue[KING]); + board->material[BLACK] = board->material[WHITE]; + + zobrist_gen(board); + + return board; +} + +/** + * Free all memory associated with a board_t. + */ +void board_destroy(board_t *board) +{ + if (board) + { + free(board); + } +} + +/** + * Generates a FEN string for the given position. Free it yourself when you're + * done with it. This function makes no effort to be fast; you shouldn't be + * using it during the search process anyway. + */ +#define FEN_MAX_LENGTH 85 +char *board_fen(board_t *board) +{ + char *fen; + int row, col; + char emptysquares[] = "0"; /* counts consecutive empty squares */ + char halfmove[8]; /* Move clock string - "8 45" maybe */ + piece_t piece; + unsigned char color; + unsigned char empty_end_of_line; + + if (board == NULL) + { + return NULL; + } + + fen = malloc(FEN_MAX_LENGTH + 1); + affirm_msg(fen, "Couldn't allocate board FEN"); + fen[0] = 0; + + for (row = 7; row >= 0; row--) + { + emptysquares[0] = '0'; + empty_end_of_line = 0; + + for (col = 0; col < 8; col++) + { + color = 0; /* really init'ed next line; this makes gcc happy */ + piece = board_pieceatsquare(board, SQUARE(col,row), &color); + if (piece == (piece_t)-1) + { + emptysquares[0]++; + if (col == 7) + { + empty_end_of_line = 1; + } + } + else + { + /* print the emptysquare count if it exists */ + if (emptysquares[0] != '0') + { + strcat(fen, emptysquares); + emptysquares[0] = '0'; + } + strcat(fen, piecename[color][piece]); + } + } + /* we finished printing this row, unless it was empty */ + if (empty_end_of_line) + { + strcat(fen, emptysquares); + } + /* print the row separator */ + strcat(fen, ((row > 0) ? "/" : " ")); + } + /* now all that's left is the flags */ + strcat(fen, ((board->tomove == WHITE) ? "w " : "b ")); + /* castle privileges - this is kinda messy */ + if (!(board->castle[WHITE][QUEENSIDE] || board->castle[WHITE][KINGSIDE] || + board->castle[BLACK][QUEENSIDE] || board->castle[BLACK][KINGSIDE])) + { + strcat(fen, "-"); + } + else + { + if (board->castle[WHITE][KINGSIDE]) strcat(fen, "K"); + if (board->castle[WHITE][QUEENSIDE]) strcat(fen, "Q"); + if (board->castle[BLACK][KINGSIDE]) strcat(fen, "k"); + if (board->castle[BLACK][QUEENSIDE]) strcat(fen, "q"); + } + strcat(fen, " "); + /* enpassant square */ + strcat(fen, ((board->ep != 0) ? squarename[board->ep] : "-")); + strcat(fen, " "); + /* move clocks - 0 for absolute move */ + sprintf(halfmove, "%d %d", board->halfmoves, (board->moves + 1)/2); + strcat(fen, halfmove); + + return fen; +} + +/** + * Gets the piece at the given square index. If the square is empty, -1. + * You should already know that there's a piece there when you call this. + * If the board is NULL or the square is invalid, -2. + * If the third argument is non-null, stores the color of the piece in there + * (unmodified if piece not present). + */ +piece_t board_pieceatsquare(board_t *board, square_t square, unsigned char *c) +{ + bitboard_t mask; + piece_t piece; + unsigned char color; + + if (board == NULL || square > 63) + { + return -2; + } + + mask = BB_SQUARE(square); + + /* find what color the piece is */ + if (board->piecesofcolor[WHITE] & mask) + { + color = WHITE; + } + else if (board->piecesofcolor[BLACK] & mask) + { + color = BLACK; + } + else + { + return -1; + } + + if (c != NULL) + { + *c = color; + } + + /* find what piece type it is */ + piece = 0; + while (!(board->pos[color][piece] & mask)) + { + piece++; + } + return piece; +} + +/** + * Is the player whose move it is in check? (1 if so, 0 if not) + */ +int board_incheck(board_t *board) +{ + return board_colorincheck(board, board->tomove); +} + +/** + * Is the given player in check? (1 if so, 0 if not) + */ +int board_colorincheck(board_t *board, unsigned char color) +{ + return !!(board->pos[color][KING] & board->attackedby[OTHERCOLOR(color)]); +} + +/** + * Check if the player to move is checkmated or stalemated. Returns either + * BOARD_CHECKMATED or BOARD_STALEMATED (from board.h), or 0 if neither. + * This is a very expensive call. Only the engine, not the searcher, should + * use this in-between moves to determine when the game ends. + */ +int board_mated(board_t *board) +{ + int result; + movelist_t moves; + move_t move; + unsigned char color; + + color = board->tomove; + result = board_colorincheck(board, color) ? + BOARD_CHECKMATED : BOARD_STALEMATED; + board_generatemoves(board, &moves); + + + while (!movelist_isempty(&moves)) + { + move = movelist_remove_max(&moves); + /* try the move, see if it puts us in check */ + board_applymove(board, move); + if (!board_colorincheck(board, color)) + { + /* found a legal move */ + board_undomove(board, move); + result = 0; + break; + } + board_undomove(board, move); + } + movelist_destroy(&moves); + return result; +} + +/** + * Is the pawn of given color at given square passed? + */ +int board_pawnpassed(board_t *board, square_t square, unsigned char color) +{ + return !(bb_passedpawnmask[color][square] & + board->pos[OTHERCOLOR(color)][PAWN]); +} + +/** + * Is the given square attacked by any piece of the given color? 1 or 0 + * Presumably the square has the OTHERCOLOR(color)'s king on it + * Note: This is "the" expensive call now that the board library doesn't use + * attacked bitboards. + */ +int board_squareisattacked(board_t *board, square_t square, unsigned char color) +{ + return !!(BB_SQUARE(square) & board->attackedby[color]); +} + +/** + * Returns true if *any* of the given squares are attacked by color. Useful + * for determining castling legality + */ +int board_squaresareattacked(board_t *board, bitboard_t squares, unsigned char color) +{ + return !!(squares & board->attackedby[color]); +} + + +/****************** + * Move generation + ******************/ + +/** + * Given the current board state, returns a bitmask representing all possible + * attacks from a given square assuming a piece of the specified type/color at + * that square. This is not the same as all the moves the piece at that square + * can make - see the special cases: pawns (capture/ep) and kings (castling). + * For pawns, forward pushes are NOT reflected in this mask, but diagonally + * threatened squares ARE, EVEN IF there is a friendly piece there. + * + * Note: Considering how the attack bitboards work, realize that we want to + * keep both attacks on other color's pieces and attacks on same color's + * pieces in here. The board_addmoves functions take care of making sure we + * don't capture our own pieces. + * + * For a cache-friendly optimization, consider taking the slidingpiece's + * index OUT of the occupancy mask before looking up - i.e. for 11101011 and + * the rook is the 3rd index from the right, use 11100011 as a lookup key + * instead, so subsequent accesses with that mask (if you move the rook along + * the column/row, etc) stay in cache. + * UPDATE: It seems to not help. I took it out. + */ +bitboard_t board_attacksfrom(board_t *board, square_t square, piece_t piece, unsigned char color) +{ + /* Used for rook/bishop attack generation */ + int shiftamount; + int diag; + bitboard_t movemask; + bitboard_t rowatk, colatk; + bitboard_t diag45attacks, diag315attacks; + + /* NOTE: We mask with ~piecesofcolor in the calling function. */ + switch (piece) + { + case PAWN: + return pawnattacks[color][square]; + case KNIGHT: + return knightattacks[square]; + case BISHOP: + /* The first table lookup */ + diag = rot45diagindex[square]; + movemask = rot45attacks[(board->occupied45 >> rot45index_shiftamountright[diag]) & 0xFF] + [COL(square)]; + diag45attacks = (movemask << rotresult_shiftamountleft[diag]) + >> rotresult_shiftamountright[diag]; + /* The second table lookup */ + diag = rot315diagindex[square]; + movemask = rot315attacks[((board->occupied315 << rot315index_shiftamountleft[diag]) >> rot315index_shiftamountright[diag]) & 0xFF] + [COL(square)]; + diag315attacks = (movemask << rotresult_shiftamountleft[diag]) + >> rotresult_shiftamountright[diag]; + /* Put them together */ + return (diag45attacks | diag315attacks); + case ROOK: + /* The first table lookup */ + shiftamount = 8 * ROW(square); + movemask = rowattacks[(board->occupied >> shiftamount) & 0xFF][COL(square)]; + rowatk = movemask << shiftamount; + /* The second table lookup */ + shiftamount = COL(square); + movemask = colattacks[(board->occupied90 >> (shiftamount * 8)) & 0xFF][ROW(square)]; + colatk = movemask << shiftamount; + /* Put them together */ + return (rowatk | colatk); + case QUEEN: + return board_attacksfrom(board, square, BISHOP, color) | + board_attacksfrom(board, square, ROOK, color); + case KING: + return kingattacks[square]; + } + /* If we got to here then piece was invalid */ + panic("Invalid piece!"); + return BB(0x0); +} + +/** + * A bitboard of all legal pawn pushes from a square (in the direction + * determined by color) considering the occupied state of the board + */ +bitboard_t board_pawnpushesfrom(board_t *board, square_t square, unsigned char color) +{ + bitboard_t moves, emptysquares; + + emptysquares = ~(board->occupied); + moves = pawnmoves[color][square] & emptysquares; /* can't push if blocked */ + /* handle double push only if a single push was available */ + if (moves) + { + if (color == WHITE) + { + if (ROW(square) == RANK_2) + { + moves |= pawnmoves[color][square + 8] & emptysquares; + } + } + else if (ROW(square) == RANK_7) + { + moves |= pawnmoves[color][square - 8] & emptysquares; + } + } + return moves; +} + +/** + * Generates a linkedlist of "legal" moves for the color to play at the given + * position. The moves are guaranteed legal, with all appropriate flags set, + * suitable for being given to makemove(), EXCEPT it is possible that the move + * might leave the player in check. We leave this task to the searcher - since + * it is necessary to call makemove() to see if a move leaves the player in + * check, and because the searcher calls makemove() anyway; we don't want to + * waste time calling it twice. + * This list needs to be movelist_destroy()ed. If there are no legal moves, + * returns an empty list; if the board is NULL, returns a null pointer. + */ +void board_generatemoves(board_t *board, movelist_t *ml) +{ + bitboard_t position; + piece_t piece; + square_t square; + unsigned char color; + + assert(board); + + color = board->tomove; + movelist_init(ml); + /* we only need to do this part once, not once per pawn */ + if (board->ep) + { + board_addmoves_ep(board, color, ml); + } + /* now do the rest of the moves */ + for (piece = 0; piece < 6; piece++) + { + position = board->pos[color][piece]; + while (position) + { + /* find a piece */ + square = BITSCAN(position); + /* clear the bit */ + position ^= BB_SQUARE(square); + /* special functions for special cases */ + switch (piece) + { + case PAWN: + board_addmoves_pawn(board, square, color, ml); + break; + case KING: + board_addmoves_king(board, square, color, ml); + break; + /* for knights, rooks, bishops, queens, + * we can use attacksfrom() directly */ + default: + board_addmoves(board, square, piece, color, ml); + } + } + } + return; +} + +/** + * The board_addmoves* series of functions take pointers to two linkedlists, + * and add each legal move for the specified piece of the specified color at + * the specified square to the lists, sorted by capture/noncapture. + */ +static void board_addmoves_pawn(board_t *board, square_t square, unsigned char color, + movelist_t *ml) +{ + bitboard_t moves; + square_t destsquare; + piece_t captpiece; + move_t move; + /* note enpassant is handled separately. first we do captures: pawns + * can't move to a square they threaten unless it's a capture */ + moves = pawnattacks[color][square] & /* inlined attacksfrom */ + board->piecesofcolor[OTHERCOLOR(color)]; + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + captpiece = board_pieceatsquare(board, destsquare, NULL); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (0x1 << MOV_INDEX_CAPT) | + (captpiece << MOV_INDEX_CAPTPC) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal capture */ + { + movelist_add(ml, board->attackedby, move); + } + } + /* now we handle pushes */ + moves = board_pawnpushesfrom(board, square, color); + /* and now we have the proper movemask generated */ + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions - add to the captures list because pawn + * promotions, like captures, change the board's material */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal push */ + { + movelist_add(ml, board->attackedby, move); + } + } + /* and we're done, phew */ + return; +} +/* don't call this if board->ep = 0 */ +static void board_addmoves_ep(board_t *board, unsigned char color, movelist_t *ml) +{ + bitboard_t pawns; + square_t fromsquare; /* we know where the dest is; we need this now */ + move_t move; + + assert(board->ep); + + /* find all pawns eligible to make the capture */ + pawns = bb_adjacentcols[COL(board->ep)] & /* the col the pawn is on */ + BB_EP_FROMRANK(color) & /* the rank a pawn needs to be on */ + board->pos[color][PAWN] /* where your pawns actually are */; + while (pawns) + { + fromsquare = BITSCAN(pawns); + pawns ^= BB_SQUARE(fromsquare); + move = (fromsquare << MOV_INDEX_SRC) | + (board->ep << MOV_INDEX_DEST) | + (0x1 << MOV_INDEX_EP) | + (0x1 << MOV_INDEX_CAPT) | + (PAWN << MOV_INDEX_CAPTPC) | + (PAWN << MOV_INDEX_PIECE); + movelist_add(ml, board->attackedby, move); + } + return; +} +/* wrapper for board_addmoves() with a special case handler for castling */ +static void board_addmoves_king(board_t *board, square_t square, unsigned char color, + movelist_t *ml) +{ + move_t move; + square_t destsquare; + int side; + /* used in the second half */ + bitboard_t moves, capts; + piece_t captpiece; + + /* deal with castling - iterate side={0,1} */ + for (side = 0; side < 2; side++) + { + if (board->castle[color][side]) + { + /* If the squares are occupied (1st two lines) or + * threatened (2nd two) then we cannot castle */ + if (!((castle_clearsquares[color][side] & + board->occupied) || + board_squaresareattacked(board, castle_safesquares[color][side], + OTHERCOLOR(color)))) + { + /* find where the king will end up */ + destsquare = SQUARE(CASTLE_DEST_COL(side), + HOMEROW(color)); + /* generate and add the move */ + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (0x1 << MOV_INDEX_CASTLE) | + (KING << MOV_INDEX_PIECE); + movelist_add(ml, board->attackedby, move); + } + } + } + /* now the special case is out of the way, the rest is simple. this + * could be a call to board_addmoves, but for move ordering purposes + * we do it separately. also, if we filter out suicide moves here, + * we avoid wasting time with applymove() in the searcher before + * seeing if the move is legal. */ + /* inlined attacksfrom */ + moves = kingattacks[square] & (~(board->piecesofcolor[color])); + /* here's the special part - we can't move the king anywhere where it + * will be in check - note, this still produces an illegal move if the + * king walks straight backward from a sliding piece, but we're only + * producing pseudo-legal moves, so this is merely an optimization. + * the movelist relies on not producing an obvious king-hang move. */ + moves &= (~(board->attackedby[OTHERCOLOR(color)])); + /* the rest is the same as board_addmoves */ + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* that's a lie - the other special thing we do here is ordering so + * the king moves/capts are grouped with the pawn moves/capts */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (KING << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + /* then process noncapture moves */ + while (moves) + { + /* find and clear a bit */ + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (KING << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + + return; +} +/* for non-special-case pieces: knight bishop rook queen. see above comment */ +static void board_addmoves(board_t *board, square_t square, piece_t piece, unsigned char color, + movelist_t *ml) +{ + bitboard_t moves, capts; + square_t destsquare; + piece_t captpiece; + move_t move; + + /* find all destination squares -- all attacked squares, but can't + * capture our own pieces */ + moves = board_attacksfrom(board, square, piece, color) & (~(board->piecesofcolor[color])); + /* separate captures from noncaptures */ + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* process captures first */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (piece << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + /* then process noncapture moves */ + while (moves) + { + /* find and clear a bit */ + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (piece << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + return; +} + +/** + * The same as board_generatemoves, except we generate only captures. This is + * optimized to not even think about noncapture moves to be especially fast + * for quiescence searching. + */ +void board_generatecaptures(board_t *board, movelist_t *ml) +{ + bitboard_t position; + piece_t piece; + square_t square; + unsigned char color; + + assert(board); + + color = board->tomove; + movelist_init(ml); + /* same call as in addmoves... ep is always a capture */ + if (board->ep) + { + //XXX: Take this out, as it won't help that much in quiescence? Depends on how fast it is + board_addmoves_ep(board, color, ml); + } + for (piece = 0; piece < 6; piece++) + { + position = board->pos[color][piece]; + while (position) + { + /* find a piece */ + square = BITSCAN(position); + /* clear the bit */ + position ^= BB_SQUARE(square); + switch (piece) + { + case PAWN: + board_addcaptures_pawn(board, square, color, ml); + break; + case KING: + board_addcaptures_king(board, square, color, ml); + break; + default: + board_addcaptures(board, square, piece, color, ml); + } + } + } + return; +} + +static void board_addcaptures_pawn(board_t *board, square_t square, unsigned char color, movelist_t *ml) +{ + bitboard_t moves; + square_t destsquare; + piece_t captpiece; + move_t move; + /* captures */ + moves = pawnattacks[color][square] & /* inlined attacksfrom */ + board->piecesofcolor[OTHERCOLOR(color)]; + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + captpiece = board_pieceatsquare(board, destsquare, NULL); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (0x1 << MOV_INDEX_CAPT) | + (captpiece << MOV_INDEX_CAPTPC) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal capture */ + { + movelist_add(ml, board->attackedby, move); + } + } + /* now we handle pushes only if it's a passed pawn */ + if (board_pawnpassed(board, square, color)) + { + moves = board_pawnpushesfrom(board, square, color); + /* and now we have the proper movemask generated */ + while (moves) + { + destsquare = BITSCAN(moves); + moves ^= BB_SQUARE(destsquare); + move = (square << MOV_INDEX_SRC) | + (destsquare << MOV_INDEX_DEST) | + (color << MOV_INDEX_COLOR) | + (PAWN << MOV_INDEX_PIECE); + /* handle promotions */ + if (ROW(destsquare) == HOMEROW(OTHERCOLOR(color))) + { + move |= (0x1 << MOV_INDEX_PROM); + movelist_add(ml, board->attackedby, (move | (BISHOP << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (ROOK << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (KNIGHT << MOV_INDEX_PROMPC))); + movelist_add(ml, board->attackedby, (move | (QUEEN << MOV_INDEX_PROMPC))); + } + else /* normal push */ + { + movelist_add(ml, board->attackedby, move); + } + } + } + return; +} + +static void board_addcaptures_king(board_t *board, square_t square, unsigned char color, movelist_t *ml) +{ + move_t move; + square_t destsquare; + bitboard_t moves, capts; + piece_t captpiece; + + /* No dealing with castling! :D this is the same as addcaptures() but + * again we do the special thing */ + /* inlined attacksfrom */ + moves = kingattacks[square] & (~(board->piecesofcolor[color])); + moves &= (~(board->attackedby[OTHERCOLOR(color)])); + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* like in regular movegen, captures by king go at the beginning */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (KING << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + return; +} + +static void board_addcaptures(board_t *board, square_t square, piece_t piece, unsigned char color, movelist_t *ml) +{ + bitboard_t moves, capts; + square_t destsquare; + piece_t captpiece; + move_t move; + + /* find all destination squares -- all attacked squares, but can't + * capture our own pieces */ + moves = board_attacksfrom(board, square, piece, color) & + (~(board->piecesofcolor[color])); + /* separate captures from noncaptures */ + capts = moves & board->piecesofcolor[OTHERCOLOR(color)]; + moves ^= capts; + /* process captures first */ + while (capts) + { + /* find and clear a bit */ + destsquare = BITSCAN(capts); + capts ^= BB_SQUARE(destsquare); + /* find what piece was captured */ + captpiece = board_pieceatsquare(board, destsquare, NULL); + /* generate the move_t */ + move = (square << MOV_INDEX_SRC) | /* from square */ + (destsquare << MOV_INDEX_DEST) | /* to square */ + (color << MOV_INDEX_COLOR) | /* color flag */ + (0x1 << MOV_INDEX_CAPT) | /* capture flag */ + (captpiece << MOV_INDEX_CAPTPC) | /* captured piece */ + (piece << MOV_INDEX_PIECE); /* our piece */ + /* and add it to the list */ + movelist_add(ml, board->attackedby, move); + } + return; +} + + +/*********************** + * Changing board state + ***********************/ + +/** + * Given a move, which MUST be properly formatted AND legal (only use moves + * returned by board_generatemoves() or move_islegal() here), applies the move + * to change the board position. Updates the zobrist hash, undo stacks, + * everything. + */ +void board_applymove(board_t *board, move_t move) +{ + square_t rooksrc, rookdest; /* how the rook moves in castling */ + square_t epcapture; /* where a pawn will disappear from */ + int i; + + /* save history. */ + history_t *h = &board->history[board->moves]; + affirm(board->moves < HISTORY_STACK_SIZE); + h->hash = board->hash; + h->attackedby[WHITE] = board->attackedby[WHITE]; + h->attackedby[BLACK] = board->attackedby[BLACK]; + h->castle[WHITE][QUEENSIDE] = board->castle[WHITE][QUEENSIDE]; + h->castle[WHITE][KINGSIDE] = board->castle[WHITE][KINGSIDE]; + h->castle[BLACK][QUEENSIDE] = board->castle[BLACK][QUEENSIDE]; + h->castle[BLACK][KINGSIDE] = board->castle[BLACK][KINGSIDE]; + h->ep = board->ep; + h->halfmoves = board->halfmoves; + h->reps = board->reps; + h->move = move; + + /* cleanly handle null-move */ + if (move == 0) + { + /* clear ep square */ + board->hash ^= zobrist_ep[board->ep]; + board->ep = 0; + board->hash ^= zobrist_ep[board->ep]; + /* update the move clock */ + board->halfmoves++; + board->moves++; + /* null move is illegal, so it can't cause a threefold draw */ + board->reps = 0; + /* switch who has the move */ + board->tomove = OTHERCOLOR(board->tomove); + board->hash ^= zobrist_tomove; + return; + } + + assert(MOV_PIECE(move) >= 0 && MOV_PIECE(move) < 6); + + /* Take care of captures - we need to remove the captured piece. */ + if (MOV_CAPT(move)) + { + /* special case - en passant - square behind the dest square */ + if (MOV_EP(move)) + { + assert(ROW(MOV_SRC(move)) == 4 - board->tomove); + /* find where the pawn disappears from */ + epcapture = (board->tomove == WHITE) ? + (MOV_DEST(move) - 8) : + (MOV_DEST(move) + 8); + /* kill the pawn */ + board_togglepiece(board, epcapture, + OTHERCOLOR(board->tomove), PAWN); + /* change the material count */ + board->material[OTHERCOLOR(board->tomove)] -= + eval_piecevalue[PAWN]; + } + /* standard capture - square is the dest square */ + else + { + board_togglepiece(board, MOV_DEST(move), + OTHERCOLOR(board->tomove), + MOV_CAPTPC(move)); + /* If the captured piece is a rook on its home square, + * and the player was still able to castle that side, + * we need to clear the castle privileges there */ + if (MOV_CAPTPC(move) == ROOK && + ROW(MOV_DEST(move)) == HOMEROW(OTHERCOLOR(board->tomove)) && + (COL(MOV_DEST(move)) == COL_H || + COL(MOV_DEST(move)) == COL_A)) + { + /* (COLUMN == COL_H) will evaluate to 1 if on + * KINGSIDE (this depends on KINGSIDE == 1) */ + unsigned char side = (COL(MOV_DEST(move)) == COL_H); + /* if castle rights is already gone there, we + * don't do anything. this is important when + * toggling the zobrist */ + if (board->castle[OTHERCOLOR(board->tomove)][side]) + { + board->castle[OTHERCOLOR(board->tomove)][side] = 0; + board->hash ^= zobrist_castle[OTHERCOLOR(board->tomove)] + [side]; + } + + } + /* change the material count */ + board->material[OTHERCOLOR(board->tomove)] -= + eval_piecevalue[MOV_CAPTPC(move)]; + } + board->halfmoves = 0; + } + /* here we detect irreversible moves for the halfmove clock */ + else + { + if (MOV_PIECE(move) == PAWN) + { + board->halfmoves = 0; + } + else + { + board->halfmoves++; + } + } + /* the game clock as well */ + board->moves++; + + /* castling, need to move the rook. castle privileges handled below */ + if (MOV_CASTLE(move)) + { + /* detect kingside vs queenside */ + if (COL(MOV_DEST(move)) == COL_G) + { + rooksrc = SQUARE(COL_H,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_F,HOMEROW(board->tomove)); + } + else + { + rooksrc = SQUARE(COL_A,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_D,HOMEROW(board->tomove)); + } + /* and move the rook */ + board_togglepiece(board, rooksrc, board->tomove, ROOK); + board_togglepiece(board, rookdest, board->tomove, ROOK); + /* set the flag */ + board->hascastled[board->tomove] = 1; + } + + /* here we move the moving piece itself; in the former case it turns + * into a different type of piece */ + board_togglepiece(board, MOV_SRC(move), board->tomove, + MOV_PIECE(move)); + if (MOV_PROM(move)) + { + assert(ROW(MOV_DEST(move)) == + HOMEROW(OTHERCOLOR(board->tomove))); + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PROMPC(move)); + /* and of course account for this in the material count */ + board->material[board->tomove] += + (eval_piecevalue[MOV_PROMPC(move)] - + eval_piecevalue[PAWN]); + } + else + { + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PIECE(move)); + } + + /* detect an enpassantable move */ + if (MOV_PIECE(move) == PAWN) + { + /* if the difference between the square values is 16 not 8 + * then it was a double push */ + if ((board->tomove == WHITE) && + ((MOV_DEST(move) - MOV_SRC(move)) == 16)) + { + /* clear the old ep status in the hash */ + board->hash ^= zobrist_ep[board->ep]; + /* set the new value */ + board->ep = MOV_SRC(move) + 8; + /* throw in the new key */ + board->hash ^= zobrist_ep[board->ep]; + } + else if ((board->tomove == BLACK) && + ((MOV_SRC(move) - MOV_DEST(move)) == 16)) + { + board->hash ^= zobrist_ep[board->ep]; + board->ep = MOV_DEST(move) + 8; + board->hash ^= zobrist_ep[board->ep]; + } + else + { + board->hash ^= zobrist_ep[board->ep]; + board->ep = 0; + board->hash ^= zobrist_ep[board->ep]; + } + } + /* not a pawn move. ep square goes away. */ + else + { + board->hash ^= zobrist_ep[board->ep]; + board->ep = 0; + board->hash ^= zobrist_ep[board->ep]; + /* handle castling rights */ + if (MOV_PIECE(move) == KING) + { + if (board->castle[board->tomove][KINGSIDE]) + { + board->castle[board->tomove][KINGSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][KINGSIDE]; + } + if (board->castle[board->tomove][QUEENSIDE]) + { + board->castle[board->tomove][QUEENSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][QUEENSIDE]; + } + } + else if (MOV_PIECE(move) == ROOK) + { + if ((board->castle[board->tomove][KINGSIDE]) && + (COL(MOV_SRC(move)) == COL_H)) + { + board->castle[board->tomove][KINGSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][KINGSIDE]; + } + else if ((board->castle[board->tomove][QUEENSIDE]) && + (COL(MOV_SRC(move)) == COL_A)) + { + board->castle[board->tomove][QUEENSIDE] = 0; + board->hash ^= zobrist_castle[board->tomove][QUEENSIDE]; + } + } + } + + /* switch who has the move */ + board->tomove = OTHERCOLOR(board->tomove); + board->hash ^= zobrist_tomove; + + /* calculate repetition count */ + board->reps = 0; + for (i = 1; i <= board->halfmoves; i++) + { + if (board->history[board->moves - i].hash == board->hash) + { + board->reps = board->history[board->moves - i].reps+1; + break; + } + } + + /* and finally */ + board_regeneratethreatened(board); + return; +} + +/** + * Go back one move. The cleaner implementation is to keep a stack of the + * moves, but it's faster to have the searcher/legalitychecker just pass in + * the move again rather than mucking about with data structures. + * Note if you pass in a move different from the one that was most recently + * made, the board state will choke and die horribly. + */ +void board_undomove(board_t *board, move_t move) +{ + square_t rooksrc, rookdest, epcapture; + + /* switch who has the move */ + board->tomove = OTHERCOLOR(board->tomove); + board->hash ^= zobrist_tomove; + + /* cleanly handle null-move */ + if (move == 0) + { + board->moves--; + board->halfmoves--; + board->hash ^= zobrist_ep[board->ep]; + board->ep = board->history[board->moves].ep; + board->hash ^= zobrist_ep[board->ep]; + board->reps = board->history[board->moves].reps; + return; + } + + /* The non-special things (see bottom of function for special things) + * are basically applymove in reverse. First move the piece back. */ + board_togglepiece(board, MOV_SRC(move), board->tomove, MOV_PIECE(move)); + if (MOV_PROM(move)) + { + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PROMPC(move)); + /* material count */ + board->material[board->tomove] -= + (eval_piecevalue[MOV_PROMPC(move)] - + eval_piecevalue[PAWN]); + } + else + { + board_togglepiece(board, MOV_DEST(move), board->tomove, + MOV_PIECE(move)); + } + /* castling, need to move the rook back. */ + if (MOV_CASTLE(move)) + { + /* detect kingside vs queenside */ + if (COL(MOV_DEST(move)) == COL_G) + { + /* note src is where it needs to end up because we're + * moving backwards not forwards */ + rooksrc = SQUARE(COL_H,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_F,HOMEROW(board->tomove)); + } + else + { + rooksrc = SQUARE(COL_A,HOMEROW(board->tomove)); + rookdest = SQUARE(COL_D,HOMEROW(board->tomove)); + } + /* and move the rook */ + board_togglepiece(board, rooksrc, board->tomove, ROOK); + board_togglepiece(board, rookdest, board->tomove, ROOK); + /* flag */ + board->hascastled[board->tomove] = 0; + } + /* for captures, put the captured piece back */ + if (MOV_CAPT(move)) + { + /* special case - en passant - square behind the dest square */ + if (MOV_EP(move)) + { + epcapture = (board->tomove == WHITE) ? + (MOV_DEST(move) - 8) : + (MOV_DEST(move) + 8); + board_togglepiece(board, epcapture, + OTHERCOLOR(board->tomove), PAWN); + board->material[OTHERCOLOR(board->tomove)] += + eval_piecevalue[PAWN]; + } + /* standard capture - square is the dest square */ + else + { + board_togglepiece(board, MOV_DEST(move), + OTHERCOLOR(board->tomove), + MOV_CAPTPC(move)); + board->material[OTHERCOLOR(board->tomove)] += + eval_piecevalue[MOV_CAPTPC(move)]; + } + } + + /* decrement the game clock */ + board->moves--; + + /* Get the previous special board state information from the stacks */ + board->attackedby[WHITE] = board->history[board->moves].attackedby[WHITE]; + board->attackedby[BLACK] = board->history[board->moves].attackedby[BLACK]; + + /* clear the old castle keys */ + if (board->castle[WHITE][QUEENSIDE]) { board->hash ^= zobrist_castle[WHITE][QUEENSIDE]; } + if (board->castle[WHITE][KINGSIDE]) { board->hash ^= zobrist_castle[WHITE][KINGSIDE]; } + if (board->castle[BLACK][QUEENSIDE]) { board->hash ^= zobrist_castle[BLACK][QUEENSIDE]; } + if (board->castle[BLACK][KINGSIDE]) { board->hash ^= zobrist_castle[BLACK][KINGSIDE]; } + /* set the new castle rights */ + board->castle[WHITE][QUEENSIDE] = board->history[board->moves].castle[WHITE][QUEENSIDE]; + board->castle[WHITE][KINGSIDE] = board->history[board->moves].castle[WHITE][KINGSIDE]; + board->castle[BLACK][QUEENSIDE] = board->history[board->moves].castle[BLACK][QUEENSIDE]; + board->castle[BLACK][KINGSIDE] = board->history[board->moves].castle[BLACK][KINGSIDE]; + /* set the new castle keys */ + if (board->castle[WHITE][QUEENSIDE]) { board->hash ^= zobrist_castle[WHITE][QUEENSIDE]; } + if (board->castle[WHITE][KINGSIDE]) { board->hash ^= zobrist_castle[WHITE][KINGSIDE]; } + if (board->castle[BLACK][QUEENSIDE]) { board->hash ^= zobrist_castle[BLACK][QUEENSIDE]; } + if (board->castle[BLACK][KINGSIDE]) { board->hash ^= zobrist_castle[BLACK][KINGSIDE]; } + + /* restore ep information */ + board->hash ^= zobrist_ep[board->ep]; + board->ep = board->history[board->moves].ep; + board->hash ^= zobrist_ep[board->ep]; + + /* set the halfmove clock */ + board->halfmoves = board->history[board->moves].halfmoves; + + /* and repetitions */ + board->reps = board->history[board->moves].reps; + + /* consistency check */ + assert(board->hash == board->history[board->moves].hash); + assert(move == board->history[board->moves].move); + return; +} + +/** + * The togglepiece function is a wrapper to simplify moving pieces around on + * the board. They modify the bits in the piece-specific position masks, the + * all-pieces-of-one-color mask, and in the four occupied boards, and adjust + * the zobrist hash. + */ +static void board_togglepiece(board_t *board, square_t square, + unsigned char color, piece_t piece) +{ + /* no other piece ought be on this square */ + assert(!(board->occupied & BB_SQUARE(square) & + ~board->pos[color][piece])); + /* piece-specific position mask */ + board->pos[color][piece] ^= BB_SQUARE(square); + + /* all the color's pieces */ + board->piecesofcolor[color] ^= BB_SQUARE(square); + + /* general occupied masks */ + board->occupied ^= BB_SQUARE(square); + board->occupied90 ^= BB_SQUARE(ROT90SQUAREINDEX(square)); + board->occupied45 ^= BB_SQUARE(ROT45SQUAREINDEX(square)); + board->occupied315 ^= BB_SQUARE(ROT315SQUAREINDEX(square)); + + /* adjust the zobrist */ + board->hash ^= zobrist_piece[color][piece][square]; +} + +/** + * This hashtable stores threatened square masks so we don't have to always + * regenerate them. + */ +typedef struct { + bitboard_t key; + bitboard_t white; + bitboard_t black; +} regen_entry_t; + +#ifndef REGEN_NUM_BUCKETS +#define REGEN_NUM_BUCKETS (32 * 1024 * 1024 / sizeof(regen_entry_t)) // 32 MB +#endif +static regen_entry_t regen_array[REGEN_NUM_BUCKETS]; + +static void regen_add(bitboard_t key, bitboard_t white, bitboard_t black) +{ + unsigned long bucket = key % REGEN_NUM_BUCKETS; + regen_array[bucket].key = key; + regen_array[bucket].white = white; + regen_array[bucket].black = black; +} + +static int regen_get(bitboard_t key, bitboard_t *white, bitboard_t *black) +{ + unsigned long bucket = key % REGEN_NUM_BUCKETS; + if (regen_array[bucket].key == key) + { + *white = regen_array[bucket].white; + *black = regen_array[bucket].black; + return 1; + } + return 0; +} + +int regen_hits = 0; +int regen_misses = 0; + +/** + * Regenerate the threatened squares masks for both sides. Should be used when + * a move is made. Don't use in undomove, use the special stacks instead + */ +static void board_regeneratethreatened(board_t *board) +{ + bitboard_t mask; + bitboard_t position; + piece_t piece; + square_t square; + + /* check hashtable */ + if (regen_get(board->hash, + &board->attackedby[WHITE], &board->attackedby[BLACK])) + { + regen_hits++; + return; + } + + /******** + * White + ********/ + mask = BB(0x0); + /* pawn threatened can be done for all pawns at once */ + mask |= board_pawnattacks(board->pos[WHITE][PAWN], WHITE); + /* Knights and kings manually inlined */ + position = board->pos[WHITE][KNIGHT]; + while (position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= knightattacks[square]; + } + position = board->pos[WHITE][KING]; + while(position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= kingattacks[square]; + } + /* other piece threatened */ + for (piece = 2; piece < 5; piece++) + { + position = board->pos[WHITE][piece]; + /* keep going until we've found all the pieces */ + while (position) + { + /* Find one of the pieces, clear its bit */ + square = BITSCAN(position); + position ^= BB_SQUARE(square); + /* Put the attacks from this square in the mask */ + mask |= board_attacksfrom(board, square, piece, WHITE); + } + } + board->attackedby[WHITE] = mask; + /******** + * Black + ********/ + mask = BB(0x0); + /* pawn threatened can be done for all pawns at once */ + mask |= board_pawnattacks(board->pos[BLACK][PAWN], BLACK); + /* Knights and kings manually inlined */ + position = board->pos[BLACK][KNIGHT]; + while (position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= knightattacks[square]; + } + position = board->pos[BLACK][KING]; + while(position) + { + square = BITSCAN(position); + position ^= BB_SQUARE(square); + mask |= kingattacks[square]; + } + /* other piece threatened */ + for (piece = 2; piece < 5; piece++) + { + position = board->pos[BLACK][piece]; + /* keep going until we've found all the pieces */ + while (position) + { + /* Find one of the pieces, clear its bit */ + square = BITSCAN(position); + position ^= BB_SQUARE(square); + /* Put the attacks from this square in the mask */ + mask |= board_attacksfrom(board, square, piece, BLACK); + } + } + board->attackedby[BLACK] = mask; + + /* save to hashtable */ + regen_add(board->hash, board->attackedby[WHITE], board->attackedby[BLACK]); + regen_misses++; + + return; +} + +/** + * Get a bitmap of all squares attacked by the pawns in the given position of + * the given color. Used by regenthreatened, and also in pawnstructure eval + */ +bitboard_t board_pawnattacks(bitboard_t pawns, unsigned char color) +{ + /* a-pawns don't attack left; h-pawns don't attack right */ + if (color == WHITE) + { + return ((pawns & ~BB_FILEA) << 7) | ((pawns & ~BB_FILEH) << 9); + } + else + { + return ((pawns & ~BB_FILEA) >> 9) | ((pawns & ~BB_FILEH) >> 7); + } +} + +/** + * Is the current position a threefold draw? + */ +int board_threefold_draw(board_t *board) +{ + return board->reps >= 2; +} + +/**************************************************************************** + * END: BITBOARD FUNCTIONS + * BEGIN: MOVE FUNCTIONS + ****************************************************************************/ + +static move_t move_checksuicide(board_t *, move_t, char **); + +/** + * Parses computer friendly ("d7c8N" or "e1g1") notation to generate a simple + * move_t template. Will return 0 on a malformatted move (note 0 is never a + * valid move_t). This will only set the prom flag, not castle/ep/capt. As a + * result, the resultant move is not suitable for throwing directly into + * applyMove. + */ +move_t move_fromstring(char *str) +{ + size_t length = strlen(str); + move_t move = 0; + + /* check for malformatted move string */ + if (length < 4 || length > 5 || /* too short/long */ + !(str[0] >= 'a' && str[0] <= 'h') || /* bad src/dest squares */ + !(str[1] >= '1' && str[1] <= '8') || + !(str[2] >= 'a' && str[2] <= 'h') || + !(str[3] >= '1' && str[3] <= '8') || + (length == 5 && /* bad promotion piece */ + !(str[4] == 'N' || str[4] == 'B' || + str[4] == 'R' || str[4] == 'Q' || + str[4] == 'n' || str[4] == 'b' || + str[4] == 'r' || str[4] == 'q'))) + { + return (move_t)0; + } + + /* set the src and dest */ + move |= SQUARE((str[0] - 'a'), (str[1] - '1')) << MOV_INDEX_SRC; + move |= SQUARE((str[2] - 'a'), (str[3] - '1')) << MOV_INDEX_DEST; + + /* promotion */ + if (length == 5) + { + move |= 1 << MOV_INDEX_PROM; /* set the flag */ + switch(str[4]) + { + case 'N': + case 'n': + move |= KNIGHT << MOV_INDEX_PROMPC; + break; + case 'B': + case 'b': + move |= BISHOP << MOV_INDEX_PROMPC; + break; + case 'R': + case 'r': + move |= ROOK << MOV_INDEX_PROMPC; + break; + default: + move |= QUEEN << MOV_INDEX_PROMPC; + } + } + + return move; +} + +/** + * A more advanced form of move_fromstring. Given also a board_t, will return + * a move_t for the move represented by str if it is 1) properly formatted, + * 2) valid, 3) legal. Otherwise returns 0. All appropriate flags will be set, + * so this is suitable for applymove. + * This code is not fast, as it will apply/undo the move from the board. Use + * it for checking the opponent's move, not the engine's move. + */ +move_t move_islegal(board_t *board, char *str, char **errmsg) +{ + move_t move; + square_t src, dest; + piece_t piece; + bitboard_t moves, clearsquares; + + /* Parse the string */ + move = move_fromstring(str); + src = MOV_SRC(move); + dest = MOV_DEST(move); + + /* First check: sanity; this also handles if move_fromstring failed */ + if (src == dest) + { + *errmsg = "!!! Motion is required for a move."; + return 0; + } + /* Does this piece belong to us */ + if (!(BB_SQUARE(src) & board->piecesofcolor[board->tomove])) + { + *errmsg = "!!! You don't have a piece there."; + return 0; + } + + /* Find our piece and where it can go */ + piece = board_pieceatsquare(board, src, NULL); + moves = board_attacksfrom(board, src, piece, board->tomove) & + (~(board->piecesofcolor[board->tomove])); /* can't capture own piece */ + move |= piece << MOV_INDEX_PIECE; /* set the piece-type flag */ + + /* of course, pawns and kings are special... */ + if (piece == PAWN) /* pushes and enpassants */ + { + /* can't make an attacking move unless it's a capture */ + moves &= board->piecesofcolor[OTHERCOLOR(board->tomove)]; + /* Trying to make an illegal promotion, or not promoting on an + * advance to the promotion rank */ + if ((!!(MOV_PROM(move))) ^ + (!!(ROW(dest) == HOMEROW(OTHERCOLOR(board->tomove))))) + { + if (!!(MOV_PROM(move))) { + *errmsg = "!!! Pawns don't promote like that."; + } else { + *errmsg = "!!! Promote into what? (N/B/R/Q)"; + } + return 0; + } + /* move is a regular capture */ + if (BB_SQUARE(dest) & moves) + { + move |= 1 << MOV_INDEX_CAPT; + move |= board_pieceatsquare(board, dest, NULL) << MOV_INDEX_CAPTPC; + return move_checksuicide(board, move, errmsg); + } + /* enpassant */ + if (board->ep && dest == board->ep) + { + move |= (0x1 << MOV_INDEX_EP) | + (0x1 << MOV_INDEX_CAPT) | + (PAWN << MOV_INDEX_CAPTPC); + return move_checksuicide(board, move, errmsg); + } + /* check for push */ + clearsquares = ~board->occupied; + /* is pawn free to move one square ahead? we don't need to set + * any special additional flags here */ + if (pawnmoves[board->tomove][src] & clearsquares) + { + /* Are we trying to move 1 square ahead? Note: relies + * on the fact that pawnmoves[][] has one bit set. */ + if (BB_SQUARE(dest) == pawnmoves[board->tomove][src]) + { + return move_checksuicide(board, move, errmsg); + } + /* 2-square push from 2nd rank */ + if (((board->tomove == WHITE) && + (pawnmoves[board->tomove][src+8] & clearsquares) && + (BB_SQUARE(dest) == pawnmoves[board->tomove][src+8])) || + ((board->tomove == BLACK) && + (pawnmoves[board->tomove][src-8] & clearsquares) && + (BB_SQUARE(dest) == pawnmoves[board->tomove][src-8]))) + { + return move_checksuicide(board, move, errmsg); + } + } + *errmsg = "!!! Pawns can't move like that."; + return 0; + } + /* not a pawn, trying to promote a different piece */ + else if (MOV_PROM(move)) + { + *errmsg = "!!! You can't promote non-pawns!"; + return 0; + } + /* note - for king moves, we don't need to apply the move to check if + * it puts the player in check; we use squareisattacked() directly */ + else if (piece == KING) + { + /* handle castling - queenside */ + if (board->castle[board->tomove][QUEENSIDE] && + (src == SQUARE(COL_E,HOMEROW(board->tomove))) && + (dest == SQUARE(COL_C,HOMEROW(board->tomove)))) /* "e1c1" or "e8c8" */ + { + /* check if special squares are blocked or attacked */ + if (castle_clearsquares[board->tomove][QUEENSIDE] & board->occupied) { + *errmsg = "!!! Castling squares are blocked."; + return 0; + } else if (board_squaresareattacked(board, castle_safesquares[board->tomove][QUEENSIDE], OTHERCOLOR(board->tomove))) { + *errmsg = "!!! Can't castle through check."; + return 0; + } + /* here, the castle is legal */ + move |= 0x1 << MOV_INDEX_CASTLE; + return move; + } + /* kingside */ + if (board->castle[board->tomove][KINGSIDE] && + (src == SQUARE(COL_E,HOMEROW(board->tomove))) && + (dest == SQUARE(COL_G,HOMEROW(board->tomove)))) /* "e1g1" or "e8g8" */ + { + /* check if special squares are blocked or attacked */ + if (castle_clearsquares[board->tomove][KINGSIDE] & board->occupied) { + *errmsg = "!!! Castling squares are blocked."; + return 0; + } else if (board_squaresareattacked(board, castle_safesquares[board->tomove][KINGSIDE], OTHERCOLOR(board->tomove))) { + *errmsg = "!!! Can't castle through check."; + return 0; + } + /* here, the castle is legal */ + move |= 0x1 << MOV_INDEX_CASTLE; + return move; + } + /* otherwise it must be a normal king move to be legal */ + /* we can make this move */ + if (BB_SQUARE(dest) & moves) + { + /* making a capture */ + if (BB_SQUARE(dest) & board->piecesofcolor[OTHERCOLOR(board->tomove)]) + { + move |= 1 << MOV_INDEX_CAPT; + move |= board_pieceatsquare(board, dest, NULL) << MOV_INDEX_CAPTPC; + } + if (board_squareisattacked(board, dest, OTHERCOLOR(board->tomove))) + { + *errmsg = "!!! Can't move king into check."; + return 0; + } + return move; + } + *errmsg = "!!! Kings can't move like that."; + return 0; + } + /* typical case piece - N B R Q */ + else + { + /* is this one of our legal moves? */ + if (BB_SQUARE(dest) & moves) + { + /* making a capture? */ + if (BB_SQUARE(dest) & board->piecesofcolor[OTHERCOLOR(board->tomove)]) + { + move |= 1 << MOV_INDEX_CAPT; + move |= board_pieceatsquare(board, dest, NULL) << MOV_INDEX_CAPTPC; + } + return move_checksuicide(board, move, errmsg); + } + *errmsg = + piece == QUEEN ? "!!! Queens can't move like that." : + piece == ROOK ? "!!! Rooks can't move like that." : + piece == BISHOP ? "!!! Bishops can't move like that." : + "!!! Knights can't move like that."; + return 0; + } +} + +/** + * Given a move on a given position (must be legal and suitably formatted for + * applymove), check if making this move would leave the player in check. + * Returns the move if it's good, 0 if not. + */ +static move_t move_checksuicide(board_t *board, move_t move, char **errmsg) +{ + board_applymove(board, move); + if (board_colorincheck(board, OTHERCOLOR(board->tomove))) + { + board_undomove(board, move); + *errmsg = "!!! That would put you in check."; + return 0; + } + board_undomove(board, move); + return move; +} + +/** + * Returns the string representation of a move in computer-friendly format + * (that is, "squarename[src]squarename[dest]promotionpiece"). Free the string + * when you're done with it. + */ +char *move_tostring(move_t m) +{ + char *string; + /* longest move in this format is a promotion, "a7a8Q" */ + string = malloc(6); + affirm_msg(string, "Couldn't allocate move string"); + string[0] = 0; + strcat(string, squarename[MOV_SRC(m)]); + strcat(string, squarename[MOV_DEST(m)]); + if (MOV_PROM(m)) + { + /* use WHITE as an index to get the uppercase */ + strcat(string, piecename[WHITE][MOV_PROMPC(m)]); + } + return string; +} +/**************************************************************************** + * book.c - simple interface for retrieving moves from a plaintext book + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ + +#define BOOK_MOVE_LENGTH 4 + +// Must be sorted. +const char *book[] = { + "c2c4 c7c5 g1f3 b8c6", + "c2c4 c7c5 g1f3 g8f6 b1c3 b8c6", + "c2c4 c7c5 g1f3 g8f6 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "c2c4 c7c5 g1f3 g8f6 g2g3", + "c2c4 c7c6", + "c2c4 e7e5 b1c3 b8c6", + "c2c4 e7e5 b1c3 g8f6 g1f3 b8c6 g2g3", + "c2c4 e7e5 g2g3", + "c2c4 e7e6 b1c3 d7d5 d2d4 c7c6", + "c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 g1f3 g8f6 c1f4 e8g8 e2e3", + "c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 g1f3 g8f6 c1g5 e8g8 e2e3 h7h6", + "c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 g1f3 g8f6 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 c1g5 f8e7 e2e3", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 c4d5 e6d5 c1g5", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 b8d7", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c5", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c6 c1g5", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8b4", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8e7 c1f4 e8g8 e2e3", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "c2c4 e7e6 b1c3 d7d5 d2d4 g8f6 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 e7e6 g1f3", + "c2c4 g8f6 b1c3 c7c5", + "c2c4 g8f6 b1c3 e7e5 g1f3 b8c6 g2g3", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 b8d7", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c5", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c6 c1g5", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c6 e2e3 b8d7 d1c2 f8d6", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8b4", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8e7 c1f4 e8g8 e2e3", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8e7 c1g5 e8g8 e2e3 h7h6", + "c2c4 g8f6 b1c3 e7e6 g1f3 d7d5 d2d4 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 g8f6 b1c3 g7g6", + "c2c4 g8f6 g1f3 b7b6 g2g3", + "c2c4 g8f6 g1f3 c7c5 b1c3 b8c6", + "c2c4 g8f6 g1f3 c7c5 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "c2c4 g8f6 g1f3 c7c5 g2g3", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 b8d7", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c5", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c6 c1g5", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 d1c2 f8d6", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8b4", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8e7 c1f4 e8g8 e2e3", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 e8g8 e2e3 h7h6", + "c2c4 g8f6 g1f3 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "c2c4 g8f6 g1f3 e7e6 g2g3 d7d5 f1g2 f8e7", + "c2c4 g8f6 g1f3 g7g6 b1c3 f8g7 e2e4", + "c2c4 g8f6 g1f3 g7g6 g2g3 f8g7 f1g2 e8g8", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 e2e3", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 e7e6 c1g5", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 c7c6 b1c3 g8f6 g1f3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 e7e6 c1g5", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 c7c6 g1f3 g8f6 e2e3", + "d2d4 d7d5 c2c4 d5c4 g1f3 e7e6 e2e3 g8f6", + "d2d4 d7d5 c2c4 d5c4 g1f3 g8f6 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "d2d4 d7d5 c2c4 e7e6 b1c3 c7c6", + "d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 g1f3 g8f6 c1f4 e8g8 e2e3", + "d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 g1f3 g8f6 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 g1f3 g8f6 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 c1g5 f8e7 e2e3", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 c4d5 e6d5 c1g5", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 b8d7", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c5", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c6 c1g5", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8b4", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 c2c4 e7e6 b1c3 g8f6 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 b8d7", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c5", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c6 c1g5", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8b4", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 c1g5", + "d2d4 d7d5 c2c4 e7e6 g1f3 g8f6 g2g3", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 b8d7", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c5", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c6 c1g5", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8b4", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 c1g5", + "d2d4 d7d5 g1f3 e7e6 c2c4 g8f6 g2g3", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 e7e6 c1g5", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 g1f3 g8f6 c2c4 c7c6 e2e3", + "d2d4 d7d5 g1f3 g8f6 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 b8d7", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c5", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c6 c1g5", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8b4", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 c1g5", + "d2d4 d7d5 g1f3 g8f6 c2c4 e7e6 g2g3", + "d2d4 d7d6 e2e4 g7g6", + "d2d4 d7d6 e2e4 g8f6 b1c3 g7g6 f2f4 f8g7 g1f3", + "d2d4 e7e6 c2c4 b7b6 g1f3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 c1g5 f8e7 e2e3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 c4d5 e6d5 c1g5", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 b8d7", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c5", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c6 c1g5", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8b4", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8e7 c1f4 e8g8 e2e3", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 e7e6 c2c4 g8f6 b1c3 d7d5 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 d1c2 e8g8", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 e2e3 b7b6", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 e2e3 c7c5 f1d3", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 e2e3 e8g8 f1d3 d7d5 g1f3", + "d2d4 e7e6 c2c4 g8f6 b1c3 f8b4 g1f3", + "d2d4 e7e6 c2c4 g8f6 c1g5 f8b4", + "d2d4 e7e6 c2c4 g8f6 c1g5 h7h6", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 b1c3 f8b4", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "d2d4 e7e6 c2c4 g8f6 g1f3 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "d2d4 e7e6 c2c4 g8f6 g1f3 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 b8d7", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c5", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c6 c1g5", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8b4", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 c1g5", + "d2d4 e7e6 c2c4 g8f6 g1f3 d7d5 g2g3", + "d2d4 e7e6 c2c4 g8f6 g1f3 f8b4 b1d2", + "d2d4 e7e6 c2c4 g8f6 g1f3 f8b4 c1d2", + "d2d4 e7e6 c2c4 g8f6 g2g3 d7d5 f1g2", + "d2d4 e7e6 e2e4 d7d5 b1c3 f8b4 e4e5 c7c5 a2a3 b4c3", + "d2d4 e7e6 e2e4 d7d5 b1d2 c7c5 g1f3", + "d2d4 e7e6 e2e4 d7d5 b1d2 g8f6 e4e5 f6d7 f1d3 c7c5 c2c3 b8c6 g1e2 ", + "d2d4 g8f6 c1g5 f6e4 g5f4 c7c5 f2f3 d8a5 c2c3 e4f6 d4d5 a5b6", + "d2d4 g8f6 c2c4 c7c5 d4d5 b7b5 c4b5 a7a6", + "d2d4 g8f6 c2c4 c7c5 d4d5 e7e6 b1c3 e6d5 c4d5 d7d6", + "d2d4 g8f6 c2c4 d7d6 b1c3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 c1g5 f8e7 e2e3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 c4d5 e6d5 c1g5", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 b8d7", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c5", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c6 c1g5", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8b4", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 c2c4 e7e6 b1c3 d7d5 g1f3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 d1c2 e8g8", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 e2e3 b7b6", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 e2e3 c7c5 f1d3", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 e2e3 e8g8 f1d3 d7d5 g1f3", + "d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 g1f3", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 b1c3 f8b4", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "d2d4 g8f6 c2c4 e7e6 g1f3 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "d2d4 g8f6 c2c4 e7e6 g1f3 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 b8d7", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c5", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c6 c1g5", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8b4", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 c1g5", + "d2d4 g8f6 c2c4 e7e6 g1f3 d7d5 g2g3", + "d2d4 g8f6 c2c4 e7e6 g1f3 f8b4 b1d2", + "d2d4 g8f6 c2c4 e7e6 g1f3 f8b4 c1d2", + "d2d4 g8f6 c2c4 e7e6 g2g3 d7d5 f1g2", + "d2d4 g8f6 c2c4 g7g6 b1c3 d7d5 c4d5 f6d5 e2e4 d5c3 b2c3 f8g7 f1c4", + "d2d4 g8f6 c2c4 g7g6 b1c3 d7d5 g1f3 f8g7 d1b3 d5c4 b3c4", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 f1e2 e8g8 c1g5", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 f1e2 e8g8 g1f3 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 f2f3 e8g8 c1e3", + "d2d4 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4 d7d6 g1f3 e8g8 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 c2c4 g7g6 g1f3 f8g7 b1c3 e8g8 e2e4 d7d6 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 c2c4 g7g6 g1f3 f8g7 g2g3 e8g8 f1g2 d7d6 e1g1", + "d2d4 g8f6 c2c4 g7g6 g2g3 f8g7 f1g2 e8g8", + "d2d4 g8f6 g1f3 c7c5", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 e7e6 c1g5", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 g1f3 d7d5 c2c4 c7c6 e2e3", + "d2d4 g8f6 g1f3 d7d5 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 b8d7", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c5", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c6 c1g5", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8b4", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 c1g5", + "d2d4 g8f6 g1f3 d7d5 c2c4 e7e6 g2g3", + "d2d4 g8f6 g1f3 e7e6 c1g5", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 b1c3 f8b4", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "d2d4 g8f6 g1f3 e7e6 c2c4 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "d2d4 g8f6 g1f3 e7e6 c2c4 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 b8d7", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c5", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c6 c1g5", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8b4", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 c1g5", + "d2d4 g8f6 g1f3 e7e6 c2c4 d7d5 g2g3", + "d2d4 g8f6 g1f3 e7e6 c2c4 f8b4 b1d2", + "d2d4 g8f6 g1f3 e7e6 c2c4 f8b4 c1d2", + "d2d4 g8f6 g1f3 e7e6 g2g3", + "d2d4 g8f6 g1f3 g7g6 c1g5", + "d2d4 g8f6 g1f3 g7g6 c2c4 f8g7 b1c3 e8g8 e2e4 d7d6 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "d2d4 g8f6 g1f3 g7g6 c2c4 f8g7 g2g3 e8g8 f1g2 d7d6 e1g1", + "d2d4 g8f6 g1f3 g7g6 g2g3 f8g7 f1g2 e8g8", + "e2e4 c7c5 b1c3 b8c6 g2g3 g7g6 f1g2 f8g7", + "e2e4 c7c5 c2c3 d7d6 g1f3 g8f6", + "e2e4 c7c5 c2c3 g8f6 e4e5 f6d5 d2d4 c5d4 g1f3 ", + "e2e4 c7c5 c2c3 g8f6 e4e5 f6d5 g1f3", + "e2e4 c7c5 d2d3 g8f6", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 e7e6 b1c3 a7a6", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 e7e6 b1c3 d8c7", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g7g6 b1c3 f8g7 c1e3 g8f6 f1c4", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g7g6 c2c4 f8g7 f1d3 g8f6 b1c3 ", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 c1g5 e7e6 d1d2 a7a6 e1c1 h7h6", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 c1g5 e7e6 d1d2 f8e7 e1c1 e8g8", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 f1c4", + "e2e4 c7c5 g1f3 b8c6 d2d4 c5d4 f3d4 g8f6 b1c3 e7e5 d4b5 d7d6", + "e2e4 c7c5 g1f3 b8c6 f1b5", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 c1e3", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 c1g5 e7e6 f2f4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 f1e2 e7e5 d4b3 f8e7", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 a7a6 f2f4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 b8c6 c1g5 e7e6 d1d2 a7a6 e1c1 h7h6", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 b8c6 c1g5 e7e6 d1d2 f8e7 e1c1 e8g8", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 b8c6 f1c4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 e7e6 f1e2", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 e7e6 g2g4", + "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4 f3d4 g8f6 b1c3 g7g6 c1e3 f8g7 f2f3", + "e2e4 c7c5 g1f3 d7d6 f1b5 b8d7", + "e2e4 c7c5 g1f3 d7d6 f1b5 c8d7 b5d7", + "e2e4 c7c5 g1f3 e7e6 b1c3", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 a7a6 f1d3", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 b8c6 b1c3 a7a6", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 b8c6 b1c3 d8c7", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 f1e2", + "e2e4 c7c5 g1f3 e7e6 d2d4 c5d4 f3d4 g8f6 b1c3 d7d6 g2g4", + "e2e4 c7c6 c2c4 d7d5", + "e2e4 c7c6 d2d4 d7d5 b1c3 d5e4 c3e4 b8d7", + "e2e4 c7c6 d2d4 d7d5 b1c3 d5e4 c3e4 c8f5 e4g3 f5g6 h2h4 h7h6", + "e2e4 c7c6 d2d4 d7d5 b1d2 d5e4 d2e4 b8d7", + "e2e4 c7c6 d2d4 d7d5 b1d2 d5e4 d2e4 c8f5 e4g3 f5g6 h2h4 h7h6", + "e2e4 c7c6 d2d4 d7d5 e4d5 c6d5 c2c4 g8f6 b1c3 e7e6 g1f3", + "e2e4 c7c6 d2d4 d7d5 e4e5 c8f5", + "e2e4 c7c6 b1c3 d7d5 d2d4 d5e4 c3e4 c8f5 e4g3 f5g6 h2h4 h7h6", + "e2e4 c7c6 b1c3 d7d5 g1f3 c8g4 h2h3 g4f3 d1f3 e7e6", + "e2e4 c7c6 b1c3 d7d5 g1f3 d5e4 c3e4 g8f6", + "e2e4 c7c6 g1f3 d7d5 b1c3", + "e2e4 d7d6 d2d4 g7g6", + "e2e4 d7d6 d2d4 g8f6 b1c3 g7g6 f2f4 f8g7 g1f3", + "e2e4 e7e5 b1c3 g8f6 g1f3 b8c6", + "e2e4 e7e5 g1f3 b8c6 b1c3 g8f6 f1b5", + "e2e4 e7e5 g1f3 b8c6 d2d4 e5d4 f3d4", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 d7d6", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f6e4 d2d4 b7b5 a4b3 d7d5 d4e5 c8e6 c2c3", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 d7d6 c2c3 e8g8 h2h3 c6a5 b3c2 c7c5 d2d4 d8c7 b1d2", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 d7d6 c2c3 e8g8 h2h3 c6b8 d2d4 b8d7", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 d7d6 c2c3 e8g8 h2h3 c8b7 d2d4 f8e8", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 e8g8 c2c3 d7d6 h2h3 c6a5 b3c2 c7c5 d2d4 d8c7 b1d2", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 e8g8 c2c3 d7d6 h2h3 c6b8 d2d4 b8d7", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5a4 g8f6 e1g1 f8e7 f1e1 b7b5 a4b3 e8g8 c2c3 d7d6 h2h3 c8b7 d2d4 f8e8", + "e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5c6 d7c6 e1g1", + "e2e4 e7e5 g1f3 b8c6 f1b5 g8f6 e1g1", + "e2e4 e7e5 g1f3 b8c6 f1c4 f8c5", + "e2e4 e7e5 g1f3 b8c6 f1c4 g8f6", + "e2e4 e7e5 g1f3 g8f6 f3e5 d7d6 e5f3 f6e4 d2d4", + "e2e4 e7e6 d2d4 d7d5 b1c3 f8b4 e4e5 c7c5 a2a3 b4c3 b2c3 g8e7", + "e2e4 e7e6 d2d4 d7d5 b1c3 g8f6 c1g5", + "e2e4 e7e6 d2d4 d7d5 b1d2 c7c5 e4d5 e6d5", + "e2e4 e7e6 d2d4 d7d5 b1d2 c7c5 g1f3", + "e2e4 e7e6 d2d4 d7d5 b1d2 g8f6 e4e5", + "e2e4 e7e6 d2d4 d7d5 e4e5 c7c5 c2c3 b8c6 g1f3 d8b6 a2a3 ", + "e2e4 e7e6 d2d4 d7d5 e4e5 c7c5 c2c3 d8b6 g1f3 b8c6 a2a3", + "e2e4 g7g6 d2d4 f8g7 b1c3 c7c6 g1f3", + "e2e4 g7g6 d2d4 f8g7 b1c3 d7d6 c1e3", + "e2e4 g7g6 d2d4 f8g7 b1c3 d7d6 g1f3", + "e2e4 g8f6 e4e5 f6d5 c2c4 d5b6 d2d4 d7d6 e5d6 e7d6", + "e2e4 g8f6 e4e5 f6d5 d2d4 d7d6 g1f3", + "g1f3 c7c5 c2c4 b8c6", + "g1f3 c7c5 c2c4 g8f6 b1c3 b8c6", + "g1f3 c7c5 c2c4 g8f6 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "g1f3 c7c5 c2c4 g8f6 g2g3", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 e7e6 c1g5", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 d7d5 d2d4 g8f6 c2c4 c7c6 e2e3", + "g1f3 d7d5 d2d4 g8f6 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 b8d7", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c5", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c6 c1g5", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8b4", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 c1g5", + "g1f3 d7d5 d2d4 g8f6 c2c4 e7e6 g2g3", + "g1f3 d7d5 g2g3", + "g1f3 g8f6 c2c4 b7b6 g2g3", + "g1f3 g8f6 c2c4 c7c5 b1c3 b8c6", + "g1f3 g8f6 c2c4 c7c5 b1c3 e7e6 g2g3 b7b6 f1g2 c8b7 e1g1 f8e7", + "g1f3 g8f6 c2c4 c7c5 g2g3", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 b8d7", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c5", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c6 c1g5", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8b4", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 c1f4 e8g8 e2e3", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 g8f6 c2c4 e7e6 b1c3 d7d5 d2d4 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 g8f6 c2c4 e7e6 g2g3 d7d5 f1g2 f8e7", + "g1f3 g8f6 c2c4 g7g6 b1c3 f8g7 e2e4", + "g1f3 g8f6 c2c4 g7g6 g2g3 f8g7 f1g2 e8g8", + "g1f3 g8f6 d2d4 c7c5", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 d5c4 a2a4 c8f5 e2e3 e7e6 f1c4", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 e7e6 c1g5", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 b1c3 e7e6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 d2d4 d7d5 c2c4 c7c6 e2e3", + "g1f3 g8f6 d2d4 d7d5 c2c4 d5c4 e2e3 e7e6 f1c4 c7c5 e1g1 a7a6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 b8d7", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c5", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c6 c1g5", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8b4", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 c1f4 e8g8 e2e3", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 c1g5", + "g1f3 g8f6 d2d4 d7d5 c2c4 e7e6 g2g3", + "g1f3 g8f6 d2d4 e7e6 c1g5", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 a2a3 c8b7 b1c3 d7d5 c4d5 f6d5", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 b1c3 c8b7 a2a3 d7d5 c4d5 f6d5", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 b1c3 f8b4", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 g2g3 c8a6 b2b3 f8b4 c1d2 b4e7", + "g1f3 g8f6 d2d4 e7e6 c2c4 b7b6 g2g3 c8b7 f1g2 f8e7 e1g1 e8g8 b1c3 f6e4 d1c2 e4c3 c2c3", + "g1f3 g8f6 d2d4 e7e6 c2c4 c7c5 d4d5 e6d5 c4d5 d7d6 b1c3 g7g6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 b8d7", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c5", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c6 c1g5", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 d1c2 f8d6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 c7c6 e2e3 b8d7 f1d3 d5c4 d3c4 b7b5 c4d3", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8b4", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8e7 c1f4 e8g8 e2e3", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 e8g8 e2e3 h7h6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 b1c3 f8e7 c1g5 h7h6 g5h4 e8g8 e2e3 b7b6", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 c1g5", + "g1f3 g8f6 d2d4 e7e6 c2c4 d7d5 g2g3", + "g1f3 g8f6 d2d4 e7e6 c2c4 f8b4 b1d2", + "g1f3 g8f6 d2d4 e7e6 c2c4 f8b4 c1d2", + "g1f3 g8f6 d2d4 e7e6 g2g3", + "g1f3 g8f6 d2d4 g7g6 c1g5", + "g1f3 g8f6 d2d4 g7g6 c2c4 f8g7 b1c3 e8g8 e2e4 d7d6 f1e2 e7e5 e1g1 b8c6 d4d5 c6e7 f3e1 f6d7", + "g1f3 g8f6 d2d4 g7g6 c2c4 f8g7 g2g3 e8g8 f1g2 d7d6 e1g1", + "g1f3 g8f6 d2d4 g7g6 g2g3 f8g7 f1g2 e8g8", + "g1f3 g8f6 g2g3 g7g6", +}; + +// Returns bool. If true, then book[start] to book[end-1] inclusive will +// match line. So end-start is the number of matching lines. +int book_range(char *line, int *startp, int *endp) +{ + unsigned int start, end; + if (ARRAY_SIZE(book) == 0) return 0; // no book?? + /* Find start. */ + for (start = 0; start < ARRAY_SIZE(book); start++) { + int result = strncmp(book[start], line, strlen(line)); + if (result < 0) + continue; // not yet + else if (result > 0) + break; // line not in book at all + // OK, found start. + for (end = start + 1; end < ARRAY_SIZE(book); end++) { + int result = strncmp(book[end], line, strlen(line)); + if (result > 0) + break; + else + assert(result == 0 && "opening book not sorted :("); + } + // Found end. + *startp = start; + *endp = end; + return 1; + } + return 0; // line not found +} + +int book_enabled = 1; + +/** + * Get a move from the book. Line is a string like "e2e4 e7e5 g1f3 " - note + * the space at the end! and the board is for passing to move_islegal. + */ +move_t book_move(char *line, board_t *board) +{ + int start, end; + if (!book_enabled) return 0; + if (book_range(line, &start, &end)) { + char book_move_str[BOOK_MOVE_LENGTH+1]; + move_t book_move; + unsigned long move_index; + static int rand_inited = 0; + char *errmsg; + if (!rand_inited) { + sgenrand((unsigned long)get_ticks()); + rand_inited = 1; + } + assert(end - start > 0); + move_index = (genrand() % (end-start)) + start; + strncpy(book_move_str, &book[move_index][strlen(line)], + BOOK_MOVE_LENGTH); + book_move_str[BOOK_MOVE_LENGTH] = 0; + book_move = move_islegal(board, book_move_str, &errmsg); + if (!book_move) { + set_cursor_pos(0,0); + printf("BUG: please email bblum@cs.cmu.edu the following: \n"); + printf("Line: \"%s\"\n", line); + printf("Attempted book line: \"%s\"\n", book[move_index]); + printf("Attempted move: \"%s\"\n", book_move_str); + assert(0 && "Illegal line in opening book?"); + } + return book_move; + } else { + return 0; + } +} +/**************************************************************************** + * engine.c - wrapper functions for managing computer vs human play + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +#define ENGINE_REPEATED_BUCKETS 127 + +/* from xboard.c, for printing */ +// void output(char *); + +/** + * Initialize a game engine given the searching function, with a new board + */ +engine_t *engine_init(search_fn search) +{ + engine_t *e = malloc(sizeof(engine_t)); + affirm_msg(e, "Couldn't allocate game engine"); + e->board = board_init(); + e->search = search; + e->line[0] = '\0'; + e->line_moves = 0; + e->inbook = 1; + return e; +} + +#define SEARCHTIME_DEFAULT 5 +#define SEARCHTIME_MAX 60 +unsigned int searchtime = SEARCHTIME_DEFAULT; + +extern int outbuf_size; +extern int text_loud; +extern char outbuf[]; +void output(); + +/** + * Have the engine generate a move for the side to play. String must be freed. + */ +char *engine_generatemove(engine_t *e) +{ + if (e->inbook) + { + move_t move = book_move(e->line, e->board); + if (move) + { + /* book lookup was successful */ + // output("ENGINE: Book lookup successful"); + char *str = move_tostring(move); + if (text_loud) { + snprintf(outbuf, outbuf_size, + "My move: %s (from opening book)", str); + output(); + } + return str; + } + else + { + /* we've left the book lines */ + // output("ENGINE: Leaving opening book lines"); + e->inbook = 0; + } + } + /* we get here if already out of book or if we just left book */ + return move_tostring(e->search(e->board, searchtime, NULL, NULL)); +} + +/** + * Change the board to reflect a move being made. Returns 1 if the move is + * illegal, 0 if it's good + */ +int engine_applymove(engine_t *e, char *str, char **errmsg) +{ + /* we need to make the move before adding, else we won't detect draws + * before they actually are called */ + move_t move = move_islegal(e->board, str, errmsg); + if (move == 0) { + return 0; + } + /* keep track of the game's line, but only if not too long */ + if (strlen(e->line) < BOOK_LINE_MAX_LENGTH-6) { + strcat(e->line, str); + strcat(e->line, " "); + assert(e->line_moves == e->board->moves); + e->line_moves++; + } + + board_applymove(e->board, move); + + return 1; +} + +void engine_undomove(engine_t *e) +{ + assert(e->board->moves > 0); + if (e->line_moves == e->board->moves) { + int i = strlen(e->line)-1; + assert(i > 0); + assert(e->line[i] == ' '); + if (e->line_moves == 1) { + e->line[0] = 0; + } else { + for (i--; i > 0 && e->line[i] != ' '; i--) { continue; } + assert(i > 0); + e->line[i+1] = 0; + } + e->line_moves--; + } + e->inbook = 1; // Not necessarily true. But it can't hurt. + board_undomove(e->board, e->board->history[e->board->moves-1].move); +} + +void engine_destroy(engine_t *e) +{ + if (e == NULL) + { + return; + } + board_destroy(e->board); + free(e); + return; +} +/**************************************************************************** + * eval.c - evaluation function to tell how good a position is + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* endgame starts when both sides have <= LIM_ENDGAME */ +#define EVAL_LIM_ENDGAME 1600 +/* use this limit when no queens on the board */ +#define EVAL_LIM_ENDGAME2 2000 + +#define EVAL_CASTLE_BONUS 20 + +int16_t eval_piecevalue[6] = { 100, 300, 300, 500, 900, 0 }; +int16_t eval_piecevalue_endgame[6] = { 125, 300, 300, 550, 1200, 0 }; + +/* Players get small point bonuses if their pieces are on good squares. If + * white has a rook on d1, squarevalue[WHITE][ROOK][D1] will be added to + * white's score. */ +/* Differences between src/dest squares are considered when ordering moves, so + * it is important that for any legal (src,dest) pair, abs(sqval(dest) - + * sqval(src)) <= SOME_CONSTANT - that constant is 16 for now. (only in the + * regular tables, not the endgame tables) */ +int16_t eval_squarevalue[2][6][64] = { + /******************************************************************** + * WHITE + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -4, -4, 4, 0, 0, + 6, 2, 3, 4, 4, 3, 2, 8, + 3, 4, 12, 12, 12, 8, 4, 3, + 5, 8, 16, 20, 20, 16, 8, 5, + 20, 24, 24, 32, 32, 24, 24, 20, + 36, 36, 40, 40, 40, 40, 36, 36, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -6, -6, -6, -6, -6, -6,-10, + -6, 0, 0, 3, 3, 0, 0, -6, + -6, 0, 8, 4, 4, 10, 0, -6, + -6, 0, 8, 10, 10, 8, 0, -6, + -4, 0, 8, 10, 10, 8, 0, -4, + -4, 5, 12, 12, 12, 12, 5, -4, + -4, 0, 5, 3, 3, 5, 0, -4, + -10, -4, -4, -4, -4, -4, -4,-10 + }, + /* BISHOP */ + { + -6, -5, -5, -5, -5, -5, -5, -6, + -5, 10, 5, 8, 8, 5, 10, -5, + -5, 5, 3, 5, 5, 3, 5, -5, + -5, 3, 10, 3, 3, 10, 3, -5, + -5, 5, 10, 3, 3, 10, 5, -5, + -5, 3, 8, 8, 8, 8, 3, -5, + -5, 5, 5, 8, 8, 5, 5, -5, + -6, -5, -5, -5, -5, -5, -5, -6 + }, + /* ROOK */ + { + 0, 3, 3, 3, 3, 3, 3, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 2, 2, 2, 1, 0, + 3, 5, 8, 8, 8, 8, 5, 3, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + 5, 5, 8, 0, 0, -5, 10, 10, + 0, 0, 0, 0, 0, 0, 5, 5, + 0, 0, 0, -5, -5, 0, 0, 0, + 0, 0, -5,-10,-10, -5, 0, 0, + 0, -5,-10,-10,-10,-10, -5, 0, + -5,-10,-10,-15,-15,-10,-10, -5, + -20,-20,-20,-20,-20,-20,-20,-20, + -20,-20,-20,-20,-20,-20,-20,-20 + } + }, + /******************************************************************** + * BLACK + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 36, 40, 40, 40, 40, 36, 36, + 20, 24, 24, 32, 32, 24, 24, 20, + 5, 8, 16, 20, 20, 16, 8, 5, + 3, 4, 12, 12, 12, 8, 4, 3, + 6, 2, 3, 4, 4, 3, 2, 8, + 0, 0, 0, -4, -4, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -4, -4, -4, -4, -4, -4,-10, + -4, 0, 5, 3, 3, 5, 0, -4, + -4, 5, 12, 12, 12, 12, 5, -4, + -4, 0, 8, 10, 10, 8, 0, -4, + -6, 0, 8, 10, 10, 8, 0, -6, + -6, 0, 8, 4, 4, 10, 0, -6, + -6, 0, 0, 3, 3, 0, 0, -6, + -10, -6, -6, -6, -6, -6, -6,-10 + }, + /* BISHOP */ + { + -6, -5, -5, -5, -5, -5, -5, -6, + -5, 5, 5, 8, 8, 5, 5, -5, + -5, 5, 8, 8, 8, 8, 5, -5, + -5, 3, 10, 5, 5, 10, 3, -5, + -5, 5, 10, 5, 5, 10, 5, -5, + -5, 3, 3, 5, 5, 3, 3, -5, + -5, 10, 5, 8, 8, 5, 10, -5, + -6, -5, -5, -5, -5, -5, -5, -6 + }, + /* ROOK */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 5, 8, 8, 8, 8, 5, 3, + 0, 1, 2, 2, 2, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 3, 3, 3, 3, 3, 3, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + -20,-20,-20,-20,-20,-20,-20,-20, + -20,-20,-20,-20,-20,-20,-20,-20, + -5,-10,-10,-15,-15,-10,-10, -5, + 0, -5,-10,-10,-10,-10, -5, 0, + 0, 0, -5,-10,-10, -5, 0, 0, + 0, 0, 0, -5, -5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5, 8, 0, 0, -5, 10, 10 + } + } +}; +int16_t eval_squarevalue_endgame[2][6][64] = { + /******************************************************************** + * WHITE + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + -10,-10,-10,-10,-10,-10,-10,-10, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 20, 20, 20, 20, 20, 20, 20, 20, + 40, 40, 40, 40, 40, 40, 40, 40, + 80, 80, 80, 80, 80, 80, 80, 80, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -5, -5, -5, -5, -5, -5,-10, + -8, 0, 0, 3, 3, 0, 0, -8, + -8, 0, 10, 8, 8, 10, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 12, 12, 12, 12, 0, -8, + -8, 0, 9, 3, 3, 9, 0, -8, + -10, -5, -5, -5, -5, -5, -5,-10 + }, + /* BISHOP */ + { + -8, -5, -5, -5, -5, -5, -5, -8, + -5, 3, 5, 5, 5, 5, 3, -5, + -5, 5, 5, 8, 8, 5, 5, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 3, 8, 8, 8, 8, 3, -5, + -5, 3, 5, 8, 8, 5, 3, -5, + -8, -5, -5, -5, -5, -5, -5, -8 + }, + /* ROOK */ + { + 0, 3, 3, 5, 5, 3, 3, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 2, 2, 2, 1, 0, + 1, 3, 5, 5, 5, 5, 3, 1, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + -25,-15,-10,-10,-10,-10,-15,-25, + -15, -5, 0, 0, 0, 0, -5,-15, + -10, 0, 5, 10, 10, 5, 0,-10, + -10, 0, 10, 15, 15, 10, 0,-10, + -5, 5, 15, 20, 20, 15, 5, -5, + 0, 10, 20, 20, 20, 15, 10, 0, + -15, 0, 5, 5, 5, 5, 0,-15, + -25,-15,-10,-10,-10,-10,-15,-25 + } + }, + /******************************************************************** + * BLACK + ********************************************************************/ + { + /* PAWN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 80, 80, 80, 80, 80, 80, 80, + 40, 40, 40, 40, 40, 40, 40, 40, + 20, 20, 20, 20, 20, 20, 20, 20, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + -10,-10,-10,-10,-10,-10,-10,-10, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KNIGHT */ + { + -10, -5, -5, -5, -5, -5, -5,-10, + -8, 0, 9, 3, 3, 9, 0, -8, + -8, 0, 12, 12, 12, 12, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 8, 10, 10, 8, 0, -8, + -8, 0, 10, 8, 8, 10, 0, -8, + -8, 0, 0, 3, 3, 0, 0, -8, + -10, -5, -5, -5, -5, -5, -5,-10 + }, + /* BISHOP */ + { + -8, -5, -5, -5, -5, -5, -5, -8, + -5, 3, 5, 8, 8, 5, 3, -5, + -5, 3, 8, 8, 8, 8, 3, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 5, 10, 10, 10, 10, 5, -5, + -5, 5, 5, 8, 8, 5, 5, -5, + -5, 3, 5, 5, 5, 5, 3, -5, + -8, -5, -5, -5, -5, -5, -5, -8 + }, + /* ROOK */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 3, 5, 5, 5, 5, 3, 1, + 0, 1, 2, 2, 2, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 1, 2, 3, 3, 2, 1, 0, + 0, 3, 3, 5, 5, 3, 3, 0 + }, + /* QUEEN */ + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* KING */ + { + -25,-15,-10,-10,-10,-10,-15,-25 + -15, 0, 5, 5, 5, 5, 0,-15, + 0, 10, 20, 20, 20, 15, 10, 0, + -5, 5, 15, 20, 20, 15, 5, -5, + -10, 0, 10, 15, 15, 10, 0,-10, + -10, 0, 5, 10, 10, 5, 0,-10, + -15, -5, 0, 0, 0, 0, -5,-15, + -25,-15,-10,-10,-10,-10,-15,-25, + } + } +}; + +static int16_t eval_endgame(board_t *); + +/* Penalty for trapping the d- e- pawns on 2nd rank, or c-pawn with the knight + * if there's a pawn on d4 and no pawn on e4 */ +#define EVAL_BLOCKED_PAWN -25 +/* used for pawn-block checking N on c3 with pawns c2 d4 !e4 */ +#define BB_C2D4 (BB_SQUARE(C2) | BB_SQUARE(D4)) +#define BB_C2D4E4 (BB_C2D4 | BB_SQUARE(E4)) +#define BB_C7D5 (BB_SQUARE(C7) | BB_SQUARE(D5)) +#define BB_C7D5E5 (BB_C7D5 | BB_SQUARE(E5)) +/* reward the bishop pair and penalize the knight pair */ +#define EVAL_BISHOP_PAIR 20 +#define EVAL_KNIGHT_PAIR -20 +/* Rooks like to see towards the other end of the board */ +#define EVAL_ROOK_OPENFILE 10 +#define EVAL_ROOK_OPENFILE_MULTIPLIER 3 +/* bonus for having multiple rooks on the 7th - take the number of heavies + * on the 7th, leftshift this constant by that number */ +#define EVAL_ROOK_RANK7_MULTIPLIER 12 +/* bonus for having a minor piece on an "outpost" - a hole in the opp's pawn + * structure protected by one of own pawns. */ +#define EVAL_OUTPOST_BONUS 32 + +/************** + * King safety + **************/ +/* Points for having N pawns on rank 2/3 in front of a castled king*/ +static int16_t pawncover_rank2[4] = { -80, -40, 0, 5 }; +static int16_t pawncover_rank3[4] = { 0, 5, 20, 40 }; +/* penalty for having no pawns on king's file */ +#define EVAL_KINGFILEOPEN -35 +/* penalty for having no pawns on file adjacent to king's file */ +#define EVAL_ADJACENTFILEOPEN -15 + +/* tropism bonus from one square to another (one square has a piece of given + * type on it, the other has the enemy king) */ +#define EVAL_TROPISM_MAX 192 +/* this lookup array gives shiftamounts for distance so we don't have to idiv + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 */ +static int tropism_rice[15] = { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5}; +/* this lookup array gives shiftamounts for scaling by piece value + * P N B R Q K */ +static int tropism_piecescale[6] = { 3, 2, 2, 1, 0, 0 }; + +static int16_t tropism(square_t a, square_t b, piece_t piece) +{ + int16_t rowdist, coldist; + /* absolute values of the difference between the two squares */ + rowdist = ROW(a) - ROW(b); + if (rowdist < 0) { rowdist = -rowdist; } + coldist = COL(a) - COL(b); + if (coldist < 0) { coldist = -coldist; } + /* score inversely proportional to distance, also scaled by how + * heavy the piece is - queen right up against the opp king will + * get like 100 points */ + return (EVAL_TROPISM_MAX >> tropism_rice[rowdist + coldist]) >> + tropism_piecescale[piece]; +} + +int eval_isendgame(board_t *board) +{ + if (board->pos[WHITE][QUEEN] | board->pos[BLACK][QUEEN]) + { + return (board->material[WHITE] <= EVAL_LIM_ENDGAME) || + (board->material[BLACK] <= EVAL_LIM_ENDGAME); + } + return (board->material[WHITE] <= EVAL_LIM_ENDGAME2) || + (board->material[BLACK] <= EVAL_LIM_ENDGAME2); +} + +/** + * Evaluate - return a score for the given position for who's to move + */ +int16_t eval(board_t *board) +{ + int piece, square; + bitboard_t piecepos; + /* keeps track of {WHITE,BLACK}s score */ + int16_t score_white, score_black; + /* king safety scores - scaled by the material on the board to + * encourage trading when under attack */ + int16_t ksafety_white, ksafety_black; + square_t kingsq_white, kingsq_black; /* where's each king */ + /* counting pieces/pawns for king safety */ + int num_pieces; + /* holes in 's pawnstructure */ + bitboard_t holes_white, holes_black; + + /* use the special endgame evaluator if in the endgame */ + if (eval_isendgame(board)) + { + return eval_endgame(board); + } + + /* begin evaluating */ + score_white = 0; score_black = 0; + ksafety_white = 0; ksafety_black = 0; + kingsq_white = BITSCAN(board->pos[WHITE][KING]); + kingsq_black = BITSCAN(board->pos[BLACK][KING]); + + /******************************************************************** + * Piece/square tables + ********************************************************************/ + /******** + * White + ********/ + /* regular pieces - pawns taken care of in pawnstructure eval */ + for (piece = 1; piece < 5; piece++) + { + piecepos = board->pos[WHITE][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_white += eval_squarevalue[WHITE][piece][square]; + /* tropism scores - how close is to our/opp king? */ + //ksafety_white += tropism(square, kingsq_white, piece); + ksafety_black -= tropism(square, kingsq_black, piece); + /* Rooks like open files */ + if (piece == ROOK) + { + /* no pawns on this file */ + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(square)))) + { + score_white += EVAL_ROOK_OPENFILE; + } + /* how far can we see? */ + score_white += EVAL_ROOK_OPENFILE_MULTIPLIER * POPCOUNT(colattacks[(board->occupied90 >> (8 * COL(square))) & 0xFF][ROW(square)]); + } + } + } + /* king */ + score_white += eval_squarevalue[WHITE][KING][kingsq_white]; + + /******** + * Black + ********/ + for (piece = 1; piece < 5; piece++) + { + piecepos = board->pos[BLACK][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_black += eval_squarevalue[BLACK][piece][square]; + /* tropism scores - how close is to our/opp king? */ + ksafety_white -= tropism(square, kingsq_white, piece); + //ksafety_black += tropism(square, kingsq_black, piece); + /* Rooks like open files */ + if (piece == ROOK) + { + /* no pawns on this file */ + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(square)))) + { + score_black += EVAL_ROOK_OPENFILE; + } + /* how far can we see? */ + score_black += EVAL_ROOK_OPENFILE_MULTIPLIER * POPCOUNT(colattacks[(board->occupied90 >> (8 * COL(square))) & 0xFF][ROW(square)]); + } + } + } + /* king */ + score_black += eval_squarevalue[BLACK][KING][kingsq_white]; + + /******************************************************************** + * Misc. bonuses + ********************************************************************/ + /* bishop/knight pair bonus/penalties */ + if (POPCOUNT(board->pos[WHITE][BISHOP]) > 1) { score_white += EVAL_BISHOP_PAIR; } + if (POPCOUNT(board->pos[WHITE][KNIGHT]) > 1) { score_white += EVAL_KNIGHT_PAIR; } + if (POPCOUNT(board->pos[BLACK][BISHOP]) > 1) { score_black += EVAL_BISHOP_PAIR; } + if (POPCOUNT(board->pos[BLACK][KNIGHT]) > 1) { score_black += EVAL_KNIGHT_PAIR; } + /* pawnstructure bonus */ + score_white += eval_pawnstructure(board, WHITE, &holes_white); + score_black += eval_pawnstructure(board, BLACK, &holes_black); + /* analysis of pawnstructure holes - all holes that our pawns attack + * and have a minor piece on them get an "outpost" bonus - don't allow + * bonus for outposts on the A and H files */ + /* find white's outposts */ + holes_black &= board_pawnattacks(board->pos[WHITE][PAWN], WHITE) & + (board->pos[WHITE][KNIGHT] | board->pos[WHITE][BISHOP]) & + ~(BB_FILEA | BB_FILEH); + score_white += EVAL_OUTPOST_BONUS * POPCOUNT(holes_black); + /* find black's outposts */ + holes_white &= board_pawnattacks(board->pos[BLACK][PAWN], BLACK) & + (board->pos[BLACK][KNIGHT] | board->pos[BLACK][BISHOP]) & + ~(BB_FILEA | BB_FILEH); + score_black += EVAL_OUTPOST_BONUS * POPCOUNT(holes_white); + /* pawn block penalties */ + if (((board->piecesofcolor[WHITE] ^ board->pos[WHITE][PAWN]) & BB_SQUARE(D3)) && + (board->pos[WHITE][PAWN] & BB_SQUARE(D2))) /* blocked on D2 */ + { + score_white += EVAL_BLOCKED_PAWN; + } + if (((board->piecesofcolor[WHITE] ^ board->pos[WHITE][PAWN]) & BB_SQUARE(E3)) && + (board->pos[WHITE][PAWN] & BB_SQUARE(E2))) /* blocked on E2 */ + { + score_white += EVAL_BLOCKED_PAWN; + } + if ((board->pos[WHITE][KNIGHT] & BB_SQUARE(C3)) && /* knight on C3 */ + !((board->pos[WHITE][PAWN] ^ BB_C2D4) & BB_C2D4E4)) /* "closed" opening */ + { + score_white += EVAL_BLOCKED_PAWN; + } + /* black */ + if (((board->piecesofcolor[BLACK] ^ board->pos[BLACK][PAWN]) & BB_SQUARE(D6)) && + (board->pos[BLACK][PAWN] & BB_SQUARE(D7))) /* blocked on D7 */ + { + score_black += EVAL_BLOCKED_PAWN; + } + if (((board->piecesofcolor[BLACK] ^ board->pos[BLACK][PAWN]) & BB_SQUARE(E6)) && + (board->pos[BLACK][PAWN] & BB_SQUARE(E7))) /* blocked on E7 */ + { + score_black += EVAL_BLOCKED_PAWN; + } + if ((board->pos[BLACK][KNIGHT] & BB_SQUARE(C6)) && /* knight on C6 */ + !((board->pos[BLACK][PAWN] ^ BB_C7D5) & BB_C7D5E5)) /* "closed" defense */ + { + score_black += EVAL_BLOCKED_PAWN; + } + /* rook/queen on the 7th bonus */ + score_white += EVAL_ROOK_RANK7_MULTIPLIER << + POPCOUNT((board->pos[WHITE][ROOK] | board->pos[WHITE][QUEEN]) & + BB_RANK7); + score_black += EVAL_ROOK_RANK7_MULTIPLIER << + POPCOUNT((board->pos[BLACK][ROOK] | board->pos[BLACK][QUEEN]) & + BB_RANK2); + + /******************************************************************** + * King safety - white + ********************************************************************/ + /* pawn shield */ + if (board->hascastled[WHITE]) + { + ksafety_white += EVAL_CASTLE_BONUS; + /* pawn shield one row in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_white] & + board->pos[WHITE][PAWN] & BB_RANK2); + ksafety_white += pawncover_rank2[num_pieces]; + /* pawn shield two rows in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_white + 8] & + board->pos[WHITE][PAWN] & BB_RANK3); + ksafety_white += pawncover_rank3[num_pieces]; + } + /* open files near the king */ + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(kingsq_white)))) + { + ksafety_white += EVAL_KINGFILEOPEN; + } + switch(COL(kingsq_white)) /* this idea taken from gnuchess */ + { + case COL_A: + case COL_E: + case COL_F: + case COL_G: + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(kingsq_white) + 1))) + { + ksafety_white += EVAL_ADJACENTFILEOPEN; + } + break; + case COL_H: + case COL_D: + case COL_C: + case COL_B: + if (!(board->pos[WHITE][PAWN] & BB_FILE(COL(kingsq_white) - 1))) + { + ksafety_white += EVAL_ADJACENTFILEOPEN; + } + break; + default: + break; + } + score_white += ksafety_white * board->material[BLACK] / 3100; + /******************************************************************** + * King safety - black + ********************************************************************/ + /* pawn shield */ + if (board->hascastled[BLACK]) + { + ksafety_black += EVAL_CASTLE_BONUS; + /* pawn shield one row in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_black] & + board->pos[BLACK][PAWN] & BB_RANK7); + ksafety_black += pawncover_rank2[num_pieces]; + /* pawn shield two rows in front of the king */ + num_pieces = POPCOUNT(kingattacks[kingsq_black - 8] & + board->pos[BLACK][PAWN] & BB_RANK6); + ksafety_black += pawncover_rank3[num_pieces]; + } + /* open files near the king */ + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(kingsq_black)))) + { + ksafety_black += EVAL_KINGFILEOPEN; + } + switch(COL(kingsq_black)) /* this idea taken from gnuchess */ + { + case COL_A: + case COL_E: + case COL_F: + case COL_G: + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(kingsq_black) + 1))) + { + ksafety_black += EVAL_ADJACENTFILEOPEN; + } + break; + case COL_H: + case COL_D: + case COL_C: + case COL_B: + if (!(board->pos[BLACK][PAWN] & BB_FILE(COL(kingsq_black) - 1))) + { + ksafety_black += EVAL_ADJACENTFILEOPEN; + } + break; + default: + break; + } + score_black += ksafety_black * board->material[WHITE] / 3100; + /******************************************************************** + * return the values + ********************************************************************/ + if (board->tomove == WHITE) + { + return (score_white + board->material[WHITE]) - + (score_black + board->material[BLACK]); + } + else + { + return (score_black + board->material[BLACK]) - + (score_white + board->material[WHITE]); + } +} + +/** + * Special-case endgame evaluator + */ +static int16_t eval_endgame(board_t *board) +{ + int piece, square; + bitboard_t piecepos; + /* keeps track of {WHITE,BLACK}s score */ + int16_t score_white = 0, score_black = 0; + int16_t difference = board->material[WHITE] - + board->material[BLACK]; + + /* draw evaluation - if no pawns are left, many possibilities + * note, our goal in this if block is to put the conditionals most + * likely to fail first, so we don't waste time saying "is the pawn's + * promotion square the opposite color of the bishop" when there's a + * queen on the board. */ + if (!(board->pos[WHITE][PAWN] | board->pos[BLACK][PAWN])) + { + /* absolute value */ + if (difference < 0) { difference = -difference; } + + /* a good heuristic to use is if the material difference is + * less than 400, the position is drawn */ + if (difference < 400) + { + return 0; + } + + /* KNN vs K */ + else if (difference == 600) + { + /* check if white has the two knights */ + if ((board->material[BLACK] == 0) && + (board->piecesofcolor[WHITE] == + (board->pos[WHITE][KING] | + board->pos[WHITE][KNIGHT]))) + { + return 0; + } + /* or black has the two knights */ + if ((board->material[WHITE] == 0) && + (board->piecesofcolor[BLACK] == + (board->pos[BLACK][KING] | + board->pos[BLACK][KNIGHT]))) + { + return 0; + } + /* here it must be a different piece configuration */ + } + } + /* KB + wrong color rook pawn vs K */ + else if (difference == 400) + { + /* first make sure it's KB rookpawn v K */ + if ((board->material[BLACK] == 0) && + (board->pos[WHITE][BISHOP] != BB(0x0)) && + (board->pos[WHITE][PAWN] & (COL_A | COL_H))) + { + square_t pawnsquare = BITSCAN(board->pos[WHITE][PAWN]); + square_t bishopsquare = BITSCAN(board->pos[WHITE][BISHOP]); + square_t promotionsquare = SQUARE(COL(pawnsquare),RANK_8); + /* check the square parities and also where's + * the enemy king */ + if ((PARITY(bishopsquare) != PARITY(promotionsquare)) && + (kingattacks[BITSCAN(board->pos[BLACK][KING])] & + BB_SQUARE(promotionsquare))) + { + return 0; + } + } + /* same thing for the other color */ + else if ((board->material[WHITE] == 0) && + (board->pos[BLACK][BISHOP] != BB(0x0)) && + (board->pos[BLACK][PAWN] & (COL_A | COL_H))) + { + square_t pawnsquare = BITSCAN(board->pos[BLACK][PAWN]); + square_t bishopsquare = BITSCAN(board->pos[BLACK][BISHOP]); + square_t promotionsquare = SQUARE(COL(pawnsquare),RANK_1); + /* check the square parities and also where's + * the enemy king */ + if ((PARITY(bishopsquare) != PARITY(promotionsquare)) && + (kingattacks[BITSCAN(board->pos[WHITE][KING])] & + BB_SQUARE(promotionsquare))) + { + return 0; + } + } + } + /* KP vs K - here we code just two cases, to facilitate the searcher; + * once we hit the back rank the searcher will see the draw itself. + * the first position is with the Ks in opposition with the pawn + * in between (either side to move, it's a draw); the second is + * with the pawn behind the winning king, in opposition (zugzwang) */ + else if (difference == 100) + { + /* white has the pawn */ + if (board->material[BLACK] == 0) + { + square_t whiteking = BITSCAN(board->pos[WHITE][KING]); + square_t blackking = BITSCAN(board->pos[BLACK][KING]); + square_t whitepawn = BITSCAN(board->pos[WHITE][PAWN]); + unsigned char pawncol = COL(whitepawn); + /* test for rook pawn draws */ + if (pawncol == COL_A || pawncol == COL_H) + { + /* if black king gets in front of the pawn, + * it's a draw no matter what */ + if ((COL(blackking) == pawncol) && + (blackking > whitepawn)) + { + return 0; + } + /* if the white king is in front of his pawn, + * but trapped by the black king, it'll end in + * stalemate */ + if (COL(whiteking) == pawncol) + { + if (pawncol == COL_A) + { + if (blackking - whiteking == 2) + { + return 0; + } + } + else /* pawncol == COL_H */ + { + if (whiteking - blackking == 2) + { + return 0; + } + } + } + } + if ((blackking - whiteking == 16) && + (ROW(blackking) != RANK_8)) + { + if (whitepawn - whiteking == 8) + { + return 0; + } + else if ((whiteking - whitepawn == 8) && + (board->tomove == WHITE)) + { + return 0; + } + } + } + /* black has the pawn */ + else if (board->material[WHITE] == 0) + { + square_t whiteking = BITSCAN(board->pos[WHITE][KING]); + square_t blackking = BITSCAN(board->pos[BLACK][KING]); + square_t blackpawn = BITSCAN(board->pos[BLACK][PAWN]); + unsigned char pawncol = COL(blackpawn); + /* test for rook pawn draws */ + if (pawncol == COL_A || pawncol == COL_H) + { + /* if black king gets in front of the pawn, + * it's a draw no matter what */ + if ((COL(whiteking) == pawncol) && + (whiteking < blackpawn)) + { + return 0; + } + /* if the white king is in front of his pawn, + * but trapped by the black king, it'll end in + * stalemate */ + if (COL(blackking) == pawncol) + { + if (pawncol == COL_A) + { + if (whiteking - blackking == 2) + { + return 0; + } + } + else /* pawncol == COL_H */ + { + if (blackking - whiteking== 2) + { + return 0; + } + } + } + } + if ((blackking - whiteking == 16) && + (ROW(whiteking) != RANK_1)) + { + if (blackking - blackpawn == 8) + { + return 0; + } + else if ((blackpawn - blackking == 8) && + (board->tomove == BLACK)) + { + return 0; + } + } + } + } + + /* calculate piece/square totals */ + for (piece = 0; piece < 6; piece++) + { + piecepos = board->pos[WHITE][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_white += eval_piecevalue_endgame[piece] + + eval_squarevalue_endgame[WHITE][piece][square]; + } + } + for (piece = 0; piece < 6; piece++) + { + piecepos = board->pos[BLACK][piece]; + while (piecepos) + { + square = BITSCAN(piecepos); + piecepos ^= BB_SQUARE(square); + score_black += eval_piecevalue_endgame[piece] + + eval_squarevalue_endgame[BLACK][piece][square]; + } + } + + /* return the values - we revalued the pieces to make pawns more + * important so board->material is inaccurate here */ + if (board->tomove == WHITE) + { + return score_white - score_black; + } + else + { + return score_black - score_white; + } +} + +/** + * Lazy evaluator + */ +int16_t eval_lazy(board_t *board) +{ + return board->material[board->tomove] - + board->material[OTHERCOLOR(board->tomove)]; +} +/**************************************************************************** + * movelist.c - data structure for move sorting in move generation/iteration + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ + +extern int16_t eval_squarevalue[2][6][64]; + +/* Material values, add/subtract to find indices for moves which change the + * material count */ +static uint8_t movelist_material[] = { 1, 3, 3, 5, 9, 12 }; + +/* arg 1 is the attacked boards, arg 2 is the move */ +static unsigned long movelist_findindex(uint64_t[2], uint32_t); + +/** + * Add a move. Determines where to add it using findindex + */ +void movelist_add(movelist_t *ml, uint64_t attackedby[2], uint32_t m) +{ + movelist_addtohead(ml, m, movelist_findindex(attackedby, m)); +} + +/** + * Determine at which index in the movelist a move should be added + */ +static unsigned long movelist_findindex(uint64_t attackedby[2], uint32_t m) +{ + int16_t materialgain; + /* which side has the move? this is a substitute for board->tomove */ + unsigned char tomove = MOV_COLOR(m); + + if (MOV_PROM(m)) + { + if (MOV_PROMPC(m) == QUEEN) + { + /* MOV_CAPT is 1 or 0 */ + return MOVELIST_INDEX_PROM_QUEEN + MOV_CAPT(m); + } + return MOVELIST_INDEX_PROM_MINOR; + } + if (MOV_CASTLE(m)) + { + /* The second term will be 1 if O-O, 0 if O-O-O */ + return MOVELIST_INDEX_CASTLE + (COL(MOV_DEST(m)) == COL_G); + } + if (MOV_CAPT(m)) + { + materialgain = movelist_material[MOV_CAPTPC(m)]; + /* see if the capturing piece will be recaptured - assume it + * will be if the opponent attacks that square at all */ + if (attackedby[OTHERCOLOR(tomove)] & BB_SQUARE(MOV_DEST(m))) + { + /* this will index past the end of the array if the + * moving piece is a king - we rely on the board + * library to filter out suicide king captures */ + materialgain -= movelist_material[MOV_PIECE(m)]; + /* neutral capture */ + if (materialgain == 0) + { + return MOVELIST_INDEX_NEUTRAL + MOV_PIECE(m); + } + //real SEE could be done here + } + /* losing material */ + else if (materialgain < 0) + { + return MOVELIST_INDEX_MAT_LOSS + materialgain; + } + /* winning capture */ + else + { + return MOVELIST_INDEX_MAT_GAIN + materialgain; + } + } + /* here it's a regular move */ + /* moving the piece where it can be captured */ + if (attackedby[OTHERCOLOR(tomove)] & BB_SQUARE(MOV_DEST(m))) + { + /* Moves that put the king in check are only generated if the + * attackedby bitmasks don't see it, so we won't fall apart on + * one either - they just get poor ordering, which is fine. */ + assert(MOV_PIECE(m) != KING); + /* if we can recapture after being captured */ + if (attackedby[tomove] & BB_SQUARE(MOV_DEST(m))) + { + /* if the moving piece is better than a pawn, call it + * a loss. otherwise, assume the pawn won't be taken + * (and fall through to the next phase). */ + if (MOV_PIECE(m) != PAWN) + { + /* give an "approximate" SEE - guessing, when + * we recapture we'll get between 1 and 3 */ + return MOVELIST_INDEX_MAT_LOSS + 2 - + movelist_material[MOV_PIECE(m)]; + } + //real SEE could be done here + } + /* if we move to a hanging square, we consider it complete + * loss of that piece */ + else + { + return MOVELIST_INDEX_MAT_LOSS - + movelist_material[MOV_PIECE(m)]; + } + } + /* here our piece is safe on its destination - let's see if we were + * saving it from being captured otherwise ("unhang"ing the piece); if + * so, it goes in the material gain category */ + if ((attackedby[OTHERCOLOR(tomove)] & ~(attackedby[tomove])) & + BB_SQUARE(MOV_SRC(m))) + { + return MOVELIST_INDEX_MAT_GAIN + + movelist_material[MOV_PIECE(m)]; + } + /* regular move */ + return MOVELIST_INDEX_REGULAR + + eval_squarevalue[tomove][MOV_PIECE(m)][MOV_DEST(m)] - + eval_squarevalue[tomove][MOV_PIECE(m)][MOV_SRC(m)]; +} + +void movelist_addtohead(movelist_t *mlp, uint32_t m, unsigned long index) +{ + movelist_inner_t *ml = *mlp; + /* sanity check */ + assert(index < MOVELIST_NUM_BUCKETS); + /* add to list */ + assert(ml->sublist_count[index] < MOVELIST_SUBLIST_LENGTH); + ml->array[index][ml->sublist_count[index]] = m; + ml->sublist_count[index]++; + + /* adjust max pointer */ + if (index > ml->max) + { + ml->max = index; + } + return; +} + +int movelist_isempty(movelist_t *mlp) +{ + movelist_inner_t *ml = *mlp; + return (ml->sublist_count[ml->max] == 0); +} + +/* Don't call this if movelist_isempty! */ +uint32_t movelist_remove_max(movelist_t *mlp) +{ + movelist_inner_t *ml = *mlp; + uint32_t returnval = ml->array[ml->max][--ml->sublist_count[ml->max]]; + /* check if we need to adjust the max pointer */ + while (movelist_isempty(mlp)) + { + /* we hit the bottom of the array; doesn't matter if empty */ + if (ml->max == 0) + { + break; + } + ml->max--; + } + return returnval; +} +/**************************************************************************** + * pawnstructure.c - evaluation helpers to judge pawn structure quality + * copyright (C) 2008 Ben Blum + * ****************************************************************************/ + +/* We do pawn square scoring here rather than in eval.c to save time */ +extern int16_t eval_squarevalue[2][6][64]; + +typedef struct ps_entry_t { + bitboard_t key; + bitboard_t holes; + int16_t value; +} ps_entry_t; + +/* this is a lot like the transposition table in case you haven't noticed... */ +#ifndef PS_NUM_BUCKETS +#define PS_NUM_BUCKETS (32 * 1024 * 1024 / sizeof(ps_entry_t)) // 32MB +#endif +static ps_entry_t ps_array[PS_NUM_BUCKETS]; + +static void ps_add(bitboard_t key, bitboard_t holes, int16_t value) +{ + unsigned long bucket; + + /* find the bucket */ + bucket = key % PS_NUM_BUCKETS; + /* always evict */ + ps_array[bucket].key = key; + ps_array[bucket].holes = holes; + ps_array[bucket].value = value; + + return; +} + +/** + * Fetch data from the table. + */ +#define PAWNSTRUCTURE_LOOKUP_FAIL INT16_MIN +static int16_t ps_get(bitboard_t key, bitboard_t *holes) +{ + unsigned long bucket = key % PS_NUM_BUCKETS; + if (ps_array[bucket].key == key) + { + *holes = ps_array[bucket].holes; + return ps_array[bucket].value; + } + return PAWNSTRUCTURE_LOOKUP_FAIL; +} + +/* Bonus for pawn chains - for each pawn protected by another, add bonus */ +#ifndef PS_CHAIN_BONUS +#define PS_CHAIN_BONUS 2 +#endif +/* Penalty for doubling pawns - for each pawn with another pawn on its file, + * subtract the penalty (note, tripled pawns net loss 6 times this!) */ +#ifndef PS_DOUBLED_PENALTY +#define PS_DOUBLED_PENALTY 8 +#endif +/* Isolated penalty - for each pawn with no brothers on adjacent files + * note, if a pawn gets this penalty it will also get the backwards penalty */ +#ifndef PS_ISOLATED_PENALTY +#define PS_ISOLATED_PENALTY 16 +#endif +/* Backward pawns - nothing on same rank or behind on adjacent columns */ +#ifndef PS_BACKWARD_PENALTY +#define PS_BACKWARD_PENALTY 8 +#endif + +/* Bonuses for having a passed pawn of on the given */ +int16_t pawnstructure_passed_bonus[2][8] = { + { 0, 3, 6, 12, 24, 48, 96, 0 }, + { 0, 96, 48, 24, 12, 6, 3, 0 } +}; + +/** + * Pawnstructure evaluator - color being whose pawns these are, and holes a + * pass-by-reference second return value - a chart of all "holes" in the pawn + * structure; that is, all squares which can never be attacked by these pawns. + */ +int16_t eval_pawnstructure(board_t *board, unsigned char color, bitboard_t *h) +{ + /* the value we calculate and store in the hashtable */ + int16_t value; + /* value dependent on factors outside of just the pawn pos, so we + * cannot hash this and must calculate even if the cache hits */ + int16_t unhashable_bonus = 0; + + square_t square; + bitboard_t pawns, pos, friends, everybodyelse, behindmask, holes; + + pawns = board->pos[color][PAWN]; + + /* attempt to lookup - if we succeed, only need to calculate the + * unhashable bonus. pass in the h ptr as well; if the lookup + * fails it'll be untouched */ + if ((value = ps_get(pawns, h)) != PAWNSTRUCTURE_LOOKUP_FAIL) + { + while (pawns) + { + square = BITSCAN(pawns); + pawns ^= BB_SQUARE(square); + if (board_pawnpassed(board, square, color)) + { + unhashable_bonus += pawnstructure_passed_bonus[color][ROW(square)]; + } + } + return value + unhashable_bonus; + } + + /* holes starts with everything set, and we take off bits that our + * pawns could attack (using passedpawn masks for this) */ + holes = ~BB_SQUARE(0x0); + /* for each pawn, consider its value with relation to the structure */ + pos = pawns; + while (pos) + { + /* find and clear a bit */ + square = BITSCAN(pos); + pos ^= BB_SQUARE(square); + /* piece/square table */ + value += eval_squarevalue[color][PAWN][square]; + + /* check for passed pawn */ + if (board_pawnpassed(board, square, color)) + { + unhashable_bonus += pawnstructure_passed_bonus[color][ROW(square)]; + } + + everybodyelse = pawns ^ BB_SQUARE(square); + + /* first evaluate chaining */ + friends = everybodyelse & pawnattacks[color][square]; + value += PS_CHAIN_BONUS * POPCOUNT(friends); + + /* next, doubled pawns */ + friends = everybodyelse & BB_FILE(COL(square)); + value -= PS_DOUBLED_PENALTY * POPCOUNT(friends); + + /* backwards */ + friends = everybodyelse & bb_adjacentcols[COL(square)]; + /* get a mask of all squares behind/same rank as this square */ + if (color == WHITE) + { + behindmask = (BB_SQUARE(square) ^ (BB_SQUARE(square) - 1)) | + BB_RANK(ROW(square)); + } + else + { + behindmask = (BB_SQUARE(square) ^ (-BB_SQUARE(square))) | + BB_RANK(ROW(square)); + } + if (!(friends & behindmask)) + { + value -= PS_BACKWARD_PENALTY; + /* see if isolated entirely */ + if (!friends) /* SO RONERY */ + { + value -= PS_ISOLATED_PENALTY; + } + } + /* calculate holes in pawnstructure - any squares that this + * pawn may be able to attack, take out of the bitmap */ + holes ^= (bb_passedpawnmask[color][square] & ~BB_FILE(COL(square))); + } + ps_add(pawns, holes, value); + *h = holes; + return value + unhashable_bonus; +} +/**************************************************************************** + * popcnt.c - various population-count implementations + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/** + * Kernighan's LSB-resetting popcount implementation + */ +int popcnt(uint64_t x) +{ + int count = 0; + while (x) + { + count++; + x &= x - 1; // reset LS1B + } + return count; +} + +/** + * Good on procs with slow multiplication + */ +int popcnt2(uint64_t x) +{ + x -= (x >> 1) & 0x5555555555555555ull; + x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); + x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0full; + x += x >> 8; + x += x >> 16; + x += x >> 32; + return x & 0x7f; +} + +/** + * Good on procs with fast multiplication + */ +int popcnt3(uint64_t x) { + x -= (x >> 1) & 0x5555555555555555ull; + x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); + x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0full; + return (x * 0x0101010101010101ull)>>56; +} +/**************************************************************************** + * quiescent.c - captures-only search to avoid evaluating unstable positions + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +extern volatile unsigned char timeup; +extern int lazy, nonlazy; + +#ifndef QUIESCENT_MAX_DEPTH +/* Warning: NEVER put this at 4 or below - it causes the bot to be too weak */ +#define QUIESCENT_MAX_DEPTH 8 +#endif + +static int16_t qalphabeta(board_t *, int16_t, int16_t, uint8_t); + +/** + * Play out capture chains in a position until it's quiet (or until a certain + * depth is reached, for speed) so we can accurately use the evaluator + */ +int16_t quiesce(board_t *board, int16_t alpha, int16_t beta) +{ + return qalphabeta(board, alpha, beta, QUIESCENT_MAX_DEPTH); +} + +/** + * Alpha beta searching over captures. Don't need to return a move, only the + * value. No repetition/50-move checking (obvious reasons), no transposition + * table (simplicity) - we get pretty good move ordering for captures already + * from the board library. + */ +static int16_t qalphabeta(board_t *board, int16_t alpha, int16_t beta, + uint8_t depth) +{ + movelist_t moves; + move_t curmove; + /* who has the move */ + int color; + //XXX: due to we're only generating captures, we can't check if we get + //XXX: mated here... this seems bad, but should turn out ok (i.e., a + //XXX: quiescence that doesn't see mates is better than no quiescence + //XXX: at all. + + /* used in place of lastval */ + int16_t a; + + /* what happens if the player to move declines to make any captures */ + int16_t stand_pat; + + if (timeup) + { + return 0; + } + + /* we'll be using stand_pat in a lot of places*/ + /* first do a lazy evaluation; if it's too far from the window we will + * not need the precision of eval() */ + stand_pat = eval_lazy(board); + /* check if we're not allowed to be lazy */ + if ((stand_pat > (alpha - EVAL_LAZY_THRESHHOLD)) && + (stand_pat < (beta + EVAL_LAZY_THRESHHOLD))) + { + stand_pat = eval(board); + nonlazy++; + } + else { lazy++; } + + /******************************************************************** + * terminal condition - search depth ran out + ********************************************************************/ + if (depth == 0) + { + return stand_pat; + } + + /******************************************************************** + * Main iteration over all the moves + ********************************************************************/ + /* set some preliminary values */ + if (stand_pat > alpha) + { + if (stand_pat >= beta) + { + return stand_pat; + } + alpha = stand_pat; + } + color = board->tomove; + + /* and we're ready to go */ + board_generatecaptures(board, &moves); + while (!movelist_isempty(&moves)) + { + if (timeup) + { + break; + } + curmove = movelist_remove_max(&moves); + + board_applymove(board, curmove); + /* see if this move puts us in check */ + if (board_colorincheck(board, color)) + { + board_undomove(board, curmove); + continue; + } + a = -qalphabeta(board, -beta, -alpha, depth-1); + board_undomove(board, curmove); + + if (a > alpha) + { + alpha = a; + } + if (beta <= alpha) + { + break; + } + } + movelist_destroy(&moves); + + return alpha; /* will work even if no captures were available */ +} +/**************************************************************************** + * rand.c - wrappers for GSL random number generation utilities + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +uint32_t +rand32(void) +{ + rand_init(); + return genrand(); +} + +static unsigned char rand_initted = 0; + +void rand_init() +{ + if (rand_initted) + { + return; + } + sgenrand(get_ticks()); + rand_initted = 1; +} + +uint64_t rand64() +{ + return ((uint64_t)rand32()) | (((uint64_t)rand32()) << 32); +} + +/**************************************************************************** + * search.c - traverse the game tree looking for the best position + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +/* Constants for the search algorithm */ +#define SEARCHER_INFINITY 32767 +#define SEARCHER_MATE 16383 + +/* could be changed if you wanted to {dis,en}courage draws + * TODO: make the evaluator also use this */ +#define SEARCHER_DRAW_SCORE 0 +#define VALUE_ISDRAW(v) ((v) == SEARCHER_DRAW_SCORE) + +static move_t alphabeta(board_t *, int16_t, int16_t, uint8_t, uint8_t, move_t, uint8_t, uint8_t, unsigned char); + +int transposition_hits, transposition_misses; +extern int regen_hits, regen_misses; + +static int nodes; +static int16_t lastval; + +/* used for printing stuff */ +extern int outbuf_size; +extern int text_loud; +extern char outbuf[]; +void output(); + +/* Used for iterative deepening and replacement policy in the trans table */ +static uint8_t cur_searching_depth; + +/* used for iterative deepening */ +volatile unsigned char timeup; + +#define SEARCHER_MIN_DEPTH 2 +#define SEARCHER_MAX_DEPTH 64 +// configurable; must never get bigger than MAX_DEPTH-1 +unsigned int searcher_max_depth = SEARCHER_MAX_DEPTH-1; + +#define VALUE_ISMATE(v) (((v) >= SEARCHER_MATE - SEARCHER_MAX_DEPTH) || ((v) <= -(SEARCHER_MATE - SEARCHER_MAX_DEPTH))) + +/* aspiration windows - first try a window of aspir_1 around prevalpha; if + * that fails go to aspir_2; if that fails use the full -inf,+inf search */ +#define SEARCHER_ASPIRATION_1 50 +#define SEARCHER_ASPIRATION_2 200 + +/* killer moves + * + * Tried at each move after the hashed bestmove, before generatemoves(). A + * killer move is basically any move by one player that produces a beta cutoff + * when the pther player makes a move from X position; the hope here is that + * the same refutation move will produce a cutoff in the next children of X. + * This is likely to happen if the first player is threatened somehow, and the + * killer will be the followthrough on that threat if player one doesn't + * respond to it. + * + * note - you will want to clear all the killers in the following cases: + * 1) Beginning/end of getbestmove - clear all depths + * 2) After a node finishes its children, clear the nodes at that + * child's ply + * If the killers are not adequately cleared, you may end up applying some + * illegal moves at other nodes, resulting in inconsistent board state. + * Another thing to watch out for is some killers can still be illegal - most + * cases are eliminated by preventing captures and castles, the rest need + * checking against board_attacksfrom() (or pushes, in the case of pawns). + */ +#define SEARCHER_USE_KILLERS +#ifdef SEARCHER_USE_KILLERS +#define SEARCHER_NUM_KILLERS 3 +static move_t killers[SEARCHER_MAX_DEPTH][SEARCHER_NUM_KILLERS]; +#endif + +/* margins for futility pruning - how far away from the window do we need + * to be in order to consider doing futility pruning. note that the value at + * 0 will never be used */ +#ifdef SEARCHER_FUTILITY_PRUNING +static int16_t futility_margin[3] = { 0xbeef, 250, 450 }; +#endif + +int lazy, nonlazy; + +/* determining the type of a child from a parent (first index - parent's type) + * given whether the first child (0 or 1, second index) has been searched */ +#define PV 0 +#define CUT 1 +#define ALL 2 +static unsigned char childnodetype[3][2] = { + /* first child already searched: + * NO YES */ + { PV, CUT }, /* parent was PV */ + { ALL, CUT }, /* parent was CUT */ + { CUT, CUT } /* parent was ALL */ +}; + +/* null-move depth reduction - dependent on depth */ +#define NULLMOVE_R(d) (((d) > 6) ? 3 : 2) + +/* Late move reduction - we reduce after searching this many nodes given the + * current node type (allows us to be more conservative at PV nodes) */ +static uint8_t lmr_movecount[3] = { 16, 8, 8 }; + +#define GUESS_KERNEL_HZ 100 // I really wish the syscall interface exposed this. + +void *sigalrm_thread(void *arg) +{ + sleep((int)arg * GUESS_KERNEL_HZ); + timeup = 1; + return (void *)0x15410FA1L; +} + +/** + * Stores the nodecount in the given int pointer if it's nonnull and the alpha + * value in the second pointer if that's nonnull. + */ +move_t getbestmove(board_t *board, unsigned int time, int *nodecnt, int16_t *alphaval) +{ + move_t result, prevresult; + int16_t prevalpha; + int16_t window_low, window_high; + char *movestr; + int ret; + void *statusp; + + /******************************************************************** + * Setup + ********************************************************************/ + nodes = 0; + timeup = 0; + + transposition_hits = 0; transposition_misses = 0; + regen_hits = 0; regen_misses = 0; + + lazy = 0; nonlazy = 0; + + #ifdef SEARCHER_USE_KILLERS + /* clear all killers */ + memset(killers, 0, sizeof(killers)); + #endif + /******************************************************************** + * Searching + ********************************************************************/ + snprintf(outbuf, outbuf_size, "Thinking (for %d %s)...", + time, time == 1 ? "sec" : "secs"); + output(); + /* preliminary search */ + cur_searching_depth = SEARCHER_MIN_DEPTH; + result = alphabeta(board, -SEARCHER_INFINITY, SEARCHER_INFINITY, + cur_searching_depth, 0, 0, 0, 0, PV); + prevresult = result; + prevalpha = lastval; + + /* start the iterative timer */ + ret = thr_create(sigalrm_thread, (void *)time); + assert(ret > 0 && "Failed to create timer thread"); + + while (!timeup && cur_searching_depth < searcher_max_depth) + { + /* These guys store the result of the previous depth in case + * our next search times up */ + prevresult = result; + prevalpha = lastval; + + // Don't waste time if we have a mate + /*if (lastval >= SEARCHER_MATE) + { + break; + }*/ + + //TODO: Check if we've used up enough time to not even bother with the next search + + /* advance to the next depth */ + movestr = move_tostring(result); + if (text_loud) { + snprintf(outbuf, outbuf_size, "[depth %d] best %s score %d", + cur_searching_depth, movestr, lastval); + output(); + } + if (VALUE_ISMATE(lastval) && text_loud) + { + snprintf(outbuf, outbuf_size, "%s mates in %d", + ((lastval > 0) ? + ((board->tomove == WHITE) ? "White" : "Black") + : + ((board->tomove == WHITE) ? "Black" : "White")), + ((lastval > 0) ? + ((SEARCHER_MATE - lastval + 1) / 2) + : + ((SEARCHER_MATE + lastval + 1) / 2))); + output(); + } + free(movestr); + cur_searching_depth++; + nodes = 0; + + window_low = prevalpha - SEARCHER_ASPIRATION_1; + window_high = prevalpha + SEARCHER_ASPIRATION_1; + result = alphabeta(board, window_low, window_high, + cur_searching_depth, 0, 0, 0, 0, PV); + if (timeup) break; + /* test if aspir_1 window failed */ + if (lastval <= window_low || lastval >= window_high) + { + /* try wider window */ + window_low = prevalpha - SEARCHER_ASPIRATION_2; + window_high = prevalpha + SEARCHER_ASPIRATION_2; + /* re-search */ + result = alphabeta(board, window_low, window_high, + cur_searching_depth, 0, 0, 0, 0, PV); + } + if (timeup) break; + /* test if aspir_2 window failed */ + if (lastval <= window_low || lastval >= window_high) + { + /* use full window */ + window_low = -SEARCHER_INFINITY; + window_high = SEARCHER_INFINITY; + /* re-search */ + result = alphabeta(board, window_low, window_high, + cur_searching_depth, 0, 0, 0, 0, PV); + } + } + + /******************************************************************** + * Teardown + ********************************************************************/ + movestr = move_tostring(prevresult); + if (text_loud) { + if (timeup) { + snprintf(outbuf, outbuf_size, "[depth %d] (timeout, %d nodes)", + cur_searching_depth, nodes); + } else { + snprintf(outbuf, outbuf_size, "[depth %d] best %s score %d", + cur_searching_depth, movestr, lastval); + } + output(); + } + snprintf(outbuf, outbuf_size, "My move: %s", movestr); + output(); + free(movestr); + #ifdef SEARCHER_USE_KILLERS + /* clear killers, just in case */ + memset(killers, 0, sizeof(killers)); + #endif + if (nodecnt != NULL) + { + *nodecnt = nodes; + } + if (alphaval != NULL) + { + *alphaval = prevalpha; + } + // TODO: Do this in a non-blocking way all the time. + thr_join(ret, &statusp); + assert(statusp == (void*)0x15410FA1L); + return prevresult; +} + +/** + * Alpha-beta search, with trans table, check extension, futility pruning + * board - the current node's position + * alpha - lower bound + * beta - upper bound + * depth - how deep we will search this node + * ply - how far this position is from the board's real position (used + * because depth can change based on extensions/reductions) + * prevmove - the move that was just made (used in futility pruning) + * num_checks - how many checks have occurred so far in the search (used for + * check extension) + * nodetype - what type of node we're searching - PV, CUT, or ALL + */ +static move_t alphabeta(board_t *board, int16_t alpha, int16_t beta, + uint8_t depth, uint8_t ply, move_t prevmove, + uint8_t num_checks, uint8_t null_extended, + unsigned char nodetype) +{ + movelist_t moves; + move_t curmove, returnmove; + /* who has the move */ + int color; + /* used for telling if the movelist we got had no non-suicide moves, + * also for telling what the child's node type will be */ + unsigned char children_searched; + + /* transposition table */ + trans_data_t trans_data; + int trans_flag; + /* for move ordering */ + move_t bestmove; + + int killer_index; + + nodes++; + if (timeup) + { + return 0; + } + /******************************************************************** + * threefold repetition/50 move - always check first + ********************************************************************/ + /* draw score if only even -one- prior repetition, not two. this is + * more efficient (taken from crafty). note that it obsoletes storing + * the repetition count in the trans table, but if it gets put back, + * transing the reps will still be essential. */ + if (board->halfmoves >= 100 || board_threefold_draw(board)) + { + //fprintf(ttyout, "%sSEARCHER: Detected threefold repetition at depth %d%s\n", + // TTYOUT_COLOR, cur_searching_depth - depth, DEFAULT_COLOR); + lastval = SEARCHER_DRAW_SCORE; + return 0; + } + /******************************************************************** + * check transposition table + ********************************************************************/ + trans_data = trans_get(board->hash); + if (trans_data_valid(trans_data)) + { + if (TRANS_SEARCHDEPTH(trans_data) >= depth && + TRANS_REPS(trans_data) >= board->reps) + { + int16_t storedval = TRANS_VALUE(trans_data); + + /* direct hit! */ + if (TRANS_FLAG(trans_data) == TRANS_FLAG_EXACT) + { + transposition_hits++; + lastval = storedval; + return TRANS_MOVE(trans_data); + } + /* if we do this on the root node, we run the risk of + * getting a1a1 as the returnmove, so prevent it */ + else if (depth != cur_searching_depth) + { + /* we have a lower bound for the true value */ + if (TRANS_FLAG(trans_data) == TRANS_FLAG_BETA) + { + /* above our current window? */ + if (storedval >= beta) + { + transposition_hits++; + lastval = storedval; + return 0; + } + /* not above the window but inside? */ + if (storedval > alpha) + { + alpha = storedval; + } + } + /* this means we'll have an upper bound */ + else if (TRANS_FLAG(trans_data) == + TRANS_FLAG_ALPHA) + { + /* below current window entirely? */ + if (storedval <= alpha) + { + transposition_hits++; + lastval = storedval; + return 0; + } + /* inside window - cut the top off */ + if (storedval < beta) + { + beta = storedval; + } + } + } + } + /* well, we can still use move-ordering information. note: + * we'll want to grab it regardless of the flag. if it's beta + * we'll get a move; if it's alpha we'll get 0; oh well */ + bestmove = TRANS_MOVE(trans_data); + } + else + { + bestmove = (move_t)0; + transposition_misses++; + } + /******************************************************************** + * terminal condition - search depth ran out + * futility pruning done here + ********************************************************************/ + if (depth == 0) + { + lastval = quiesce(board, alpha, beta); + /* we time up in the middle of quiescence and get zero, and go + * to add it in the trans table, OH SHI-- */ + if (timeup) + { + return 0; + } + /* if we already have an entry, and this is an end condition, + * we don't want to replace our better entry */ + if (!trans_data_valid(trans_data)) + { + trans_add(board->hash, (move_t)0, board->reps, lastval, + (board->moves - cur_searching_depth), + board->moves, 0, TRANS_FLAG_EXACT); + } + return 0; + } + #ifdef SEARCHER_FUTILITY_PRUNING + /* futility pruning - prune only 1 and 2 plies from the horizon */ + else if (depth < 3) + { + /* if we're in check or possibly in a capture sequence, trying + * to prune will be too dangerous */ + if (!(board_incheck(board) || MOV_CAPT(prevmove))) + { + int16_t score = eval_lazy(board); + /* check how far we are from the window */ + if ((score + futility_margin[depth] < alpha) || + (score - futility_margin[depth] > beta)) + { + lastval = quiesce(board, alpha, beta); + return 0; + } + } + } + #endif + /******************************************************************** + * Null-move pruning + ********************************************************************/ + /* only do it if all of the following: + * we're a fail-high (CUT) node + * depth is not three or less + * we're not in the endgame + * a lazy eval fails high + * we're not in check + */ + if ((nodetype != PV) && (depth > 3) && !eval_isendgame(board) && + (eval_lazy(board) >= beta) && !board_incheck(board)) + { + /* make null move */ + board_applymove(board, 0); + alphabeta(board, -beta, -beta+1, depth - NULLMOVE_R(depth) - 1, + ply+1, 0, num_checks, null_extended, ALL); + board_undomove(board, 0); + + /* failed high, we can prune */ + if (-lastval >= beta) + { + lastval = -lastval; + return 0; + } + /* mate threat - if we do nothing here, we get mated. better + * search deeper. only extend this way once per line. */ + if (VALUE_ISMATE(lastval) && !null_extended) + { + depth++; + null_extended = 1; + } + } + /******************************************************************** + * Main iteration over all the moves + ********************************************************************/ + /* set some preliminary values */ + color = board->tomove; + children_searched = 0; + returnmove = 0; + trans_flag = TRANS_FLAG_ALPHA; + /* and we're ready to go - first do hash move and killers */ + if (bestmove) + { + board_applymove(board, bestmove); + /* if this puts us in check something's really wrong... */ + assert(!board_colorincheck(board, color)); + /* check extension - if this checks the opp king */ + if (board_incheck(board)) + { + /* only extend search if >1 checks in tree */ + if (num_checks) + { + alphabeta(board, -beta, -alpha, depth, ply+1, + bestmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + else + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + bestmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + } + else /* no extensions, regular search */ + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + bestmove, num_checks, null_extended, + childnodetype[nodetype][!!children_searched]); + } + board_undomove(board, bestmove); + children_searched++; + + if (-lastval > alpha) + { + alpha = -lastval; + returnmove = bestmove; + trans_flag = TRANS_FLAG_EXACT; + } + if (alpha >= beta) + { + trans_flag = TRANS_FLAG_BETA; + goto alphabeta_after_iteration; + } + } + #ifdef SEARCHER_USE_KILLERS + /* no cutoff from the bestmove (or no bestmove); let's try killers */ + for (killer_index = 0; killer_index < SEARCHER_NUM_KILLERS; killer_index++) + { + move_t killer = killers[ply][killer_index]; + piece_t killerpiece; + square_t killersrc, killerdest; + /* check if a killer is available */ + if (killer == 0 || timeup) + { + break; + } + killerpiece = MOV_PIECE(killer); + killersrc = MOV_SRC(killer); + killerdest = MOV_DEST(killer); + /* need to check if the killer is legal in this position; it's + * guaranteed to not be a capture or castle, so the following + * legality checks are made: + * 1) We have the given piece on that square + * 2) The destination square is not occupied (by either color) + * 3) If a sliding piece, there must be nothing in the way */ + if ((!(BB_SQUARE(killersrc) & board->pos[color][killerpiece])) || + (BB_SQUARE(killerdest) & board->occupied) || /* #2 */ + (PIECE_SLIDES(killerpiece) && /* #3 */ + !(BB_SQUARE(killerdest) & + board_attacksfrom(board, killersrc, killerpiece, color)))) + { + continue; + } + /* next we check if our piece can move to the destsquare */ + if (killerpiece == PAWN) + { + /* destination square not among the legal pushes? */ + if (!(BB_SQUARE(killerdest) & + board_pawnpushesfrom(board, killersrc, color))) + { + continue; + } + } + else + { + /* destination square not among the legal moves? */ + if (!(BB_SQUARE(killerdest) & + board_attacksfrom(board, killersrc, killerpiece, + color))) + { + continue; + } + } + /* we have a pseudolegal killer move to try, good */ + board_applymove(board, killer); + /* this might put us in check, unlike the bestmove */ + if (board_colorincheck(board, color)) + { + board_undomove(board, killer); + continue; + } + /* check extension - if this checks the opp king */ + if (board_incheck(board)) + { + /* only extend search if >1 checks in tree */ + if (num_checks) + { + alphabeta(board, -beta, -alpha, depth, ply+1, + killer, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + else + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + killer, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + } + else /* no extensions, regular search */ + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + killer, num_checks, null_extended, + childnodetype[nodetype][!!children_searched]); + } + board_undomove(board, killer); + children_searched++; + + if (-lastval > alpha) + { + alpha = -lastval; + returnmove = killer; + trans_flag = TRANS_FLAG_EXACT; + } + if (alpha >= beta) + { + trans_flag = TRANS_FLAG_BETA; + goto alphabeta_after_iteration; + } + } + #endif + /* okay, no beta cutoff; let's continue... */ + board_generatemoves(board, &moves); + while (!movelist_isempty(&moves)) + { + if (timeup) + { + break; + } + curmove = movelist_remove_max(&moves); + + board_applymove(board, curmove); + /* see if this move puts us in check */ + if (board_colorincheck(board, color)) + { + board_undomove(board, curmove); + continue; + } + /* check extension - if this checks the opp king */ + if (board_incheck(board)) + { + /* only extend search if >1 checks in tree */ + if (num_checks) + { + alphabeta(board, -beta, -alpha, depth, ply+1, + curmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + else + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + curmove, num_checks+1, null_extended, + childnodetype[nodetype][!!children_searched]); + } + } + /* Late move reductions (LMR) + * The idea here is if a move occurs late in the movelist, + * it's probably not worth searching to a full depth (if it + * happens to return a value within the window, re-search with + * full depth). This works recursively, so strings of moves + * that are all Late get searched to (optimal case) 1/2 depth + * overall, while lines with just one Late move are searched + * with depth reduced by just one overall. What happens if we + * encounter a seemingly bad move that only pays off when + * searched to the full depth (i.e. sacrifice -> attack)? + * Typically, such lines will only have one or two Late moves + * in them, and we rely on the more extreme reductions on the + * completely nonsense lines (1/2-depth mentioned before) to + * possibly give us another ply so we find the sacrifice. */ + else if (children_searched > lmr_movecount[nodetype] && depth > 3 && + !MOV_CAPT(curmove) && !MOV_CAPT(prevmove)) + { + alphabeta(board, -beta, -alpha, depth-2, ply+1, + curmove, num_checks, null_extended, + childnodetype[nodetype][1]); + /* oops, it fell within our window. full re-search */ + if (-lastval > alpha) + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + curmove, num_checks, null_extended, + childnodetype[nodetype][1]); + } + } + else /* no extensions/reductions, regular search */ + { + alphabeta(board, -beta, -alpha, depth-1, ply+1, + curmove, num_checks, null_extended, + childnodetype[nodetype][!!children_searched]); + } + board_undomove(board, curmove); + children_searched++; + + if (-lastval > alpha) + { + alpha = -lastval; + returnmove = curmove; + /* we've gotten above the bottom of the window */ + trans_flag = TRANS_FLAG_EXACT; + } + if (beta <= alpha) + { + /* oops, above the top of the window */ + trans_flag = TRANS_FLAG_BETA; + #ifdef SEARCHER_USE_KILLERS + /* Not a killer if capture or castle */ + if (!(MOV_CAPT(curmove)) && !(MOV_CASTLE(curmove))) + { + /* We found a killer move! Add it in... note + * we will never here cause duplicate killers + * because we would have tested this killer + * earlier and skipped this */ + killer_index = 0; + while ((killers[ply][killer_index] != 0) && + (killer_index < SEARCHER_NUM_KILLERS-1)) + { + /* move to first empty killer slot, + * or if full replace at the end */ + killer_index++; + } + killers[ply][killer_index] = curmove; + } + #endif + break; + } + } + movelist_destroy(&moves); + /* now we are done iterating; cleanup and exit this node. note, this + * label is here so we can skip over iteration if the bestmove/killers + * produce a cutoff */ +alphabeta_after_iteration: + /* The transposition table will get really sad if we choke all over it + * with bogus results from after we get cut off */ + if (timeup) + { + return 0; + } + #ifdef SEARCHER_USE_KILLERS + /* okay we need to clear the killers for the children here */ + memset(killers[ply+1], 0, (SEARCHER_NUM_KILLERS * sizeof(move_t))); + #endif + /* check if there were no legal moves */ + if (children_searched) + { + /* this is the "typical case" function ending + * set the value so the calling function sees it properly */ + lastval = alpha; + /* Don't add mates because they are depth-dependent. Don't add + * draws because they are state-dependent. */ + if (!VALUE_ISMATE(alpha) && !VALUE_ISDRAW(alpha)) + { + /* update the trans table - here we always replace */ + trans_add(board->hash, returnmove, board->reps, alpha, + (board->moves + depth - cur_searching_depth), + board->moves, depth, trans_flag); + } + } + else /* no children were searched - must be an end condition */ + { + /* checkmate vs stalemate */ + if (board_incheck(board)) + { + lastval = -1 * (SEARCHER_MATE - ply); + } + else + { + lastval = 0; + } + /* DON'T add to the transposition table here... this can screw + * up which mates are sooner and cause 3-rep draws - besides, + * if a mate is coming up and we've seen it there's no use + * trying to search deeper/faster */ + return 0; + } + /* and we're done */ + return returnmove; +} +/**************************************************************************** + * transposition.c - avoid re-searching already searched positions + * copyright (C) 2008 Ben Blum + ****************************************************************************/ + +typedef struct trans_entry_t { + uint64_t key; + trans_data_t value; +} trans_entry_t; + +/** + * Statically initting the array is good because it avoids committing memory + * we don't use, but depends, for efficiency not correctness, on the kernel + * harbl-filling our memory with zeros. When we go to kick out an entry, if + * we haven't put one there yet, we'll see that the depth is 0 and the flag + * is ALPHA - the two worst possible values, so this type will always be + * replaced. + */ +#ifndef TRANS_NUM_BUCKETS +#define TRANS_NUM_BUCKETS ((128 * 1024 * 1024)/sizeof(trans_entry_t)) // 128 MB +#endif +static trans_entry_t array[TRANS_NUM_BUCKETS]; + +/** + * Convert separate data values -> condensed struct + */ +static trans_data_t trans_data(move_t move, uint8_t reps, int16_t value, + uint8_t gamedepth, uint8_t searchdepth, + uint8_t flag) +{ + trans_data_t foo; + assert(searchdepth < 64); + foo.move = move | (reps << MOV_INDEX_UNUSED); + foo.value = value; + foo.gamedepth = gamedepth; + foo.flags = ((searchdepth & 0x3f) << TRANS_INDEX_SEARCHDEPTH) | + ((flag & 0x3) << TRANS_INDEX_FLAG); + return foo; +} + +/** + * Add transposition information to the table. Note, it will only kick the old + * entry out if: + * 1) The flag is higher (exact kicks out beta, beta kicks out alpha) + * 2) The flag is equal and the depth is higher + * 3) The old node was from ancient history + * Note the different depth arguments: + * rootdepth - how far down the game tree the real board state is. + * used in comparison for evicting the old node. + * gamedepth - how far down this current node is in the game tree. we + * store this for future nodes to use to evict us. + * searchdepth - how much deeper still we've searched this node. this + * tells how trustworthy the alpha value is. + * At present we don't discriminate based on repetition depth. + */ +void trans_add(zobrist_t key, move_t move, uint8_t reps, int16_t value, + uint8_t rootdepth, uint8_t gamedepth, + uint8_t searchdepth, uint8_t flag) +{ + unsigned long bucket; + trans_data_t old; + + /* find the bucket */ + bucket = key % TRANS_NUM_BUCKETS; + + /* find what used to be there */ + old = array[bucket].value; + + /* see if we should evict */ + if ((rootdepth >= TRANS_GAMEDEPTH(old)) || /* old node too old */ + (flag > TRANS_FLAG(old)) || /* more accurate data */ + ((flag == TRANS_FLAG(old)) && /* same type of data but... */ + (searchdepth > TRANS_SEARCHDEPTH(old)))) /* ...deeper search */ + { + /* so we set the stuff to our new node */ + array[bucket].key = key; + array[bucket].value = trans_data(move, reps, value, gamedepth, + searchdepth, flag); + } + return; +} + +/** + * Fetch data from the table. If there is no entry for this key the flag in + * the return value will be set to -1. + */ +static trans_data_t foo = { (uint8_t)(-1), (uint8_t)(-1), + (int16_t)(-1), (uint32_t)(-1) }; +trans_data_t trans_get(zobrist_t key) +{ + unsigned long bucket = key % TRANS_NUM_BUCKETS; + if (array[bucket].key == key) + { + return array[bucket].value; + } + return foo; +} + +/** + * Check if the transposition data is valid, according to whatever spec may be + * in use for saying "invalid entry". Used for checking the returnvalue of get + */ +int trans_data_valid(trans_data_t foo) +{ + return (foo.flags != (uint8_t)(-1)); +} + +/****************************************************************************** + * Custom pebbles interface + ******************************************************************************/ + +/********************** BOARD / SCREEN CONTENT ********************************/ + +char *board_strs[] = { + " a b c d e f g h ", + " .-------------------------------. ", + "8 | | | | | | | | | 8", + " |---+---+---+---+---+---+---+---| ", + "7 | | | | | | | | | 7", + " |---+---+---+---+---+---+---+---| ", + "6 | | | | | | | | | 6", + " |---+---+---+---+---+---+---+---| ", + "5 | | | | | | | | | 5", + " |---+---+---+---+---+---+---+---| ", + "4 | | | | | | | | | 4", + " |---+---+---+---+---+---+---+---| ", + "3 | | | | | | | | | 3", + " |---+---+---+---+---+---+---+---| ", + "2 | | | | | | | | | 2", + " |---+---+---+---+---+---+---+---| ", + "1 | | | | | | | | | 1", + " `-------------------------------' ", + " a b c d e f g h ", +}; +char *board_strs_flipped[] = { + " h g f e d c b a ", + " .-------------------------------. ", + "1 | | | | | | | | | 1", + " |---+---+---+---+---+---+---+---| ", + "2 | | | | | | | | | 2", + " |---+---+---+---+---+---+---+---| ", + "3 | | | | | | | | | 3", + " |---+---+---+---+---+---+---+---| ", + "4 | | | | | | | | | 4", + " |---+---+---+---+---+---+---+---| ", + "5 | | | | | | | | | 5", + " |---+---+---+---+---+---+---+---| ", + "6 | | | | | | | | | 6", + " |---+---+---+---+---+---+---+---| ", + "7 | | | | | | | | | 7", + " |---+---+---+---+---+---+---+---| ", + "8 | | | | | | | | | 8", + " `-------------------------------' ", + " h g f e d c b a ", +}; +#define BOARD_ROW 3 // the row of the opponent's sides lettering (a-h/h-a) +#define BOARD_COL 4 // the col of the left side numbering (1-8/8-1) +#define BOARD_ROW_SCALE 2 +#define BOARD_COL_SCALE 4 + +#define BOARD_COLOR (FGND_BRWN | BGND_BLACK) +#define WHITE_COLOR (FGND_WHITE | BGND_BLACK) +#define BLACK_COLOR (FGND_RED | BGND_BLACK) // like the old-time chess sets + +int flipped = 0; +int xyzzy = 0; + +void set_text_color(int color) { + int low = color & 0xf; + int high = color & ~0xf; + if (low == FGND_BLACK) { + set_term_color(color); + } else { + low = (low + xyzzy) & 0xf; + if (low == FGND_BLACK) low++; + set_term_color(low | high); + } +} + +void draw_pieces(board_t *board, int color) { + int square; + bitboard_t pos; + int piece = PAWN; + while (piece <= KING) { + pos = board->pos[color][piece]; + while (pos) { + int row_offset, col_offset; + square = BITSCAN(pos); + if (flipped) { + row_offset = BOARD_ROW_SCALE*(1 + ROW(square)); + col_offset = BOARD_COL_SCALE*(8 - COL(square)); + } else { + row_offset = BOARD_ROW_SCALE*(8 - ROW(square)); + col_offset = BOARD_COL_SCALE*(1 + COL(square)); + } + set_cursor_pos(BOARD_ROW + row_offset, BOARD_COL + col_offset); + print(1, piecename[color][piece]); + pos &= BB_ALLEXCEPT(square); + } + piece++; + } +} + +// I'd say this should be called only on redraw, but it also has the +// convenient effect of setting blank all unoccupied squares, which means +// fewer syscalls overall... unless you'd like to analyse the board state +// to determine what the most recently vacated square is.... etc. +void draw_board(board_t *board) { + unsigned int i; + set_text_color(BOARD_COLOR); + if (flipped) { + for (i = 0; i < ARRAY_SIZE(board_strs_flipped); i++) { + set_cursor_pos(BOARD_ROW+i, BOARD_COL); + print(strlen(board_strs_flipped[i]), board_strs_flipped[i]); + } + } else { + for (i = 0; i < ARRAY_SIZE(board_strs); i++) { + set_cursor_pos(BOARD_ROW+i, BOARD_COL); + print(strlen(board_strs[i]), board_strs[i]); + } + } + set_text_color(WHITE_COLOR); + draw_pieces(board, WHITE); + set_text_color(BLACK_COLOR); + draw_pieces(board, BLACK); +} + +enum player_mode { + bot_black = 0, + bot_white = 1, + human = 2, +}; +char *player_strs[] = { + "you vs bistromath", + "bistromath vs you", + " you vs yourself ", +}; +#define PLAYERSTR_ROW 1 +#define PLAYERSTR_COL 14 +#define PLAYERSTR_COLOR (FGND_BBLUE | BGND_BLACK) + +enum player_mode player_mode = bot_black; + +void draw_player_str() { + set_text_color(PLAYERSTR_COLOR); + set_cursor_pos(PLAYERSTR_ROW, PLAYERSTR_COL); + assert(player_mode < ARRAY_SIZE(player_strs)); + print(strlen(player_strs[player_mode]), + player_strs[player_mode]); +} + +#define STATUS_WHITEMOVE " [white to move] " +#define STATUS_BLACKMOVE " [black to move] " +#define STATUS_WHITEMATE " [0-1 white checkmated] " +#define STATUS_BLACKMATE " [1-0 black checkmated] " +#define STATUS_WHITERESIGN " [0-1 white resigns] " +#define STATUS_BLACKRESIGN " [1-0 black resigns] " +#define STATUS_DRAW3MOVE " [1/2-1/2 game drawn by 3-fold repetition] " +#define STATUS_DRAW50MOVE " [1/2-1/2 game drawn by 50 move rule] " +#define STATUS_DRAWSTALE " [1/2-1/2 game drawn by stalemate] " +#define STATUS_DRAWNOMATE "[1/2-1/2 neither side has mating material]" + +#define STATUS_ROW 23 +#define STATUS_COL 1 +#define STATUS_COLOR (FGND_BBLUE | BGND_BLACK) + +char *status_str = STATUS_WHITEMOVE; + +// gentleperson's agreement: msg must be one of the predefined ones above +void draw_status_str() { + assert(strlen(status_str) == strlen(STATUS_WHITEMOVE)); + set_text_color(STATUS_COLOR); + set_cursor_pos(STATUS_ROW, STATUS_COL); + print(strlen(status_str), status_str); +} + +/************************* CONSOLE LIBRARY ************************************/ + +char *helptext[] = { + "Commands available: ", + "a2a4 - move (e.g.) ", // + "e7e8Q - move with pawn promote ", // + "go - switch sides; bot goes ", // + "human - let two people play ", // + "flip - turn the board around ", // + "new - start a new game ", // + "quiet - don't think out loud ", // + "loud - think out loud ", // + "hint - what the bot would do ", // + "undo - take back a move ", // + "resign - give up ", // + "depth - set/show difficulty ", // + "time - set search time limit ", + "book - turn on/off opening book", // + "credit - show credit info ", // + "help - show this ", // + "quit - quit ", // + "Sorry no algebraic move syntax. ", +}; + +char *credittext[] = { + "\"Bistromath\" is (C) 2013 Ben Blum", + "Originally written 2008 ", + "Engine finished 2010 ", + "Ported to Pebbles 2012 ", + "Questions/bugs? bblum@cs.cmu.edu", + "(type \"help\" for commands) ", +}; + +#define CONSOLE_HEIGHT 25 +#define CONSOLE_WIDTH 80 + +// these defines could be a little more flexible +#define TEXT_WIDTH 34 // custom console dimensions +#define TEXT_HEIGHT (CONSOLE_HEIGHT-2) +#define TEXT_ROW 0 // where the custom console's top left corner is +#define TEXT_COL (CONSOLE_WIDTH-TEXT_WIDTH) +char textconsole[TEXT_HEIGHT][TEXT_WIDTH]; +#define PROMPT "> " +#define TEXT_COLOR (FGND_GREEN | BGND_BLACK) +#define PROMPT_COLOR (FGND_BGRN | BGND_BLACK) + +void init_console() { + int i, j; + for (i = 0; i < TEXT_HEIGHT; i++) { for (j = 0; j < TEXT_WIDTH; j++) { + textconsole[i][j] = ' '; + }} +} + +// Printing e.g. help text would be more efficient with a print n lines function +// Future work! At least draw_console is separated out. +void print_line(const char *buf, unsigned int len) { + if (len > TEXT_WIDTH) len = TEXT_WIDTH; + /* Scroll. */ + int i; + for (i = 1; i < TEXT_HEIGHT; i++) { + strncpy(textconsole[i-1], textconsole[i], TEXT_WIDTH); + } + /* Command prompt always stays on the bottom. */ + strncpy(textconsole[TEXT_HEIGHT-1], buf, len); + /* Pad rest of line with whitespace */ + for (i = len; i < TEXT_WIDTH; i++) { + textconsole[TEXT_HEIGHT-1][i] = ' '; + } +} + +// Flush, essentially +void draw_console() { + int i; + set_text_color(TEXT_COLOR); + for (i = 0; i < TEXT_HEIGHT; i++) { + set_cursor_pos(TEXT_ROW + i, TEXT_COL); + print(TEXT_WIDTH, textconsole[i]); + } +} +void draw_prompt() { + char buf[TEXT_WIDTH+1]; // Trac ticket #157. ARGGH + set_text_color(PROMPT_COLOR); + set_cursor_pos(TEXT_ROW + TEXT_HEIGHT, TEXT_COL); + assert(strlen(PROMPT) < TEXT_WIDTH); + snprintf(buf, TEXT_WIDTH, "%s%*s", PROMPT, TEXT_WIDTH-strlen(PROMPT), " "); + buf[TEXT_WIDTH-1] = 0; // Trac ticket #157. ARGGH + print(TEXT_WIDTH, buf); + set_cursor_pos(TEXT_ROW + TEXT_HEIGHT, TEXT_COL + strlen(PROMPT)); +} + + +// for other modules of the engine to print +int outbuf_size = TEXT_WIDTH; +char outbuf[TEXT_WIDTH]; +void output() { print_line(outbuf, TEXT_WIDTH); draw_console(); } + +/**************************** MAIN ROUTINES ***********************************/ + +int text_loud = 1; + +void help() { + unsigned int i; + for (i = 0; i < ARRAY_SIZE(helptext); i++) { + print_line(helptext[i], strlen(helptext[i])); + } +} +void credits() { + unsigned int i; + for (i = 0; i < ARRAY_SIZE(credittext); i++) { + print_line(credittext[i], strlen(credittext[i])); + } +} + +void redraw(board_t *board) { + // clear screen + int i; + char spaces[CONSOLE_WIDTH+1]; // Trac ticket #157. ARGGH + snprintf(spaces, CONSOLE_WIDTH, "%*s", CONSOLE_WIDTH, " "); + spaces[CONSOLE_WIDTH-1] = 0; // Trac ticket #157. ARGGH + set_text_color(FGND_BLACK | BGND_BLACK); // erase existing bgnd + for (i = 0; i < CONSOLE_HEIGHT; i++) { + set_cursor_pos(i, 0); + print(CONSOLE_WIDTH, spaces); + } + // draw everything + draw_board(board); + draw_player_str(); + draw_status_str(); + draw_console(); + draw_prompt(); +} + +engine_t *e; +int gameover = 0; + +int checkgameover() { + int matetype; + if (e->board->halfmoves >= 100) { + status_str = STATUS_DRAW50MOVE; + return 1; + } else if (board_threefold_draw(e->board)) { + status_str = STATUS_DRAW3MOVE; + return 1; + } + /* Resignation is handled elsewhere */ + matetype = board_mated(e->board); + /* check if a player is mated */ + if (matetype == BOARD_CHECKMATED) { + status_str = e->board->tomove == WHITE ? STATUS_WHITEMATE + : STATUS_BLACKMATE; + return 1; + } else if (matetype == BOARD_STALEMATED) { + status_str = STATUS_DRAWSTALE; + return 1; + } else if ((e->board->material[BLACK] == 0 && // Both players have 0 + e->board->material[WHITE] == 0) || + (e->board->material[BLACK] == 0 && // B has 0, W has N or B + ((e->board->material[WHITE] == eval_piecevalue[BISHOP] && + e->board->pos[WHITE][BISHOP] != BB(0x0)) || + (e->board->material[WHITE] == eval_piecevalue[KNIGHT] && + e->board->pos[WHITE][KNIGHT] != BB(0x0)))) || + (e->board->material[WHITE] == 0 && // W has 0, B has N or B + ((e->board->material[BLACK] == eval_piecevalue[BISHOP] && + e->board->pos[BLACK][BISHOP] != BB(0x0)) || + (e->board->material[BLACK] == eval_piecevalue[KNIGHT] && + e->board->pos[BLACK][KNIGHT] != BB(0x0))))) { + status_str = STATUS_DRAWNOMATE; + return 1; + } else { + status_str = e->board->tomove == WHITE ? STATUS_WHITEMOVE + : STATUS_BLACKMOVE; + return 0; + } +} + +void makemove() { + draw_prompt(); + // TODO: Spawn a separate thread that can interrupt... somehow? + char *str = engine_generatemove(e); + char *errmsg; + int x = engine_applymove(e, str, &errmsg); + affirm_msg(x, "engine_generatemove() generated an illegal move"); + free(str); +} + +#define INBUF_LEN (2*TEXT_WIDTH) +static inline void print_string(const char *s) { print_line(s, strlen(s)); } + +int main() { + thr_init(4096); + e = engine_init(getbestmove); + char inbuf[INBUF_LEN]; + char *nogame = "No game is in progress."; + assert(e != NULL); + { + int i; + init_console(); + credits(); + for (i = ARRAY_SIZE(credittext); i < TEXT_HEIGHT; i++) { + print_line("", 0); + } + redraw(e->board); + } + while(1) { + int ret, need_redraw = 0; + char inbuf2[TEXT_WIDTH]; + memset(inbuf, 0, sizeof(inbuf)); + ret = readline(INBUF_LEN-1, inbuf); + affirm_msg(ret >= 0, "readline() failed"); + if (inbuf[strlen(inbuf)-1] == '\n') { + inbuf[strlen(inbuf)-1] = '\0'; + } + if (strlen(inbuf) > TEXT_WIDTH-strlen(PROMPT)) { + need_redraw = 1; + snprintf(inbuf + TEXT_WIDTH - strlen(PROMPT) - 3, + 3, "..."); + } + /* echo user command */ + snprintf(inbuf2, TEXT_WIDTH, "%s%s", PROMPT, inbuf); + print_line(inbuf2, strlen(inbuf2)); + /* process command */ + if (0 == strcmp(inbuf, "quit") || 0 == strcmp(inbuf, "exit")) { + set_cursor_pos(CONSOLE_HEIGHT, 0); + engine_destroy(e); + thr_exit(0); + return 0; + /* Misc management */ + } else if (0 == strcmp(inbuf, "help")) { + help(); + } else if (0 == strcmp(inbuf, "credit")) { + credits(); + } else if (0 == strcmp(inbuf, "loud")) { + if (text_loud) { + print_string("This is as loud as I can be!"); + } else { + print_string("Will now think out loud."); + text_loud = 1; + } + } else if (0 == strcmp(inbuf, "quiet")) { + if (!text_loud) { + print_string("You don't need to ask twice."); + } else { + print_string("OK, I'll keep it to myself."); + text_loud = 0; + } + } else if (0 == strcmp(inbuf, "flip")) { + flipped = !flipped; + if (!need_redraw) draw_board(e->board); + } else if (0 == strcmp(inbuf, "book")) { + book_enabled = !book_enabled; + if (book_enabled) { + print_string("Opening book on."); + e->inbook = 1; + } else { + print_string("Opening book off."); + } + /* Easter eggs */ + } else if (0 == strncmp(inbuf, "punch", 5) || + 0 == strncmp(inbuf, "kill", 4)) { + print_string("Keep your mind on the game."); + } else if (0 == strncmp(inbuf, "hug", 3)) { + print_string("If you think that'll help."); + } else if (0 == strncmp(inbuf, "look", 4) || + 0 == strcmp(inbuf, "north") || 0 == strcmp(inbuf, "n") || + 0 == strcmp(inbuf, "east") || 0 == strcmp(inbuf, "e") || + 0 == strcmp(inbuf, "south") || 0 == strcmp(inbuf, "s") || + 0 == strcmp(inbuf, "west") || 0 == strcmp(inbuf, "w")) { + print_string("This isn't that kind of game."); + } else if (0 == strcmp(inbuf, "inventory")) { + print_string("Nothing. This isn't bughouse."); + } else if (0 == strcmp(inbuf, "ls")) { + print_string("I'll pretend you didn't say that."); + } else if (0 == strcmp(inbuf, "xyzzy")) { + xyzzy++; + if (xyzzy == 0x10) xyzzy = 0; + need_redraw = 1; + /* Game management */ + } else if (0 == strcmp(inbuf, "resign")) { + // Future feature: ask "are you sure?" (also on "new") + if (gameover) { + print_string(nogame); + } else { + print_string("I'm sorry it had to be that way."); + gameover = 1; + status_str = e->board->tomove == WHITE ? + STATUS_WHITERESIGN : STATUS_BLACKRESIGN; + draw_status_str(); + } + } else if (0 == strcmp(inbuf, "hint")) { + trans_data_t trans_data = trans_get(e->board->hash); + if (gameover) { + print_string(nogame); + } else if (trans_data_valid(trans_data)) { + char *move = move_tostring(TRANS_MOVE(trans_data)); + static unsigned int hint_index = 0; + const char *words[] = + { "Consider %s.", "Why not %s?", + "How do you feel about %s?", + "If it were me, I'd play %s." }; + snprintf(inbuf2, TEXT_WIDTH, + words[hint_index++ % ARRAY_SIZE(words)], + move); + print_line(inbuf2, strlen(inbuf2)); + free(move); + } else { + print_string("You're on your own here."); + } + } else if (0 == strcmp(inbuf, "new")) { + gameover = 0; + flipped = 0; + player_mode = bot_black; + status_str = STATUS_WHITEMOVE; + engine_destroy(e); + e = engine_init(getbestmove); + assert(e != NULL); + need_redraw = 1; + } else if (0 == strcmp(inbuf, "human")) { + if (gameover) { + print_string(nogame); + } else { + player_mode = human; + if (!need_redraw) draw_player_str(); + } + } else if (0 == strncmp(inbuf, "depth", 5)) { + // See trac bug #73. Argghhhh. + char *endp; + unsigned int n = strtol(&inbuf[6], &endp, 0); + assert(searcher_max_depth < SEARCHER_MAX_DEPTH); + assert(searcher_max_depth >= SEARCHER_MIN_DEPTH); + if (inbuf[5] != ' ' || endp == &inbuf[6]) { + print_string("Use \"depth N\" to limit max depth."); + snprintf(inbuf2, TEXT_WIDTH, "Currently %u (0 = no limit)", + searcher_max_depth == SEARCHER_MAX_DEPTH-1 ? + 0 : searcher_max_depth); + print_string(inbuf2); + } else { + if (n >= SEARCHER_MAX_DEPTH || n == 0) + n = SEARCHER_MAX_DEPTH-1; + else if (n < SEARCHER_MIN_DEPTH) + n = SEARCHER_MIN_DEPTH; + searcher_max_depth = n; + print_string("OK."); + } + } else if (0 == strncmp(inbuf, "time", 4)) { + // Argghhhh, as above. + char *endp; + unsigned int n = strtol(&inbuf[5], &endp, 0); + assert(searchtime >= 1); + assert(searchtime <= SEARCHTIME_MAX); + if (inbuf[4] != ' ' || endp == &inbuf[5]) { + print_string("Use \"time N\" to limit search time."); + snprintf(inbuf2, TEXT_WIDTH, "Currently %u (max %u)", + searchtime, SEARCHTIME_MAX); + print_string(inbuf2); + } else { + if (n > SEARCHTIME_MAX || n == 0) + n = SEARCHTIME_DEFAULT; + searchtime = n; + print_string("OK."); + } + } else if (0 == strcmp(inbuf, "undo")) { + const char *words1[] = + { "We're at the beginning already.", + "My memories are hazy before this.", + "Stop, you're making me dizzy.", + "Can't take tail of empty list." }; + static unsigned int undo_index = 0; + const char *words2[] = + { "Be more careful next time.", + "I won't judge you; I'm a computer.", + "Sure, as if time travel is easy.", + "You're pushing your luck, kiddo.", + "Next you'll ask for lessons?", + }; + static unsigned int undo_index2 = 0; + if (e->board->moves == 0) { + print_string(gameover ? + "Just accept it and move on." : + words1[undo_index++ % ARRAY_SIZE(words1)]); + } else { + engine_undomove(e); + if (player_mode == bot_white) + player_mode = bot_black; + else if (player_mode == bot_black) + player_mode = bot_white; + flipped = !flipped; + gameover = checkgameover(); // refresh status string + assert(!gameover && "Game over after undo??"); + if (!need_redraw) draw_player_str(); + if (!need_redraw) draw_board(e->board); + if (!need_redraw) draw_status_str(); + print_string(words2[undo_index2++ % + ARRAY_SIZE(words2)]); + } + /* Moving */ + } else if (0 == strcmp(inbuf, "go")) { + if (gameover) { + print_string(nogame); + } else { + player_mode = e->board->tomove == WHITE ? + bot_white : bot_black; + flipped = !flipped; + if (!need_redraw) draw_player_str(); + if (!need_redraw) draw_board(e->board); + makemove(); + if (!need_redraw) draw_board(e->board); + gameover = checkgameover(); + if (!need_redraw) draw_status_str(); + } + } else if (!!move_fromstring(inbuf)) { + char *errmsg = NULL; + if (gameover) { + print_string(nogame); + } else if (engine_applymove(e, inbuf, &errmsg)) { + if ((gameover = checkgameover())) { + print_string("Good game!"); + } else if (player_mode != human) { + /* Make a move in response. */ + if (!need_redraw) draw_status_str(); + if (!need_redraw) draw_board(e->board); + makemove(); + if (!need_redraw) draw_board(e->board); + if ((gameover = checkgameover())) { + print_string("Good game!"); + } + } else { + flipped = !flipped; + if (!need_redraw) draw_board(e->board); + } + if (!need_redraw) draw_status_str(); + } else { + assert(errmsg != NULL); + print_string(errmsg); + } + /* Fail */ + } else { + print_string(strlen(inbuf) ? "I didn't understand that." : + "You'll have to be more specific."); + } + /* Update display to reflect changes */ + if (need_redraw) { + redraw(e->board); + } else { + draw_console(); + draw_prompt(); + } + } + panic("completed infinite loop!"); + return 31337; +} diff --git a/410user/progs/cat.c b/410user/progs/cat.c new file mode 100644 index 0000000..9d2ef97 --- /dev/null +++ b/410user/progs/cat.c @@ -0,0 +1,30 @@ +// Simple program to print out files. +// Michael J. Sullivan, Spring 2013 + +#include +#include +#include + +#define BUFSIZE 87 // "four score and seven" + +int main(int argc, char **argv) +{ + char buf[BUFSIZE]; + int i; + for (i = 1; i < argc; i++) { + char *file = argv[i]; + int offset = 0; + int amt_read; + while ((amt_read = readfile(file, buf, BUFSIZE, offset)) > 0) { + print(amt_read, buf); + offset += amt_read; + } + if (amt_read < 0) { + printf("error reading from file %s at offset %d\n", + file, offset); + return -1; + } + } + + return 0; +} diff --git a/410user/progs/cho.c b/410user/progs/cho.c new file mode 100644 index 0000000..2270a75 --- /dev/null +++ b/410user/progs/cho.c @@ -0,0 +1,103 @@ +/** @file 410user/progs/cho.c + * @author de0u + * @brief "Continuous hours of operation" - runs many tests. + * @public yes + * @for p3 + * @covers fork exec wait set_status vanish sleep + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("cho:"); + +/* Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +#define UPDATE_FREQUENCY 50 + +#define SERIOUSLY_DEAD (0xdeaddead) + +struct prog { + char *name; + int pid; + int count; +} progs[] = { + {"sleep_test1", -1, 13}, + {"wait_getpid", -1, 100}, + {"wild_test1", -1, 100}, + {"exec_basic", -1, 100}, + {"print_basic", -1, 100} +}; + +int main() +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(300); + + fence = progs + active_progs; + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_misc("After fork(): I am a child!"); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed (missing object?)"); + report_end(END_FAIL); + exit(SERIOUSLY_DEAD); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == SERIOUSLY_DEAD) + exit(SERIOUSLY_DEAD); + report_fmt("wait() done: %d with status %d", pid, status); + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs; p < fence; ++p) { + if (p->pid == pid) { + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) { + report_fmt("%s: %d left", p->name, p->count); + } + } + } + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/cho2.c b/410user/progs/cho2.c new file mode 100644 index 0000000..178ebad --- /dev/null +++ b/410user/progs/cho2.c @@ -0,0 +1,108 @@ +/** @file 410user/progs/cho2.c + * @author de0u + * @author ctokar + * @brief "Continuous hours of operation" - run many tests. + * @public yes + * @for p3 + * @covers fork exec wait gettid set_status vanish sleep + * @todo Progress checking? + */ + +#include +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("cho2:"); + +/* Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +#define UPDATE_FREQUENCY 50 + +#define SERIOUSLY_DEAD (0xdeaddead) + +struct prog { + char *name; + int pid; + int count; +} progs[] = { + {"getpid_test1", -1, 13}, + {"yield_desc_mkrun", -1, 100}, + {"remove_pages_test1", -1, 100}, + {"loader_test1", -1, 100}, + {"fork_wait", -1, 100}, + {"swexn_rampage", -1, 1}, + {"mem_permissions", -1, 31}, + {"minclone_mem", -1, 17} +}; + +int main() +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(300); + + fence = progs + active_progs; + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_misc("After fork(): I am a child!"); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed (missing object?)"); + report_end(END_FAIL); + exit(SERIOUSLY_DEAD); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == SERIOUSLY_DEAD) + exit(SERIOUSLY_DEAD); + report_fmt("wait() done: %d with status %d", pid, status); + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs; p < fence; ++p) { + if (p->pid == pid) { + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) { + report_fmt("%s: %d left", p->name, p->count); + } + } + } + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/cho_variant.c b/410user/progs/cho_variant.c new file mode 100644 index 0000000..4485f00 --- /dev/null +++ b/410user/progs/cho_variant.c @@ -0,0 +1,171 @@ +/** @file 410user/progs/cho_variant.c + * @author de0u + * @author ctokar + * @author nwf + * @brief "Continuous hours of operation" - runs many tests. + * @public yes + * @for p3 + * @covers fork exec wait set_status vanish sleep remove_pages new_pages + * @covers deschedule make_runnable yield + * @status done + */ + +#include +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("cho_variant:"); + +/** @brief Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +static const int UPDATE_FREQUENCY = 10; + +/** @brief Error signaling return code. + * @pre Ensure that no test program in the table below returns this + * constant. + */ +static const int DEAD_TEST_PROGRAM_RETURN = 0xDEADDEAD; + +/** @brief Program table */ +struct prog { + char *name; + int expected; + int pid; + int count; +} progs[] + = { + {"exec_basic", 1, -1, 5}, + {"fork_wait", 0, -1, 5}, + {"loader_test1", 0, -1, 5}, + {"loader_test2", 42, -1, 5}, + {"make_crash",10000,-1, 1}, + {"print_basic",0,-1,5}, + {"remove_pages_test1", 0, -1, 2}, + {"remove_pages_test2", -2, -1, 5}, /* Should die: wild pointer */ + {"sleep_test1", 42, -1, 5}, /* indistinguishible outcomes */ + {"stack_test1", 42, -1, 5}, + {"wild_test1", -2, -1, 5}, /* Should die: wild pointer */ + {"yield_desc_mkrun", 0, -1, 5}, +}; + +int main(int argc, char **argv) +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + int matched; + int magic_break = 0; + + if ( argc > 1 ) + { + if ( !strcmp("MAGIC", argv[1]) ) + { + magic_break = 1; + } + } + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(1200); + + fence = progs + active_progs; + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_fmt("after fork(): I am a child (prog %s, tid %d)", + p->name, gettid()); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed"); + /* Leave it to the parent to emit the test failure message */ + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(DEAD_TEST_PROGRAM_RETURN); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == DEAD_TEST_PROGRAM_RETURN) + { + lprintf("%s%s%s", TEST_PFX,test_name,TEST_END_FAIL); + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(-1); + } + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs, matched = 0; p < fence; ++p) { + if (p->pid == pid) { + matched = 1; + lprintf("%s%s After wait(): pid = %d, prog = %s", + TEST_PFX, test_name, pid, p->name); + if ( status != p->expected ) + { + lprintf("=( TEST FAILED: %s; EXPECT %d GOT %d", + p->name, p->expected, status ); + lprintf("%s%s%s", TEST_PFX,test_name,TEST_END_FAIL); + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(-1); + } + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) + { + /* Display progress on softcons as well, in condensed form */ + report_fmt("%s: %d left", p->name, p->count); + printf("[%s,%d]",p->name, p->count); + } + } + if ( matched == 0 ) + { + report_fmt("unexpected waited pid %d (status %d)", pid, status); + report_end(END_FAIL); + if ( magic_break ) + { + MAGIC_BREAK; + } + exit(-1); + } + } + if (reap_count % UPDATE_FREQUENCY == 0) + print(1, "\n"); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/chow.c b/410user/progs/chow.c new file mode 100644 index 0000000..e0c4e02 --- /dev/null +++ b/410user/progs/chow.c @@ -0,0 +1,142 @@ +/** @file 410user/progs/chow.c + * @author acrichto + * @brief "Continuous hours of operation (work)" - + * runs a bunch of user-space code, not just syscalls + * @public yes + * @for p4-smp + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("chow:"); + +/* Every UPDATE_FREQUENCY reaps, print out an update of + * how many children of each type are left. + */ +#define UPDATE_FREQUENCY 50 + +#define SERIOUSLY_DEAD (0xdeaddead) + +struct prog { + char *name; + int pid; + int count; +} progs[] = { + {"fib", -1, 20}, + {"ack", -1, 20}, + {"yield_desc_mkrun", -1, 100}, + {"fork_wait", -1, 100} +}; + +char numbers[10][5][10] = { + {" ___ ", " / _ \\ ", "| | | |", "| |_| |", " \\___/ "}, + {" _ ", "/ |", "| |", "| |", "|_|"}, + {" ____ ", "|___ \\ ", " __) |", " / __/ ", "|_____|"}, + {" _____ ", "|___ / ", " |_ \\ ", " ___) |", "|____/ "}, + {" _ _ ", "| || | ", "| || |_ ", "|__ _|", " |_| "}, + {" ____ ", "| ___| ", "|___ \\ ", " ___) |", "|____/ "}, + {" __ ", " / /_ ", "| '_ \\ ", "| (_) |", " \\___/ "}, + {" _____ ", "|___ |", " / / ", " / / ", " /_/ "}, + {" ___ ", " ( _ ) ", " / _ \\ ", "| (_) |", " \\___/ "}, + {" ___ ", " / _ \\ ", "| (_) |", " \\__, |", " /_/ "}, +}; + +int main() +{ + int active_progs = sizeof (progs) / sizeof (progs[0]); + int active_processes = 0; + struct prog *p, *fence; + int reap_count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(1200); + + fence = progs + active_progs; + int ticks = get_ticks(); + + while ((active_progs > 0) || (active_processes > 0)) { + + /* launch some processes */ + for (p = progs; p < fence; ++p) { + if ((p->count > 0) && (p->pid == -1)) { + int pid = fork(); + + if (pid < 0) { + sleep(1); + } else if (pid == 0) { + char *args[2]; + + report_misc("After fork(): I am a child!"); + TEST_PROG_PROGRESS; + + args[0] = p->name; + args[1] = 0; + exec(p->name, args); + report_misc("exec() failed (missing object?)"); + report_end(END_FAIL); + exit(SERIOUSLY_DEAD); + } else { + p->pid = pid; + ++active_processes; + } + } + } + + /* reap a child */ + if (active_processes > 0) { + int pid, status; + pid = wait(&status); + if (status == SERIOUSLY_DEAD) + exit(SERIOUSLY_DEAD); + report_fmt("wait() done: %d with status %d", pid, status); + TEST_PROG_PROGRESS; + ++reap_count; + for (p = progs; p < fence; ++p) { + if (p->pid == pid) { + p->pid = -1; + --p->count; + if (p->count <= 0) + --active_progs; + --active_processes; + } + if (reap_count % UPDATE_FREQUENCY == 0) { + report_fmt("%s: %d left", p->name, p->count); + } + } + } + } + + ticks = get_ticks() - ticks; + + int pow = 10; + while (pow * 10 < ticks) pow *= 10; + + printf("\n" + "*****************************************************************\n" + "\n" + " Total ticks taken\n" + "\n"); + + int i; + for (i = 0; i < 5; i++) { + printf(" "); + int tmp = ticks; + int tmppow = pow; + + while (tmppow > 0) { + printf("%s ", numbers[(tmp / tmppow) % 10][i]); + tmppow /= 10; + } + printf("\n"); + } + printf("\n" + "*****************************************************************\n"); + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/ck1.c b/410user/progs/ck1.c new file mode 100644 index 0000000..c5aca41 --- /dev/null +++ b/410user/progs/ck1.c @@ -0,0 +1,26 @@ +/** @file 410user/progs/ck1.c + * @author ? + * @author elly1 + * @brief Runs the checkpoint 1 script. + * @public yes + * @for p3 + * @covers gettid + * @status done + */ + +#include /* gettid() */ +#include /* lprintf() */ + +/* Main */ +int main() +{ + int tid; + + sim_ck1(); + tid = gettid(); + + lprintf("my tid is: %d", tid); + + while (1) + continue; +} diff --git a/410user/progs/coolness.c b/410user/progs/coolness.c new file mode 100644 index 0000000..b37d4a6 --- /dev/null +++ b/410user/progs/coolness.c @@ -0,0 +1,26 @@ +/** @file 410user/progs/coolness.c + * @author de0u + * @brief Tests fork, exec, and context-switching. + * @public yes + * @for p3 + * @covers fork gettid exec + * @status done + */ + +#include +#include + +char *program = "peon"; +char *args[2]; + +int main() { + + fork(); + args[0] = program; + fork(); + + exec(program, args); + + while(1) + lprintf("ULTIMATE BADNESS"); +} diff --git a/410user/progs/deschedule_hang.c b/410user/progs/deschedule_hang.c new file mode 100644 index 0000000..7f63a5e --- /dev/null +++ b/410user/progs/deschedule_hang.c @@ -0,0 +1,32 @@ +/** @file 410user/progs/deschedule_hang.c + * @author mpa + * @brief Tests that deschedule() doesn't return without a corresponding + * make_runnable() call. + * @public yes + * @for p3 + * @covers deschedule + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("deschedule_hang:"); + +int main() +{ + int error, reject; + report_start(START_4EVER); + + reject = 0; + /* stop running for quite a while */ + error = deschedule(&reject); + + report_fmt("deschedule() returned %d", error); + + report_end(END_FAIL); + exit(1); +} diff --git a/410user/progs/exec_basic.c b/410user/progs/exec_basic.c new file mode 100644 index 0000000..5cd2f6d --- /dev/null +++ b/410user/progs/exec_basic.c @@ -0,0 +1,33 @@ +/** @file 410user/progs/exec_basic.c + * @author mpa + * @brief Tests basic functionality of exec() + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("exec_basic:"); + +int main() +{ + + REPORT_LOCAL_INIT; + + char *name = "exec_basic_helper"; + char *args[] = {name, 0}; + + REPORT_START_CMPLT; + + REPORT_ON_ERR(exec(name,args)); + + REPORT_END_FAIL; + + exit(-1); +} diff --git a/410user/progs/exec_basic_helper.c b/410user/progs/exec_basic_helper.c new file mode 100644 index 0000000..c36b6be --- /dev/null +++ b/410user/progs/exec_basic_helper.c @@ -0,0 +1,25 @@ +/** @file 410user/progs/exec_basic_helper.c + * @author mpa + * @brief Run by exec_basic to test exec. + * @public yes + * @for p3 + * @covers nothing + * @status done + * @note Helper. + */ + +#include +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("exec_basic:"); + +int main() +{ + REPORT_MISC("exec_basic_helper main() starting..."); + REPORT_END_SUCCESS; + + exit(1); +} diff --git a/410user/progs/exec_nonexist.c b/410user/progs/exec_nonexist.c new file mode 100644 index 0000000..f2cb8dd --- /dev/null +++ b/410user/progs/exec_nonexist.c @@ -0,0 +1,31 @@ +/** @file 410user/progs/exec_nonexist.c + * @author mpa + * @brief Tests exec()ing a nonexistent file. + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("exec_nonexist:"); + +int main() { + char *name = "exec_a_random_file_that_does_not_exist"; + char *args[] = {name, 0}; + report_start(START_CMPLT); + + if (exec(name,args) >= 0) { + report_misc("exec() did not return an error code"); + report_end(END_FAIL); + exit(-1); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/fib.c b/410user/progs/fib.c new file mode 100644 index 0000000..4dc3ae9 --- /dev/null +++ b/410user/progs/fib.c @@ -0,0 +1,49 @@ +/** @file 410user/progs/fib.c + * @author acrichto + * @brief Computes Fibonacci series in multiple threads + * @public yes + * @for p4-smp + * @status done + */ + +#include <410_tests.h> +#include +#include +#include +#include + +DEF_TEST_NAME("fib:"); + +#define THREADS 8 +#define FIBN 32 + +typedef void*(thr_func)(void*); + +int fib(int n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +int main() { + thr_init(4096); + int ticks = get_ticks(); + int i, answer, guess; + thrgrp_group_t group; + + REPORT_ON_ERR(thrgrp_init_group(&group)); + for (i = 0; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_create(&group, (thr_func*) fib, (void*) FIBN)); + } + + REPORT_ON_ERR(thrgrp_join(&group, (void*) &answer)); + for (i = 1; i < THREADS; i++) { + REPORT_ON_ERR(thrgrp_join(&group, (void*) &guess)); + if (guess != answer) { + REPORT_END_FAIL; + } + } + printf("fib(%d) = %d\n", FIBN, answer); + printf("ticks taken: %d\n", get_ticks() - ticks); + + thr_exit(0); +} diff --git a/410user/progs/fork_bomb.c b/410user/progs/fork_bomb.c new file mode 100644 index 0000000..a64754f --- /dev/null +++ b/410user/progs/fork_bomb.c @@ -0,0 +1,27 @@ +/** @file 410user/progs/fork_bomb.c + * @author zra + * @brief Tests fork() in low-memory conditions. + * @public yes + * @for p3 + * @covers fork oom + * @status done + */ + +/* Includes */ +#include /* for fork */ +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("fork_bomb:"); + +/* Main */ +int main() { + report_start(START_4EVER); + TEST_PROG_ENGAGE(200); + + while (1) { + fork(); + TEST_PROG_PROGRESS; + } +} diff --git a/410user/progs/fork_exit_bomb.c b/410user/progs/fork_exit_bomb.c new file mode 100644 index 0000000..a0a8fbc --- /dev/null +++ b/410user/progs/fork_exit_bomb.c @@ -0,0 +1,41 @@ +/** @file 410user/progs/fork_exit_bomb.c + * @author ? + * @brief Tests many invocations of fork/exit + * @public yes + * @for p3 + * @covers fork set_status vanish + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("fork_exit_bomb:"); + +int main(int argc, char *argv[]) { + int pid = 0; + int count = 0; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(200); + + lprintf("parent pid: %d", gettid()); + + while(count < 1000) { + if((pid = fork()) == 0) { + exit(42); + } + if(pid < 0) { + break; + } + count++; + report_fmt("child: %d", pid); + TEST_PROG_PROGRESS; + } + + report_end(END_SUCCESS); + exit(42); +} diff --git a/410user/progs/fork_test1.c b/410user/progs/fork_test1.c new file mode 100644 index 0000000..45fa9d6 --- /dev/null +++ b/410user/progs/fork_test1.c @@ -0,0 +1,41 @@ +/** @file 410user/progs/fork_test1.c + * @author zra + * @brief Tests basic functionality of fork() + * @public yes + * @for p3 + * @covers fork + * @status done + */ + +/* Includes */ +#include /* for fork, getpid */ +#include /* for exit */ +#include /* for lprintf */ +#include "410_tests.h" +#include + +DEF_TEST_NAME("fork_test1:"); + +/* Main */ +int main(int argc, char *argv[]) +{ + int pid; + + report_start(START_CMPLT); + pid = fork(); + + if( pid < 0 ) { + report_end(END_FAIL); + exit(-1); + } + + if( pid > 0 ) { + report_fmt("parent: tid = %d", gettid()); + } + else { + report_fmt("child: tid = %d", gettid()); + } + + report_end(END_SUCCESS); + exit( 1 ); +} diff --git a/410user/progs/fork_wait.c b/410user/progs/fork_wait.c new file mode 100644 index 0000000..791e3e4 --- /dev/null +++ b/410user/progs/fork_wait.c @@ -0,0 +1,46 @@ +/** @file 410user/progs/fork_wait.c + * @author zra + * @brief Tests fork() and wait(). + * @public yes + * @for p3 + * @covers fork wait set_status vanish + * @status done + */ + +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("fork_wait:"); + +int main() +{ + int pid, status; + + report_start(START_CMPLT); + pid = fork(); + + if (pid < 0) { + report_end(END_FAIL); + exit(-1); + } + + if (pid == 0) { + exit(17); + report_end(END_FAIL); /* panic("vanish() didn't"); */ + } + + if (wait(&status) != pid) { + report_end(END_FAIL); + exit(-1); + } + + if (status != 17) { + report_end(END_FAIL); + exit(-1); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/fork_wait_bomb.c b/410user/progs/fork_wait_bomb.c new file mode 100644 index 0000000..bb5581b --- /dev/null +++ b/410user/progs/fork_wait_bomb.c @@ -0,0 +1,50 @@ +/** @file 410user/progs/fork_wait_bomb.c + * @author ? + * @brief Tests fork, wait, and exit in stress conditions. + * @public yes + * @for p3 + * @covers fork wait set_status vanish + * @status done + */ + +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("fork_wait_bomb:"); + +int main(int argc, char *argv[]) { + int pid = 0; + int count = 0; + int ret_val; + int wpid; + + report_start(START_CMPLT); + TEST_PROG_ENGAGE(200); + report_fmt("parent: %d", gettid()); + + while(count < 1000) { + if((pid = fork()) == 0) { + exit(42); + } + if(pid < 0) { + break; + } + + count++; + + report_fmt("child: %d", pid); + TEST_PROG_PROGRESS; + + wpid = wait(&ret_val); + + if(wpid != pid || ret_val != 42) { + report_end(END_FAIL); + exit(42); + } + } + + report_end(END_SUCCESS); + exit(42); +} diff --git a/410user/progs/getpid_test1.c b/410user/progs/getpid_test1.c new file mode 100644 index 0000000..5f45a3d --- /dev/null +++ b/410user/progs/getpid_test1.c @@ -0,0 +1,34 @@ +/** @file 410user/progs/getpid_test1.c + * @author zra + * @brief Tests gettid(). + * @public yes + * @for p2 p3 + * @covers gettid + * @status done + */ + +/* Includes */ +#include "410_tests.h" +#include +#include /* for lprintf */ +#include /* for exit */ +#include /* for getpid */ + +DEF_TEST_NAME("getpid_test1:"); + +/* Main */ +int main() { + int pid; + + report_start(START_CMPLT); + pid = gettid(); + lprintf("%s my pid is: %d", test_name, pid); + + if (pid == gettid()) { + report_end(END_SUCCESS); + exit(0); + } else { + report_end(END_FAIL); + exit(-1); + } +} diff --git a/410user/progs/halt_test.c b/410user/progs/halt_test.c new file mode 100644 index 0000000..65a5b3a --- /dev/null +++ b/410user/progs/halt_test.c @@ -0,0 +1,26 @@ +/** @file 410user/progs/halt_test.c + * @author mpa + * @brief Tests the basic functionality of halt() + * @public yes + * @for p2 p3 + * @covers halt + * @status done + */ + +#include +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("halt_test:"); + +int main() +{ + REPORT_START_ABORT; + + halt(); + + REPORT_END_FAIL; + exit(-1); +} diff --git a/410user/progs/idle.c b/410user/progs/idle.c new file mode 100644 index 0000000..e50c6d1 --- /dev/null +++ b/410user/progs/idle.c @@ -0,0 +1,14 @@ +/** @file 410user/progs/idle.c + * @author ? + * @brief Idle program. + * @public yes + * @for p2 p3 + * @covers + * @status done + */ + +int main() +{ + while (1) { + } +} diff --git a/410user/progs/init.c b/410user/progs/init.c new file mode 100644 index 0000000..f61e1a7 --- /dev/null +++ b/410user/progs/init.c @@ -0,0 +1,28 @@ +/** @file 410user/progs/init.c + * @author ? + * @brief Initial program. + * @public yes + * @for p2 p3 + * @covers fork exec wait print + * @status done + */ + +#include +#include + +int main() +{ + int pid, exitstatus; + char shell[] = "shell"; + char * args[] = {shell, 0}; + + while(1) { + pid = fork(); + if (!pid) + exec(shell, args); + + while (pid != wait(&exitstatus)); + + printf("Shell exited with status %d; starting it back up...", exitstatus); + } +} diff --git a/410user/progs/knife.c b/410user/progs/knife.c new file mode 100644 index 0000000..f982f09 --- /dev/null +++ b/410user/progs/knife.c @@ -0,0 +1,43 @@ +/** @file 410user/progs/knife.c + * @author mpa + * @brief Tests fork and context-switching. + * @public yes + * @for p3 + * @covers fork gettid + * @status done + */ + +#include +#include +#include + +#define DELAY (16*1024) + +int gcc_please_do_not_optimize_too_much = 0; + +void foo() { + ++gcc_please_do_not_optimize_too_much; +} + +/* this function eats up a bunch of cpu cycles */ +void slow() { + int i; + + for (i = 0; i < DELAY; i++) foo(); +} + +int main() { + + int tid; + + if ((tid = fork()) == 0) + while(1) { + slow(); + lprintf("child: %d", gettid()); + } + else + while(1) { + slow(); + lprintf("parent: %d\t\tchild:%d", gettid(), tid); + } +} diff --git a/410user/progs/loader_test1.c b/410user/progs/loader_test1.c new file mode 100644 index 0000000..68d389e --- /dev/null +++ b/410user/progs/loader_test1.c @@ -0,0 +1,94 @@ +/** @file 410user/progs/loader_test1.c + * @author ? + * @author nwf + * @brief Tests loading of .data and .bss + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("loader_test1:"); + +int feed = 0xfeed; +int face = 0xface; +char x[8192] = { 1, 2, 3 }; +int face2 = 0xface; +void *self = (void *)&self; +const void *cself = (void *)&cself; +int fred; + +int main(int argc, char** argv) { + + int *ip; + int ret=0; + + report_start(START_CMPLT); + + if (feed != 0xfeed) { + /* fatal */ + report_misc(".data contains the wrong value"); + report_end(END_FAIL); + ret--; + } + + if (face != 0xface) { + /* fatal */ + report_misc(".data contains the wrong value"); + report_end(END_FAIL); + ret--; + } + + ip = &feed; + ++ip; + +#ifdef notdef +// This was not promised by the language but was essentially +// always true... "fixed" by gcc 4.6.1-9 [gbrunsta] + if (*ip != 0xface) { + /* fatal */ + report_misc(".data out of order... how did the previous two tests work?"); + report_end(END_FAIL); + ret--; + } +#endif + + if (fred) { + /* fatal */ + report_misc(".bss not zeroed"); + report_end(END_FAIL); + ret--; + } + + if (face2 != 0xface) { + /* fatal */ + report_misc(".data contains wrong value"); + report_end(END_FAIL); + ret--; + } + + if (&feed >= &fred) { + /* fatal -- if even observable */ + report_misc("linker botch???"); + report_end(END_FAIL); + ret--; + } + + if ((self != (void *)&self) || (cself != (void *)&cself)) { + report_misc("One of the flay-rods has gone out askew on the treadle!"); + report_end(END_FAIL); + ret--; + } + + if(ret==0) + { + report_end(END_SUCCESS); + return 0; + } + exit(42); +} diff --git a/410user/progs/loader_test2.c b/410user/progs/loader_test2.c new file mode 100644 index 0000000..8183ae0 --- /dev/null +++ b/410user/progs/loader_test2.c @@ -0,0 +1,273 @@ +/** @file 410user/progs/loader_test2.c + * @author ? + * @brief Tests loading large code sections. + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("loader_test2:"); + +void foo(void); +void bar(void); +void no44(void); + +extern int zipper; + +int main(int argc, char** argv) { + report_start(START_CMPLT); + + foo(); + bar(); + + if (zipper != 45) { + report_misc("FAILED: code overwriting data?"); + no44(); + report_end(END_FAIL); + exit(-1); + } else { + report_end(END_SUCCESS); + exit(42); + } + +} + +void foo(void) { + /* print something encouraging */ + report_misc("first called worked"); +} + +void no0(void) { + /* fatal */ + report_end(END_FAIL); +} + +void no1(void) { + /* fatal */ + no0(); +} + +void no2(void) { + /* fatal */ + no1(); +} + +void no3(void) { + /* fatal */ + no2(); +} + +void no4(void) { + /* fatal */ + no3(); +} + +void no5(void) { + /* fatal */ + no4(); +} + +void no6(void) { + /* fatal */ + no5(); +} + +void no7(void) { + /* fatal */ + no6(); +} + +void no8(void) { + /* fatal */ + no7(); +} + +void no9(void) { + /* fatal */ + no8(); +} + +void no10(void) { + /* fatal */ + no9(); +} + +void no11(void) { + /* fatal */ + no10(); +} + +void no12(void) { + /* fatal */ + no11(); +} + +void no13(void) { + /* fatal */ + no12(); +} + +void no14(void) { + /* fatal */ + no13(); +} + +void no15(void) { + /* fatal */ + no14(); +} + +void no16(void) { + /* fatal */ + no15(); +} + +void no17(void) { + /* fatal */ + no16(); +} + +void no18(void) { + /* fatal */ + no17(); +} + +void no19(void) { + /* fatal */ + no18(); +} + +void no20(void) { + /* fatal */ + no19(); +} +void no21(void) { + /* fatal */ + no20(); +} + +void no22(void) { + /* fatal */ + no21(); +} + +void no23(void) { + /* fatal */ + no22(); +} + +void no24(void) { + /* fatal */ + no23(); +} + +void no25(void) { + /* fatal */ + no24(); +} + +void no26(void) { + /* fatal */ + no25(); +} + +void no27(void) { + /* fatal */ + no26(); +} + +void no28(void) { + /* fatal */ + no27(); +} +void no29(void) { + /* fatal */ + no28(); +} + +void no30(void) { + /* fatal */ + no29(); +} + +void no31(void) { + /* fatal */ + no30(); +} + +void no32(void) { + /* fatal */ + no31(); +} + +void no33(void) { + /* fatal */ + no32(); +} + +void no34(void) { + /* fatal */ + no33(); +} + +void no35(void) { + /* fatal */ + no34(); +} + +void no36(void) { + /* fatal */ + no35(); +} + +void no37(void) { + /* fatal */ + no36(); +} + +void no38(void) { + /* fatal */ + no37(); +} + +void no39(void) { + /* fatal */ + no38(); +} + +void no40(void) { + /* fatal */ + no39(); +} + +void no41(void) { + /* fatal */ + no40(); +} + +void no42(void) { + /* fatal */ + no41(); +} + +void no43(void) { + /* fatal */ + no42(); +} + +void no44(void) { + /* fatal */ + no43(); +} + +void bar(void) { + report_misc("second call worked"); +} + +int zipper=45; diff --git a/410user/progs/make_crash.c b/410user/progs/make_crash.c new file mode 100644 index 0000000..7cece01 --- /dev/null +++ b/410user/progs/make_crash.c @@ -0,0 +1,50 @@ +/** @file 410user/progs/make_crash.c + * @author rsa + * @author kcaffrey + * @brief Forkbombs, sleeps for a while, then exec()s a helper + * @public yes + * @for p3 + * @covers fork, exec, wait + * @status done + */ + +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME ("make_crash:"); + +int main(int argc, char **argv) { + int i, tid, status; + int parentTID = gettid (); + char *name = "make_crash_helper"; + char s_parentTID[11]; + sprintf(s_parentTID, "%d", parentTID); + char *argvec[] = {name, "evil test", s_parentTID, 0}; + char buf[100]; + REPORT_START_CMPLT; + + REPORT_MISC("This test brought to you by Group 35 (Fall 03) - rsa & kcaffrey\n"); + REPORT_MISC("Starting forks"); + + for(i=0; i<7; i++) { + if ((tid=fork())==0) { + sprintf(buf, " Starting sleep I am %d", gettid()); + REPORT_MISC(buf); + sleep(100); + } + } + + sprintf(buf, " Done with my forks, I am %d", gettid()); + REPORT_MISC(buf); + + while ((tid=wait(&status))>=0) { + sprintf(buf, " Reaped child %d with status %d, I am %d", tid, status, gettid()); + REPORT_MISC(buf); + } + + sleep(200); + exec(name, argvec); + + return -40; +} diff --git a/410user/progs/make_crash_helper.c b/410user/progs/make_crash_helper.c new file mode 100644 index 0000000..a5aa63e --- /dev/null +++ b/410user/progs/make_crash_helper.c @@ -0,0 +1,41 @@ +/** @file 410user/progs/make_crash_helper.c + * @author rza + * @author kcaffrey + * @brief Helper for make_crash. Forks and checks its tid. + * @public yes + * @for p3 + * @covers gettid fork + * @status done + * @note Helper. + */ + +#include +#include +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("make_crash:"); + +int main(int argc, char **argv) { + if (argc < 3) { + return -50; + } + char buf[200]; + sprintf(buf, " My program is %s, my argument is %s and %s TID=%d", argv[0], argv[1], argv[2], gettid()); + REPORT_MISC(buf); + + if (fork()==0) + return 0; + + REPORT_MISC(" I am an exec-ed parent"); + + /* Should print when parent execs and exits */ + if (gettid() == atoi(argv[2])) { + REPORT_END_SUCCESS; + return 10000; + } + + return gettid(); +} diff --git a/410user/progs/mem_eat_test.c b/410user/progs/mem_eat_test.c new file mode 100644 index 0000000..7e29275 --- /dev/null +++ b/410user/progs/mem_eat_test.c @@ -0,0 +1,58 @@ +/** @file 410user/progs/mem_eat_test.c + * @author ? + * @brief Grows the stack until it dies. + * @public yes + * @for p3 + * @covers oom autostack + * @status done + */ + +#include +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("mem_eat_test:"); + +#define MEGABYTE (1024*1024) +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +void touch_array(char *p); +void foo(int index); + +int main(int argc, char *argv[]) { + report_start(START_ABORT); + foo(1); + report_end(END_FAIL); + return 42; +} + +/* touch one byte per page to run faster. + * this code is a separate function so gcc doesn't optimize + * away the array writing. + */ +void touch_array(char *p) { + int i; + for(i = MEGABYTE - 1; i >= 0; i -= PAGE_SIZE) { + p[i] = 'a'; + } +} + +void foo(int index) +{ + char local_array[MEGABYTE]; + + if (index == INT_MAX) + // We will never get here. But the notion that we might get + // here defeats clang's clever infinite-recursion detector. + return; + + touch_array(local_array); + + report_fmt("used %d pages = %d MB", index * (MEGABYTE / PAGE_SIZE), index); + foo(index + 1); +} diff --git a/410user/progs/mem_permissions.c b/410user/progs/mem_permissions.c new file mode 100644 index 0000000..eb6cc46 --- /dev/null +++ b/410user/progs/mem_permissions.c @@ -0,0 +1,98 @@ +/** @file 410user/progs/mem_permissions.c + * @author mpa + * @brief Tests memory permissions. + * @public yes + * @for p3 + * @covers vm + * @status done + */ + +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("mem_permissions:"); + +/* forks off a task to die writing to the address */ +void attempt_write(int *addr) +{ + int pid, pid2, status = 333; + REPORT_LOCAL_INIT; + + REPORT_FAILOUT_ON_ERR((pid = fork())); + + if (pid == 0) { + *addr = 42; + + REPORT_END_FAIL; + exit(42); + } + + REPORT_FAILOUT_ON_ERR((pid2 = wait(&status))); + + if (pid != pid2) { + report_fmt("Bad pid %d (should be %d)", pid2, pid); + REPORT_END_FAIL; + exit(42); + } + if (status >= 0) { + report_fmt("Bad status %d", status); + REPORT_END_FAIL; + exit(42); + } + report_fmt("Good: attempt_write(0x%x)", addr); +} + +/* forks off a task to die reading from the address */ +void attempt_read(int *addr) +{ + int pid, pid2, status = 444; + REPORT_LOCAL_INIT; + + REPORT_FAILOUT_ON_ERR((pid = fork())); + + if (pid == 0) { + pid = *addr; + + REPORT_END_FAIL; + exit(pid); + } + + REPORT_FAILOUT_ON_ERR((pid2 = wait(&status))); + + if (pid != pid2) { + report_fmt("Bad pid %d (should be %d)", pid2, pid); + REPORT_END_FAIL; + exit(42); + } + if (status >= 0) { + report_fmt("Bad status %d", status); + REPORT_END_FAIL; + exit(42); + } + report_fmt("Good: attempt_read(0x%x)", addr); +} + +const char header[4096] = "push rodata onto its own page"; +const char array[] = "constant"; +const char trailer[4096] = "push other things off of rodata page"; + +int main() +{ + REPORT_START_CMPLT; + + /* try reading/writing kernel memory */ + attempt_read((int *)0x500000); + attempt_write((int *)0x500000); + + /* try writing rodata section */ + attempt_write((int *)array); + + /* try writing text secion */ + attempt_write((int *)main); + + REPORT_END_SUCCESS; + + exit(0); +} diff --git a/410user/progs/merchant.c b/410user/progs/merchant.c new file mode 100644 index 0000000..daa5713 --- /dev/null +++ b/410user/progs/merchant.c @@ -0,0 +1,59 @@ +/** @file 410user/progs/merchant.c + * @author mpa + * @brief Tests basic functionality of exec() + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include +#include +#include +#include + +#define DELAY (16*1024) + +int gcc_please_do_not_optimize_too_much = 0; + +void foo() { + ++gcc_please_do_not_optimize_too_much; +} + +/* this function eats up a bunch of cpu cycles */ +void slow() { + int i; + + for (i = 0; i < DELAY; i++) foo(); +} + +int main(int argc, char **argv) { + + int tid = gettid(); + + char buf[16]; + char msg[128]; + + sprintf(buf, "%d", tid); + + /* select a message to print out */ + if (argc != 4) + sprintf(msg, + "WARNING: incorrect number of arguments - got %d, expected %d", + argc, + 4); + else if (strcmp("merchant", argv[0]) != 0 || + strcmp("13", argv[1]) != 0 || + strcmp("foo bar", argv[2]) != 0) + sprintf(msg, "WARNING: incorrect arguments"); + else if (strcmp(argv[3], buf)) + sprintf(msg, "WARNING: tid changed"); + else + sprintf(msg, "Hello!"); + + /* print message forever */ + while(1) { + slow(); + lprintf("Message from merchant #%d:\t%s", tid, msg); + } +} diff --git a/410user/progs/minclone_many.S b/410user/progs/minclone_many.S new file mode 100644 index 0000000..27c4546 --- /dev/null +++ b/410user/progs/minclone_many.S @@ -0,0 +1,177 @@ +/** + * @file minclone_many.S + * @author nwf + * @author de0u + * @brief Spawn many threads within a task: + * 128 blocks of 64 threads, with + * occasional pauses for cleanup. + * @public yes + * @for p3 + */ + +#include "410_tests.h" +#include + +.section .rodata + +test_name: + .string "minclone_many:" +str3str: + .string "%s%s%s" +str_thread: + .string "%s: hello from tid %d in block %d" +test_start: + .string TEST_START_CMPLT +test_error: + .string TEST_END_FAIL +test_finish: + .string TEST_END_SUCCESS +test_pfx: + .string TEST_PFX + +line_fmt: + .string "%02X " + +str_T: + .string "T" +str_bang: + .string "!" +str_newline: + .string "\n" +.align 4 +/* syscall packets for print() */ +print_T_args: + .long 1 + .long str_T +print_bang_args: + .long 1 + .long str_bang +print_newline_args: + .long 1 + .long str_newline + +.section .text + +/* Created threads avoid using the original thread's stack. + * XXX Arguably better: array hosting thread stacks. + */ + +.global main +main: + pushl %ebp + movl %esp,%ebp + + /* REPORT_START_CMPLT */ + pushl $test_start + pushl $test_name + pushl $test_pfx + pushl $str3str + call lprintf + movl %ebp,%esp + + /* set_status(-17) */ + movl $-17,%esi + int $SET_STATUS_INT + + /* Engage grading-harness progress sensor */ + /* sim_fr_prog(30) */ + movl $30, %ecx + movl $SIM_FR_PROG, %ebx + xchg %bx, %bx + + movl $128, %edx /* %edx = block count */ + +block_loop: + /* printf("%02x ", block) */ + pushl %ecx + pushl %edx + pushl $line_fmt + call printf + popl %eax + popl %edx + popl %ecx + + movl $64, %ecx /* %ecx = per-block thread count */ + +thread_loop: + int $THREAD_FORK_INT + cmpl $0x0, %eax + jg parent_thread + jl error + +spawned_thread: + /* Declare progress to grading harness */ + /* sim_fr_here() */ + movl $SIM_FR_HERE, %ebx + xchg %bx, %bx + + /* print(1, "T") */ + movl $print_T_args, %esi + int $PRINT_INT + + int $VANISH_INT + +parent_thread: + decl %ecx + jne thread_loop + + /* sleep(7) -- hopefully enough for the threads to finish */ + movl $7,%esi + int $SLEEP_INT + + /* print(1, "\n") */ + movl $print_newline_args, %esi + int $PRINT_INT + + decl %edx + jne block_loop + +finish: + /* REPORT_END_SUCCESS */ + pushl $test_finish + pushl $test_name + pushl $test_pfx + pushl $str3str + call lprintf + movl %ebp,%esp + pushl $1 + pushl $test_name + call sim_update_scoreboard + movl %ebp,%esp + + /* set_status(0) */ + movl $0x0,%esi + int $SET_STATUS_INT + + int $VANISH_INT + +error: + /* print(1, "!") */ + movl $print_bang_args, %esi + int $PRINT_INT + + /* sleep(7) -- hopefully drain out broken partial block of threads */ + movl $7,%esi + int $SLEEP_INT + + /* print(1, "\n") */ + movl $print_newline_args, %esi + int $PRINT_INT + + /* REPORT_END_FAIL */ + pushl $test_error + pushl $test_name + pushl $test_pfx + pushl $str3str + call lprintf + call printf + movl $print_newline_args, %esi + int $PRINT_INT + movl %ebp,%esp + pushl $0 + pushl $test_name + call sim_update_scoreboard + movl %ebp,%esp + + int $VANISH_INT + diff --git a/410user/progs/minclone_mem.S b/410user/progs/minclone_mem.S new file mode 100644 index 0000000..0cef2f5 --- /dev/null +++ b/410user/progs/minclone_mem.S @@ -0,0 +1,78 @@ +/** @file 410user/progs/minclone_mem.S + * @author mpa + * @brief Tests sharing of memory in thread_fork + * @public yes + * @for p3 + * @covers thread_fork + * @status needswork + */ + +#include "410_tests.h" +#include "syscall_int.h" + +.global main + +test_name: + .string "minclone_mem:" +str: + .string "%s%s%s" +test_start: + .string TEST_START_CMPLT +test_pfx: + .string TEST_PFX +test_end_success: + .string TEST_END_SUCCESS + + +.comm hpvar,4,4 + +main: + pushl %ebp + movl %esp,%ebp + + pushl $test_start + pushl $test_name + pushl $test_pfx + pushl $str + call lprintf + + movl $0x0,hpvar + addl $0x4,%esp + movl $0x0,4(%esp) + + /* fork a thread */ + int $THREAD_FORK_INT + + cmpl $0x0,%eax + je child + +parent: + movl $0x172,4(%esp) /* signal child */ +loop: + cmpl $0xbacacaba,hpvar /* wait to be signaled */ + jne loop + + /* Ok, test was successful... */ + + pushl $test_end_success + pushl $test_name + pushl $test_pfx + pushl $str + call lprintf + + /* exit(0) */ + movl $0x0,%esi + int $SET_STATUS_INT + int $VANISH_INT + + leave + ret + + +child: + cmpl $0x172,4(%esp) /* wait to be signaled */ + jne child + + movl $0xbacacaba,hpvar /* signal parent */ + + int $VANISH_INT /* bye-bye */ diff --git a/410user/progs/new_pages.c b/410user/progs/new_pages.c new file mode 100644 index 0000000..749c02b --- /dev/null +++ b/410user/progs/new_pages.c @@ -0,0 +1,95 @@ +/** @file 410user/progs/new_pages.c + * @author de0u + * @brief Tests new_pages() a lot. + * @public yes + * @for p3 + * @covers new_pages + * @status done + */ + +/* Here's what we do */ +int new_stack(void); /* new_pages() into the stack */ +int new_data(void); /* new_pages() into data region */ +int lotsa_luck(void); /* new_pages() "too much" memory */ + +#include +#include +#include +#include +#include "410_tests.h" +#include +#include + +/* Yes, I mean this--see below */ +#define TEST_NAME "new_pages:" +DEF_TEST_NAME(TEST_NAME); + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +#define PAGE_BASE(a) (((int)(a)) & ~(PAGE_SIZE - 1)) + +int main(int argc, char *argv[]) { + int rets[3], i; + char mbuf[256]; + + REPORT_START_CMPLT; + + rets[0] = new_stack(); + rets[1] = new_data(); + rets[2] = lotsa_luck(); + + for (i = 0; i < sizeof (rets) / sizeof (rets[0]); ++i) { + if (rets[i] == 0) { + REPORT_MISC("I *want* my outs to count!!!"); /* Christine Lavin */ + report_fmt("died on %d", i); + REPORT_END_FAIL; + exit(71); + } + } + + format_end(mbuf, sizeof(mbuf), END_SUCCESS); + + exhaustion(exit_success, mbuf); + + REPORT_END_SUCCESS; + exit(0); +} + +int +new_stack(void) +{ + int answer = 42; + int ret; + + ret = new_pages((void *)PAGE_BASE((&answer)), PAGE_SIZE); + if (answer != 42) { + REPORT_MISC("My brain hurts!"); /* T.F. Gumby */ + REPORT_END_FAIL; + exit(71); + } + return (ret); +} + +int +new_data(void) +{ + int ret; + + ret = new_pages((void *)PAGE_BASE(test_name), PAGE_SIZE); + if (strcmp(test_name, TEST_NAME)) { + report_misc("new_pages() killed .data?"); + REPORT_END_FAIL; + exit(71); + } + return (ret); +} + +#define ADDR 0x40000000 +#define GIGABYTE (1024*1024*1024) + +int +lotsa_luck(void) +{ + return (new_pages((void *)ADDR, GIGABYTE)); +} diff --git a/410user/progs/new_shell.c b/410user/progs/new_shell.c new file mode 100644 index 0000000..e3a0135 --- /dev/null +++ b/410user/progs/new_shell.c @@ -0,0 +1,27 @@ +/** @file new_shell.c + * @brief This program tests the new_console() syscall by spawning a + * new shell + * + * @author Geoffrey G. Wilson (ggw) + * @author E. Chaos Golubitsky (egolubit) + * + */ +#include +#include + +int main() +{ + char *argvec[] = { "shell", 0} ; + + if (!(fork())) { + printf("i am thread %d; about to switch consoles\n", gettid()); + if (new_console() < 0) { + printf("failed to create new console\n"); + return(-1); + } else { + exec(argvec[0], argvec); + } + } + + return(0); +} diff --git a/410user/progs/peon.c b/410user/progs/peon.c new file mode 100644 index 0000000..2a37bb5 --- /dev/null +++ b/410user/progs/peon.c @@ -0,0 +1,35 @@ +/** @file 410user/progs/peon.c + * @author mpa + * @brief Tests exec() by launching merchant. + * @public yes + * @for p3 + * @covers exec + * @status done + */ + +#include +#include +#include +#include + +int main() { + + int tid = gettid(); + + char buf[16]; + char * prog = "merchant"; + char * args[5] = { "merchant", "13", "foo bar", NULL, NULL }; + + args[3] = buf; + sprintf(buf, "%d", tid); + + lprintf("promoting peon #%d to a merchant", tid); + + if (exec(prog, args) < 0) + lprintf("ABORTING: exec returned error"); + else + lprintf("ABORTING: exec returned success"); + + /* infinite loop as exit may not be implemented */ + while(1); +} diff --git a/410user/progs/print_basic.c b/410user/progs/print_basic.c new file mode 100644 index 0000000..37c3c2b --- /dev/null +++ b/410user/progs/print_basic.c @@ -0,0 +1,27 @@ +/** @file 410user/progs/print_basic.c + * @author mpa + * @author mtomczak + * @brief Tests print(). + * @public yes + * @for p3 + * @covers print + * @status done + */ + +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("print_basic:"); + +int main() +{ + REPORT_START_CMPLT; + if (print(13, "Hello World!\n") != 0) + REPORT_END_FAIL; + else + REPORT_END_SUCCESS; + + exit(0); +} diff --git a/410user/progs/progs.mk b/410user/progs/progs.mk new file mode 100644 index 0000000..4dc9b89 --- /dev/null +++ b/410user/progs/progs.mk @@ -0,0 +1,15 @@ +410UPROGS = $(patsubst %,$(410UDIR)/$(UPROGDIR)/%,$(410REQPROGS) $(410TESTS)) +STUUPROGS = $(patsubst %,$(STUUDIR)/$(UPROGDIR)/%,$(STUDENTREQPROGS) $(STUDENTTESTS)) +410UBINPROGS = $(patsubst %,$(410UDIR)/$(UPROGDIR)/%,$(410REQBINPROGS)) + +410UCLEANS += $(410UPROGS) $(410UBINPROGS) + +$(410UBINPROGS): %: %.bin + cp $< $@ + +ULIBS=$(410ULIBS_EARLY) $(STUULIBS_EARLY) $(410ULIBS_LATE) $(STUULIBS_LATE) +$(410UPROGS) $(EXTRA_410_PROGS): %: %.o $(CRT0) $(ULIBS) + $(LD) $(LDFLAGS) -o $@ $< $(CRT0) --start-group $(ULIBS) --end-group + +$(STUUPROGS): %: %.o $(CRT0) $(ULIBS) + $(LD) $(LDFLAGS) -o $@ $< $(CRT0) --start-group $(ULIBS) --end-group diff --git a/410user/progs/readline_basic.c b/410user/progs/readline_basic.c new file mode 100644 index 0000000..b60ebfe --- /dev/null +++ b/410user/progs/readline_basic.c @@ -0,0 +1,25 @@ +/** @file 410user/progs/readline_basic.c + * @author mpa + * @brief Tests readline() + * @public yes + * @for p3 + * @covers readline + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("readline_basic:"); + +int main() { + char buf[100]; + report_start(START_CMPLT); + REPORT_FAILOUT_ON_ERR(magic_readline(100, buf)); + report_misc(buf); + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/register_test.S b/410user/progs/register_test.S new file mode 100644 index 0000000..a45f866 --- /dev/null +++ b/410user/progs/register_test.S @@ -0,0 +1,172 @@ +/** @file 410user/progs/register_test.S + * @author mpa + * @author ctokar + * @brief Tests that registers are saved over context switches. + * @public yes + * @for p3 + * @covers ctxsw + * @status needswork + */ + +#include "410_tests.h" + +.global main + .section .rodata + +test_name: + .string "register_test:" +str: + .string "%s%s%s" +test_start: + .string TEST_START_4EVER +test_pfx: + .string TEST_PFX +test_end_fail: + .string TEST_END_FAIL + +.align 4 +eax: + + .long 0x17 +ebx: + .long 0x42 +ecx: + .long 0xffffffff +edx: + .long 0xc001d00d +esi: + .long 0x9999abcd +edi: + .long 0x12345678 +ebp: + .long 0x87654321 +esp: + .long 0xbaaaaaaa +eax2: + .long 0x20 +ebx2: + .long 0x45 +ecx2: + .long 0x01010101 +edx2: + .long 0xbeef0011 +esi2: + .long 0xfeedcafe +edi2: + .long 0x98765432 +ebp2: + .long 0x12457802 +esp2: + .long 0xabcdefab +str2: + .string "%s%sOoops: %%eax=0x%x, %%ebx=0x%x, %%ecx=0x%x, %%edx=0x%x, %%esi=0x%x, %%edi=0x%x, %%esp=0x%x, %%ebp=0x%x\n" + .text +.comm oldesp,4,4 +.comm oldebp,4,4 +.comm newesp,4,4 +.comm newebp,4,4 + +main: + movl %esp,oldesp + movl %ebp,oldebp + + movl %esp,%ebp + pushl $test_start + pushl $test_name + pushl $test_pfx + pushl $str + call lprintf + + call fork + cmp $0, %eax + je child + +parent: +.align 8 + movl eax,%eax + movl ebx,%ebx + movl ecx,%ecx + movl edx,%edx + movl esi,%esi + movl edi,%edi + movl ebp,%ebp + movl esp,%esp + +loop: + cmpl eax,%eax + jne oops + cmpl ebx,%ebx + jne oops + cmpl ecx,%ecx + jne oops + cmpl edx,%edx + jne oops + cmpl esi,%esi + jne oops + cmpl edi,%edi + jne oops + cmpl ebp,%ebp + jne oops + cmpl esp,%esp + jne oops + jmp loop + +child: +.align 8 + movl eax2,%eax + movl ebx2,%ebx + movl ecx2,%ecx + movl edx2,%edx + movl esi2,%esi + movl edi2,%edi + movl ebp2,%ebp + movl esp2,%esp + +loop2: + cmpl eax2,%eax + jne oops + cmpl ebx2,%ebx + jne oops + cmpl ecx2,%ecx + jne oops + cmpl edx2,%edx + jne oops + cmpl esi2,%esi + jne oops + cmpl edi2,%edi + jne oops + cmpl ebp2,%ebp + jne oops + cmpl esp2,%esp + jne oops + jmp loop2 + +oops: + movl %esp,newesp + movl oldesp,%esp + movl %ebp,newebp + movl oldesp,%ebp + + push newebp + push newesp + push $edi + push $esi + push $edx + push $ecx + push $ebx + push $eax + push $test_name + push $test_pfx + push $str2 + call lprintf + + push $test_end_fail + push $test_name + push $test_pfx + push $str + call lprintf + + movl oldesp,%esp + movl oldebp,%ebp + movl $0xffffffff,%eax + ret diff --git a/410user/progs/remove_pages_test1.c b/410user/progs/remove_pages_test1.c new file mode 100644 index 0000000..6c751ba --- /dev/null +++ b/410user/progs/remove_pages_test1.c @@ -0,0 +1,63 @@ +/** @file 410user/progs/remove_pages_test1.c + * @author mpa + * @brief Tests remove_pages() + * @public yes + * @for p3 + * @covers remove_pages new_pages + * @status done + */ + +#include +#include +#include "410_tests.h" +#include + +#define ADDR 0x40000000 +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +DEF_TEST_NAME("remove_pages_test1:"); + +int main() { + int i; + int size; + int failed = 0; + + report_start(START_CMPLT); + lprintf("This test exercises remove_pages\n"); + lprintf("It assumes that new_pages works as spec\n"); + + for(size = 1; size < 50; size++) { + /* allocate pages */ + if (new_pages((void *)ADDR, size * PAGE_SIZE) != 0) { + lprintf("new_pages failed to allocated %d bytes at %x", + size * PAGE_SIZE, ADDR); + failed = 1; + } + + /* verify pages */ + for (i = 0; i < size; i++) { + if (*(int *)(ADDR + i * PAGE_SIZE) != 0) { + lprintf("allocated page not zeroed at %x", ADDR + i * PAGE_SIZE); + failed = 1; + } + *(int *)(ADDR + i * PAGE_SIZE) = i+1; + } + + /* remove pages */ + if (remove_pages((void *)ADDR) != 0) { + lprintf("remove_pages failed to remove pages at %x", ADDR); + failed = 1; + } + + } + + if (failed) { + report_end(END_FAIL); + return -1; + } + + report_end(END_SUCCESS); + return 0; +} diff --git a/410user/progs/remove_pages_test2.c b/410user/progs/remove_pages_test2.c new file mode 100644 index 0000000..d79bf2b --- /dev/null +++ b/410user/progs/remove_pages_test2.c @@ -0,0 +1,60 @@ +/** @file 410user/progs/remove_pages_test2.c + * @author mpa + * @brief Tests remove_pages() + * @public yes + * @for p3 + * @covers new_pages remove_pages + * @status done + */ + +#include +#include +#include "410_tests.h" +#include + +#define ADDR 0x40000000 +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +DEF_TEST_NAME("remove_pages_test2:"); + +int main() { + report_start(START_ABORT); + lprintf("This test checks that remove_pages removed the pages\n"); + lprintf("It assumes that new_pages works as spec\n"); + + /* allocate a couple pages */ + if (new_pages((void *)ADDR, 5 * PAGE_SIZE) != 0) { + lprintf("new_pages failed at %x", ADDR); + report_end(END_FAIL); + return -1; + } + + if (*(int *)(ADDR + 2 * PAGE_SIZE) != 0) { + lprintf("allocated page not zeroed at %x", ADDR + 2 * PAGE_SIZE); + report_end(END_FAIL); + return -1; + } + *(int *)(ADDR + 2 * PAGE_SIZE) = 5; + + if (remove_pages((void *)ADDR) != 0) { + lprintf("remove_pages failed to remove pages at %x", ADDR); + report_end(END_FAIL); + return -1; + } + + report_misc("pages removed"); + + switch (*(int *)(ADDR + 2 * PAGE_SIZE)) { + case 5: + report_misc("pages not really removed"); + break; + + default: + report_fmt("pages still mapped, got %d", *(int *)(ADDR + 2 * PAGE_SIZE)); + break; + } + report_end(END_FAIL); + return -1; +} diff --git a/410user/progs/score.c b/410user/progs/score.c new file mode 100644 index 0000000..29ed81a --- /dev/null +++ b/410user/progs/score.c @@ -0,0 +1,146 @@ +/** @file 410user/progs/score.c + * + * @author Ryan Chen (ryanc1) + * @author Urvi Agrawal (urvia) + * + * @brief Runs batches of scoreboard tests based on flags provided in argv + * @public yes + * @for p3 + * @covers argc/argv, fork(), exec(), new_pages(), remove_pages() + * + * @bug None known + */ + +#include +#include +#include + +#include "syscall.h" +#include "simics.h" +#include "string.h" + +// These tests will be run if no other test suite is specified in argv. +// @covers Loading, getpid(), exec(), fork(), print() +char *default_tests[] = { + "getpid_test1", + "loader_test1", + "loader_test2", + "exec_basic", + "exec_nonexist", + "fork_test1", + "print_basic", + NULL, +}; + +// Run these tests by adding "memory" to argv. +// @covers new_pages(), remove_pages(), page fault handler, +// zeroed allocations/ZFOD +char *memory_tests[] = { + "new_pages", + "remove_pages_test1", + "mem_permissions", + NULL, +}; + +typedef struct { + char *name; + char **programs; +} TestSuite; + +// Array mapping strings potentially in argv[1] to test tables +TestSuite suites[] = { + {"memory", memory_tests}, + {NULL, default_tests}, +}; + +// You know how in kindergarten you didn't actually sleep during +// naptime so you just counted the number of tiles on the ceiling? +// No? Just me? +#define FAKE_SLEEP_DELAY 8096 +int num_tiles_gcc_please_I_want_to_live = 0; + +static void spin_delay() { + for (int i = 0; i < FAKE_SLEEP_DELAY; i++) { + ++num_tiles_gcc_please_I_want_to_live; + } +} + +// Returns 0 if x == NULL, y == NULL +// Returns some unspecified non-zero value if only one of x or y is NULL +// Otherwise, returns strcmp(x, y) +int safe_strcmp(char *x, char *y) { + if (x == NULL && y == NULL) { + return 0; + } else if (x == NULL) { + return -42; + } else if (y == NULL) { + return -42; + } else { + return strcmp(x, y); + } +} + +// Mass fork()/exec() all the tests in the named test suite. +void fork_test_suite(TestSuite *test_suite) { + if (test_suite->name == NULL) { + lprintf("score: Running default test suite."); + } else { + lprintf("score: Running test suite '%s'", test_suite->name); + } + + int program_num = 0; + while (test_suite->programs[program_num] != NULL) { + int pid = fork(); + char *testname = test_suite->programs[program_num]; + + if (pid < 0) { + lprintf("score: fork() failed while launching %s", testname); + spin_delay(); + } else if (pid == 0) { + char *args[2]; + args[0] = testname; + args[1] = NULL; + + exec(testname, args); + + lprintf("score: exec(%s) failed..?", testname); + } else { // pid > 0 + ++program_num; + } + } +} + +void run_suite(char *suite_name) { + int num_suites_loaded = sizeof(suites) / sizeof(suites[0]); + for (int i = 0; i < num_suites_loaded; i++) { + if (safe_strcmp(suite_name, suites[i].name) == 0) { + fork_test_suite(&suites[i]); + return; + } + } + + lprintf("score: test suite '%s' not found.", suite_name); +} + + +int main(int argc, char **argv) { + if (argc == 0) { // Maybe argv is not correct? + lprintf("score: argc == 0??"); + } else { + run_suite(NULL); // Always run the default suite. + if (argc >= 2) { + run_suite(argv[1]); // Additionally, run a named test suite + } + } + + // Since this test is meant to be run instead of init (before the shell is + // functional), this program must be persistent. + int sheep = 0; + while (true) { + ++sheep; + spin_delay(); + } + + lprintf("score: escaped infinite loop???"); + return -42; // Hopefully not. +} diff --git a/410user/progs/shell.c b/410user/progs/shell.c new file mode 100644 index 0000000..5546d7f --- /dev/null +++ b/410user/progs/shell.c @@ -0,0 +1,276 @@ +/** @file 410user/progs/shell.c + * @author ? + * @brief The shell. + * @public yes + * @for p2 p3 + * @covers fork exec wait set_status vanish print ls + * @status done + */ + +/* --- Since we're not calling thr_init() --- */ +/* (this is sleazy violence, *not* good form) */ +#define malloc _malloc +#define calloc _calloc +#define realloc _realloc +#define free _free + +/* --- Includes --- */ +#include +#include +#include +#include +#include + +#include + +/* --- Defines --- */ +#define MAX_LENGTH 1024 + + +/* --- Initialized Global Strings --- */ +char prompt[] = "[410-shell]$ "; +char startmsg[] = "Starting shell...\n"; +char exitmsg[] = "Exiting shell...\n"; +char forkerrmsg[] = "Shell: Cannot fork process.\n"; +char waitfailed[] = "wait() failed\n"; +char finished[] = "Process finished\n"; +char too_long[] = "That string is too long.\n"; +char null_check[] = "I've lost null termination!\n"; +char nothing[] = "Readline returned nothing!\n"; + +/* --- These are global only to avoid stack growth --- */ +/* (unclean, but lets the shell run before swexn() and new_pages()) */ +char buf[MAX_LENGTH]; +char *cmd_argv[MAX_LENGTH]; +char separators[4] = { ' ', '\t', '\n' }; + +static void print_ls(void); +static void sort_names(char **names, int num_entries); +static int mystical_readline(int len, char *buf); +static int console_height(void); + +/* Not all kernels support getchar(). + * + * Try to use it, but if it doesn't work fall back to readline(). + */ +static int fallback_getchar(void) +{ + char buf[2]; + + mystical_readline(2, buf); + + return (unsigned char)buf[0]; // cast prevents sign extension +} + +static int try_getchar(void) +{ + static int missing_getchar = 0; + int c; + + if (missing_getchar || (c = getchar()) < 0) { + missing_getchar = 1; + return fallback_getchar(); + } + return c; +} +#define getchar try_getchar + +/* --- Main --- */ +int +main(int argc, char *argv[]) +{ + int n; + int pid; + int res; + int j; + int ret; + + print(strlen(startmsg), startmsg); + + while(1) { + + bzero(buf, MAX_LENGTH); + print(strlen(prompt), prompt); + n = mystical_readline(MAX_LENGTH - 1, buf); + if (n == 0) { + /* Empty result; this shouldn't happen. */ + print(strlen(nothing), nothing); + continue; + } else if(n >= MAX_LENGTH) { + /* line too big -- kernel declared that it clobbered memory */ + print(strlen(too_long), too_long); + exit(-1); + } else if(buf[MAX_LENGTH - 1] != '\0') { + /* Overflow -- kernel tapdanced on random memory! */ + print(strlen(null_check), null_check); + exit(-1); + } + + buf[n] = '\0'; + j = 0; + if(!(cmd_argv[j++] = strtok(buf, separators))) { + continue; + } + if((strcmp(cmd_argv[0], "exit") == 0)) { + print(strlen(exitmsg), exitmsg); + exit(0); + } + if((strcmp(cmd_argv[0], "ls") == 0)) { + print_ls(); + continue; + } + + while((cmd_argv[j++] = strtok(NULL, separators))); + + pid = fork(); + if(pid < 0) { + print(sizeof(forkerrmsg), forkerrmsg); + continue; + } + if(pid == 0) { + exec(cmd_argv[0], cmd_argv); + exit(-1); + } + else { + if((ret = wait(&res)) < 0) { + printf("\nshell: wait on process %d failed!\n", pid); + } + else { + printf("\nshell: process %d finished with exit status %d\n", ret, res); + } + } + } /* while loop */ +} + +/* emulate the old ls() system call using readfile() */ +int ls(int size, char *buf) +{ + int i; + int num_files = 0; + int amt_read; + + amt_read = readfile(".", buf, size, 0); + if (amt_read < 0) return amt_read; + /* ls() returned failure if the buffer wasn't big enough for the + * entire listing. So if readfile() didn't return short (that is, + * there might be more), fail. */ + if (amt_read == size) return -1; + + /* Now scan through the buffer counting null terminators. + * Skip the one at the end. */ + for (i = 0; i < amt_read - 1; i++) { + if (buf[i] == '\0') { + num_files++; + } + } + + return num_files; +} + +static void print_ls() +{ + char *buf = NULL; + static int size = 16; + int num_entries; + char ** names = NULL; + char *bufptr; + int index; + int len; + + /* get the array of entries */ + buf = (char *)malloc(sizeof(char) * size); + if (buf == NULL) { + printf("Can't malloc(%d)!\n", sizeof(char) * size); + goto cleanup; + } + while ((num_entries = ls(size, buf)) < 0) { + size *= 2; + char *nbuf = (char *)realloc(buf, sizeof(char) * size); + if (nbuf == NULL) { + printf("Can't realloc(%d)!\n", sizeof(char) * size); + goto cleanup; + } else { + buf = nbuf; + } + } + + names = (char **)calloc(num_entries, sizeof(char *)); + if (names == NULL) { + printf("Can't calloc(%d)!\n", num_entries * sizeof(char *)); + goto cleanup; + } + + /* get pointers to each string in the array */ + bufptr = buf; + index = 0; + while ((len = strlen(bufptr)) > 0) { + names[index++] = bufptr; + bufptr += len + 1; + } + + sort_names(names, num_entries); + + printf("Listing the user tests\n"); + for (index = 0; index < num_entries; index++) { + if (index != 0 && index % (console_height() - 2) == 0) { + printf("Hit a key to continue\n"); + getchar(); + } + printf("%s\n", names[index]); + } + +cleanup: + if (buf) { + free(buf); + buf = NULL; + } + if (names) { + free(names); + names = NULL; + } +} + +static void sort_names(char **names, int num_entries) { + /* I invented this cool new sorting algorithm! It's really fast! */ + int swapped; + int i; + do { + swapped = 0; + for (i = 0; i < num_entries - 1; i++) { + if (strcmp(names[i], names[i+1]) > 0) { + char *tmp = names[i]; + names[i] = names[i+1]; + names[i+1] = tmp; + swapped = 1; + } + } + } while (swapped); +} + +static int mystical_readline(int len, char *buf) { + if (len <= 0) { return 0; } + + buf[0] = '\0'; + /* If we're in the test harness, this does something very special! */ + sim_call(0x04108005, buf, len); + + return (buf[0] ? strlen(buf) : readline(len, buf)); +} + +static int console_height() { + static int console_height = -1; + + if (console_height == -1) { + /* determine the height of the console */ + int curstartrow, curstartcol; + get_cursor_pos(&curstartrow, &curstartcol); + console_height = 0; + while (set_cursor_pos(console_height, 0) == 0) { + console_height++; + } + set_cursor_pos(curstartrow, curstartcol); + + } + + return console_height; +} diff --git a/410user/progs/slaughter.c b/410user/progs/slaughter.c new file mode 100644 index 0000000..9544e60 --- /dev/null +++ b/410user/progs/slaughter.c @@ -0,0 +1,144 @@ +/** @file 410user/progs/slaughter.c + * @author mtelgars + * @author nwf + * @brief Runs a lot of copies of a given test. + * @public yes + * @for p3 + * @covers fork exec wait set_status vanish + * @status done + */ + +#include +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("slaughter:"); + +unsigned int width; +int initial_tid; +int exit_status; + +void __attribute__((noreturn)) slaughter(char **argv, unsigned int depth) +{ + int curtid = gettid(); + + report_start(START_CMPLT); + + if ( ! depth ) + { + if (exec(argv[0], argv)) + { + lprintf("=====> exec failed from %d!", curtid); + exit(-373); + } + } + else + { + unsigned int i, j, matched; + int threads[2*width]; /* not doing anything smart here yet.. */ + int status, tid; + + for (i = 0; i != 2*width; ++i) + { + if ( ! (threads[i] = fork()) ) + { + /* alternate immediate exec and slaughter */ + slaughter(argv, (i % 2) * (depth - 1)); + } + else if (threads[i] < 0) { + lprintf("=====> XXX tid %d could not fork (err=%d)!!", + curtid,threads[i]); + report_end(END_FAIL); + exit(exit_status+1); + } + else + { + lprintf("=====> Slaugher created TID %d from TID %d", + threads[i], curtid); + } + } + + for (i = 0; i != 2*width; ++i) + { + tid = wait(&status); + if ( tid < 0 ) + { + lprintf("=====> XXX Wait failed in TID %d with %d; bombing out", + curtid, tid ); + report_end(END_FAIL); + exit(exit_status+3); + } + else + { + matched = 0; + for ( j = 0; j != 2*width; ++j ) + { + if ( threads[j] == tid ) + { + matched = 1; + threads[j] = -1; + break; + } + } + if ( matched == 0 ) + { + lprintf("=====> XXX Wait returned bad TID %d to TID %d; bombing out", + tid, curtid ); + report_end(END_FAIL); + exit(exit_status+5); + } + lprintf("=====> %stid %d gave %svalid status code of %d to tid %d", + (status == exit_status) ? "" : "XXX ", + tid, (status == exit_status) ? "" : "IN", status, curtid); + if ( status != exit_status ) + { + report_end(END_FAIL); + exit(exit_status+7); + } + } + } + } + + lprintf("=====> Slaughterer %d completed", curtid); + report_end(END_SUCCESS); + exit(exit_status); +} + +int main(int argc, char *argv[]) +{ + unsigned int initial_depth; + char *default_vec[] = { "print_basic", NULL }; + char **command_vec; + + if (argc < 5) + { + printf("slaughter " + " \n"); + initial_depth = 2; + width = 2; + exit_status = 0; + command_vec = default_vec; + printf(" DEFAULTING TO: %d %d %d %s\n", initial_depth, width, exit_status, command_vec[0]); + } + else if ( ! (width = strtoul(argv[1], NULL, 10)) ) + { + printf(" bad recursive width\n"); + return -2; + } + else if ( ! (initial_depth = strtoul(argv[2], NULL, 10)) ) + { + printf(" bad recursive depth\n"); + return -3; + } + else + { + exit_status = strtol(argv[3], NULL, 10); + command_vec = &argv[4]; + } + + slaughter(command_vec, initial_depth); + return 0; +} diff --git a/410user/progs/sleep_test1.c b/410user/progs/sleep_test1.c new file mode 100644 index 0000000..290e87a --- /dev/null +++ b/410user/progs/sleep_test1.c @@ -0,0 +1,32 @@ +/** @file 410user/progs/sleep_test1.c + * @author zra + * @brief Sleeps for amount of time given as an argument. + * @public yes + * @for p3 + * @covers sleep + * @status done + */ + +/* Includes */ +#include /* for sleep, getpid */ +#include +#include /* for lprintf */ +#include /* for atoi, exit */ +#include "410_tests.h" +#include + +DEF_TEST_NAME("sleep_test1:"); + +int main(int argc, char *argv[]) { + report_start(START_CMPLT); + report_misc("before sleeping"); + + if (argc == 2) + sleep( atoi( argv[1] ) ); + else + sleep( 3 + (gettid() % 27) ); + + report_misc("after sleeping"); + report_end(END_SUCCESS); + exit( 42 ); +} diff --git a/410user/progs/stack_test1.c b/410user/progs/stack_test1.c new file mode 100644 index 0000000..6b40545 --- /dev/null +++ b/410user/progs/stack_test1.c @@ -0,0 +1,47 @@ +/** @file 410user/progs/stack_test1.c + * @author efaust + * @brief Tests whether auto-stack pages are zeroed. + * @public yes + * @for p3 + * @covers autostack + * @status done + * + * Note: If we ever go back to the kernel-level autostack, we should revert + * this to the old one. + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("stack_test1:"); + +#define SIZE (65536) + +/* Can't you see that I am not afraid */ +void touch_me_babe(char *arr, size_t len) +{ + size_t i; + for(i = 0; i < len; i++) { + arr[i] = i; + } +} + +void do_test() +{ + char ca[SIZE]; + touch_me_babe(ca, sizeof(ca)); +} + +int main() +{ + + report_start(START_CMPLT); + + do_test(); + report_misc("stack allocation successful"); + report_end(END_SUCCESS); + exit(42); +} diff --git a/410user/progs/swexn_basic_test.c b/410user/progs/swexn_basic_test.c new file mode 100644 index 0000000..b9e2869 --- /dev/null +++ b/410user/progs/swexn_basic_test.c @@ -0,0 +1,77 @@ +/** + * @file swexn_basic_test.c + * @author bblum + * @brief Tests a simple use case for swexn + * @public yes + * @for p4 + */ + +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("swexn_basic_test:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)((unsigned int)(&exn_staq[STAQ_SIZE-7]) & ~(sizeof (int) - 1))) + +#define GOOD_MEMORY ((void *)0x40000000) + +void handler(void *arg, ureg_t *uregs) +{ + int ret; + + REPORT_MISC("Hello from a handler"); + + if (uregs == NULL) { + REPORT_MISC("what use is a handler without a ureg pointer?"); + REPORT_END_FAIL; + exit(-1); + } + + ret = new_pages(GOOD_MEMORY, STAQ_SIZE); + if (ret < 0) { + REPORT_MISC("new_pages failed"); + REPORT_END_FAIL; + exit(-1); + } + *(int *)GOOD_MEMORY = 42; + ret = swexn(EXN_STAQ_TOP, handler, NULL, uregs); + if (ret < 0) { + REPORT_MISC("second swexn rejected"); + } else { + REPORT_MISC("restoring old position failed"); + } + REPORT_END_FAIL; + exit(-1); + return; +} + +int main() +{ + int ret; + + REPORT_START_CMPLT; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + ret = *(int *)GOOD_MEMORY; + + if (ret == 0) { + REPORT_MISC("handler not run?"); + REPORT_END_FAIL; + exit(-1); + } + + TEST_PROG_PROGRESS; + REPORT_END_SUCCESS; + exit(ret); +} diff --git a/410user/progs/swexn_cookie_monster.c b/410user/progs/swexn_cookie_monster.c new file mode 100644 index 0000000..151ce25 --- /dev/null +++ b/410user/progs/swexn_cookie_monster.c @@ -0,0 +1,85 @@ +/** + * @file swexn_cookie_monster.c + * @brief Tests the correct passing of arguments to swexn handlers + * + * @author mischnal + * @for swexn p4 + * @covers swexn + * @public yes + */ + +#include +#include +#include + +#include "simics.h" +#include "410_tests.h" + +DEF_TEST_NAME("swexn_cookie_monster"); + +#define SWEXN_STACK_SIZE 2048 +char swexn_stack[SWEXN_STACK_SIZE]; +#define SWEXN_STACK ((void*)(swexn_stack + SWEXN_STACK_SIZE - 8)) + +void *cookies[] = {(void*)0xfeedbeef, (void*)0x8badf00d, (void*)0xbaddcafe, + (void*)0xc0ffee, (void*)0xface, (void*) 0x12345678, + (void*)42, (void*)57, (void*)2953575118U}; +int curr_cookie = 0; +int first_pass = 1; + + + +void handler(void *arg, ureg_t *uregs) +{ + int ret; + + if (cookies[curr_cookie] != arg) + { + REPORT_MISC(" Cookie incorrect"); + REPORT_END_FAIL; + exit(1); + } + + curr_cookie++; + if (curr_cookie < sizeof(cookies) / sizeof(cookies[0])) + { + ret = swexn(SWEXN_STACK, handler, cookies[curr_cookie], uregs); + if (ret < 0) + { + REPORT_MISC(" Failed to install handler"); + REPORT_END_FAIL; + exit(1); + } + } + else + { + /* Out of cookies */ + REPORT_END_SUCCESS; + exit(0); + } +} + +int main(void) +{ + int ret; + if (first_pass) + { + REPORT_START_CMPLT; + first_pass = 0; + } + + ret = swexn(SWEXN_STACK, handler, cookies[curr_cookie], NULL); + if (ret < 0) + { + REPORT_MISC(" Failed to install handler"); + REPORT_END_FAIL; + exit(1); + } + + *(volatile int *)NULL = 42; + + /* Should not get here */ + REPORT_MISC(" Something is very wrong"); + REPORT_END_FAIL; + return 1; +} diff --git a/410user/progs/swexn_dispatch.c b/410user/progs/swexn_dispatch.c new file mode 100644 index 0000000..50764e9 --- /dev/null +++ b/410user/progs/swexn_dispatch.c @@ -0,0 +1,55 @@ +/** + * @file swexn_dispatch.c + * @author bblum + * @brief Tests swexn basic function dispatch + * @public yes + * @for p4 + */ + +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("swexn_dispatch:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-4])) + +#define COOKIE ((void *)0x0dd0ad9b) + +void handler(void *arg, ureg_t *uregs) +{ + REPORT_MISC("Hello from a handler"); + + if (arg != COOKIE) { + /* this fight is not worth fighting */ + REPORT_MISC("C is for cookie; it's not good enough for me..."); + REPORT_END_FAIL; + exit(-1); + } + + REPORT_END_SUCCESS; + exit(42); +} + +int main() +{ + int ret; + + REPORT_START_CMPLT; + + ret = swexn(EXN_STAQ_TOP, handler, COOKIE, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + ret = *(volatile int *)NULL; + REPORT_MISC("should not get here!"); + REPORT_END_FAIL; + exit(ret); +} diff --git a/410user/progs/swexn_rampage.c b/410user/progs/swexn_rampage.c new file mode 100644 index 0000000..4203e6d --- /dev/null +++ b/410user/progs/swexn_rampage.c @@ -0,0 +1,96 @@ +/** + * @file swexn_rampage.c + * @author de0u + * @brief Tests a simple use case for swexn + * @public yes + * @for p3 + */ + +#include +#include +#include +#include "410_tests.h" + +#define USER_MEM_START 0x01000000 +#define KERNEL_BOTTOM 0x00100000 // 1 megabyte; below there lie dragons + +#define ENOUGH 410 + +DEF_TEST_NAME("swexn_rampage:"); + +#define STAQ_SIZE (4096) +static char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-7])) + +void install(void); +void rampage(void); +void handler(void *arg, ureg_t *uregs); + +static unsigned int *top_addr = (unsigned int *)USER_MEM_START - sizeof (unsigned int); + +static int events = 0; + +static unsigned int start_ticks; + +void install(void) +{ + int ret; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } +} + +void rampage(void) +{ + unsigned int *ip; + + for (ip = top_addr; ip > (unsigned int *)KERNEL_BOTTOM; ip--) + *ip = 0; + + REPORT_END_FAIL; // as if +} + +void handler(void *arg, ureg_t *uregs) +{ + if (uregs->cause != SWEXN_CAUSE_PAGEFAULT) { + report_fmt("bad cause %d", uregs->cause); + REPORT_END_FAIL; + exit(-1); + } + if (uregs->cr2 != (unsigned int) top_addr) { + report_fmt("bad addr 0x%x", uregs->cr2); + REPORT_END_FAIL; + exit(-1); + } + + TEST_PROG_PROGRESS; + + if (++events == ENOUGH) { + report_fmt("ticks %d", get_ticks() - start_ticks); + REPORT_END_SUCCESS; + exit(0); + } + + sleep(15); + + install(); + rampage(); +} + +int main() +{ + REPORT_START_CMPLT; + + start_ticks = get_ticks(); + + install(); + rampage(); + + REPORT_MISC("handler not run?"); + REPORT_END_FAIL; + exit(-1); +} diff --git a/410user/progs/swexn_regs.c b/410user/progs/swexn_regs.c new file mode 100644 index 0000000..643fb88 --- /dev/null +++ b/410user/progs/swexn_regs.c @@ -0,0 +1,65 @@ +/** + * @file swexn_regs.c + * @brief Tests a case of the validation of uregs. + * + * @author mischnal + * @for swexn p4 + * @covers swexn + * @public yes + */ + +#include +#include +#include + +#include "simics.h" +#include "410_tests.h" + +DEF_TEST_NAME("swexn_regs"); + +#define SWEXN_STACK_SIZE 2048 +char swexn_stack[SWEXN_STACK_SIZE]; +#define SWEXN_STACK ((void*)(swexn_stack + SWEXN_STACK_SIZE - 8)) + +#define EFLAGS_MASK 0x00003000 + + +void handler(void *arg, ureg_t *uregs) +{ + int ret; + REPORT_MISC(" In handler"); + + uregs->eflags |= EFLAGS_MASK; + + ret = swexn(SWEXN_STACK, handler, NULL, uregs); + if (ret < 0) + { + REPORT_END_SUCCESS; + exit(0); + } + else + { + REPORT_END_FAIL; + exit(1); + } +} + +int main(void) +{ + int ret; + + REPORT_START_CMPLT; + + ret = swexn(SWEXN_STACK, handler, NULL, NULL); + if (ret < 0) + { + REPORT_END_FAIL; + exit(1); + } + + *(volatile int *)NULL = 42; + + /* Should not get here */ + REPORT_END_FAIL; + return 1; +} diff --git a/410user/progs/swexn_stands_for_swextensible.c b/410user/progs/swexn_stands_for_swextensible.c new file mode 100644 index 0000000..31748ec --- /dev/null +++ b/410user/progs/swexn_stands_for_swextensible.c @@ -0,0 +1,58 @@ +/** + * @file swexn_stands_for_swextensible.c + * @author bblum + * @brief Tests what happens when the handler faults + * @public yes + * @for p4 + */ + +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("swexn_stands_for_swextensible:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-11])) + +#define BAD_MEMORY ((void *)0x40000000) + +volatile int already_called = 0; + +void handler(void *arg, ureg_t *uregs) +{ + REPORT_MISC("Hello from a handler"); + if (already_called == 0) { + already_called = 1; + /* Incur another fault (in a way that won't get optimized). */ + exit(*(int *)BAD_MEMORY); + } else { + REPORT_MISC("Not supposed to get called again!"); + REPORT_END_FAIL; + exit(-1); + } + return; +} + +int main() +{ + int ret; + + REPORT_START_ABORT; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + ret = *(int *)BAD_MEMORY; + + REPORT_MISC("something bad happened!"); + REPORT_END_FAIL; + exit(ret); +} diff --git a/410user/progs/swexn_uninstall_test.c b/410user/progs/swexn_uninstall_test.c new file mode 100644 index 0000000..34d898f --- /dev/null +++ b/410user/progs/swexn_uninstall_test.c @@ -0,0 +1,60 @@ +/** + * @file swexn_basic_test.c + * @author bblum + * @brief Tests uninstalling handlers + * @public yes + * @for p4 + */ + +#include +#include +#include +#include "410_tests.h" + +DEF_TEST_NAME("swexn_uninstall_test:"); + +#define STAQ_SIZE (4096) +char exn_staq[STAQ_SIZE]; +#define EXN_STAQ_TOP ((void *)(&exn_staq[STAQ_SIZE-8])) + +#define BAD_MEMORY ((void *)0x40000000) + +volatile int success = 0; + +void handler(void *arg, ureg_t *uregs) +{ + REPORT_MISC("Uh-oh, we weren't supposed to be called!"); + REPORT_END_FAIL; + exit(-1); + return; +} + +int main() +{ + int ret; + void (*x)() = (typeof(x))NULL; + + REPORT_START_ABORT; + + ret = swexn(EXN_STAQ_TOP, handler, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected"); + REPORT_END_FAIL; + exit(-1); + } + + /* uninstall */ + ret = swexn(NULL, NULL, NULL, NULL); + if (ret < 0) { + REPORT_MISC("swexn call rejected (2)"); + REPORT_END_FAIL; + exit(-1); + } + + /* Invoke handler */ + success = *(int *)BAD_MEMORY; + + REPORT_MISC("D:"); + REPORT_END_FAIL; + exit(-1); +} diff --git a/410user/progs/wait_getpid.c b/410user/progs/wait_getpid.c new file mode 100644 index 0000000..825f10c --- /dev/null +++ b/410user/progs/wait_getpid.c @@ -0,0 +1,48 @@ +/** @file 410user/progs/wait_getpid.c + * @author mpa + * @brief Tests gettid()/wait()/fork() + * @public yes + * @for p3 + * @covers gettid wait fork set_status vanish + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("wait_getpid:"); + +int main() +{ + int pid, status; + + report_start(START_CMPLT); + + pid = fork(); + + if (pid < 0) { + report_end(END_FAIL); + exit(-1); + } + + if (pid == 0) { + pid = gettid(); + exit(pid); + report_end(END_FAIL); + } + if (wait(&status) != pid) { + report_end(END_FAIL); + exit(-1); + } + + if (status != pid) { + report_end(END_FAIL); + exit(-1); + } + + report_end(END_SUCCESS); + exit(0); +} diff --git a/410user/progs/wild_test1.c b/410user/progs/wild_test1.c new file mode 100644 index 0000000..bc11ecc --- /dev/null +++ b/410user/progs/wild_test1.c @@ -0,0 +1,31 @@ +/** @file 410user/progs/wild_test1.c + * @author zra + * @brief Tests thread death by unnatural causes. + * @public yes + * @for p2 p3 + * @covers faults + * @status done + */ + +/* Includes */ +#include /* was for exit */ +#include /* for exit */ +#include +#include /* for lprintf */ + +#include "410_tests.h" +DEF_TEST_NAME("wild_test1:"); + +/* Main */ +int main(void) +{ + int *wild = (int *)0x31337000; + + REPORT_START_ABORT; + + *wild = 0x2badd00d; + + REPORT_END_FAIL; + + exit( -1 ); +} diff --git a/410user/progs/work.c b/410user/progs/work.c new file mode 100644 index 0000000..46c34f9 --- /dev/null +++ b/410user/progs/work.c @@ -0,0 +1,58 @@ +/** @file 410user/progs/work.c + * @author acrichto + * @brief Factors some numbers in some tasks + * @public yes + * @for p4-smp + * @status done + */ + +#include <410_tests.h> +#include +#include +#include +#include + +DEF_TEST_NAME("work:"); + +#define AMT 50 +#define MAX 8000000 + +int work(uint32_t num) { + uint32_t i; + uint32_t factors = 0; + + for (i = 1; i <= num; i++) { + if (num % i == 0) factors ++; + } + + return factors; +} + +int main() { + int ticks = get_ticks(); + int i; + int last = 0; + srand(0x1401); + + for (i = 0; i < AMT; i++) { + + int next = rand() % MAX; + int pid = fork(); + REPORT_ON_ERR(pid); + if (pid == 0) { + return work(next); + } + printf("factoring: %u\n", next); + } + print(1, ">"); + for (i = 0; i < AMT; i++) { + wait(NULL); + if (i * 79 / AMT > last) { + print(3, "\b=>"); + last++; + } + } + + printf("\nticks taken: %d\n", get_ticks() - ticks); + return 0; +} diff --git a/410user/progs/yield_desc_mkrun.c b/410user/progs/yield_desc_mkrun.c new file mode 100644 index 0000000..080689d --- /dev/null +++ b/410user/progs/yield_desc_mkrun.c @@ -0,0 +1,68 @@ +/** @file 410user/progs/yield_desc_mkrun.c + * @author mpa + * @brief Tests yield() and deschedule()/make_runnable() + * @public yes + * @for p3 + * @covers yield deschedule make_runnable fork set_status vanish + * @status done + */ + +#include +#include +#include +#include "410_tests.h" +#include + +DEF_TEST_NAME("yield_desc_mkrun:"); + +int main() { + int parenttid, childtid, error; + + report_start(START_CMPLT); + + parenttid = gettid(); + childtid = fork(); + + if (childtid < 0) { + lprintf("cannot fork()"); + goto fail; + } + + if (childtid == 0) { + /* child */ + + /* Wait until the process deschedules itself */ + while(yield(parenttid) == 0) { + report_misc("parent not asleep yet"); + } + + report_misc("parent presumably asleep"); + + /* Wake parent back up */ + if((error = make_runnable(parenttid)) != 0) { + lprintf("make_runnable() failed %d in child", error); + goto fail; + } + report_misc("parent should be awake"); + } else { + /* parent */ + + int reject = 0; + if((error = deschedule(&reject)) != 0) { + lprintf("deschedule() failed %d in parent", error); + goto fail; + } + + /* wait() would be better, but we're not testing wait() here */ + yield(childtid); + yield(childtid); + yield(childtid); + report_end(END_SUCCESS); + } + + exit(0); + +fail: + report_end(END_FAIL); + exit(1); +} diff --git a/410user/user.mk b/410user/user.mk new file mode 100644 index 0000000..bd7deec --- /dev/null +++ b/410user/user.mk @@ -0,0 +1,60 @@ +################# TARGET-SPECIFIC RULES ################# + +# "You are not expected to understand this." +$(STUUDIR)/libthread/panic.o: CFLAGS+=-Wno-missing-noreturn +$(STUUDIR)/libsyscall/syscall.o: CFLAGS+=-Wno-missing-noreturn + +$(410UDIR)/exec2obj.dep: INCLUDES=$(KINCLUDES) +$(410UDIR)/exec2obj.dep: CFLAGS=-m32 -Wall -Werror + +# This wants to use the system standard library and everything. I'm not sure how this ever +# worked; probably only because of the use of -I-... +$(410UDIR)/exec2obj: $(410UDIR)/exec2obj.c + 410-gcc -m32 -I. -Wall -Werror -o $@ $^ +# $(CC) -m32 -iquote 410kern/inc -Wall -Werror -o $@ $^ +# $(CC) -m32 $(KINCLUDES) -Wall -Werror -o $@ $^ + +ifeq (1,$(DO_INCLUDE_DEPS)) +-include $(410UDIR)/exec2obj.dep +endif + +410UCLEANS+=$(410UDIR)/exec2obj $(410UDIR)/exec2obj.dep + +$(PROGS:%=$(BUILDDIR)/%) : +$(BUILDDIR)/%.strip : $(BUILDDIR)/% + strip -o $@ $< + +.INTERMEDIATE: $(PROGS:%=$(BUILDDIR)/%.strip) + +# Generate a directory listing file so the shell can implement ls +$(BUILDDIR)/__DIR_LISTING__: $(PROGS:%=$(BUILDDIR)/%.strip) \ + $(FILES:%=$(BUILDDIR)/%) + (printf "%s\0" $(sort $(PROGS) $(FILES)); printf "\0") > $(BUILDDIR)/__DIR_LISTING__ + +$(BUILDDIR)/user_apps.o: $(410UDIR)/exec2obj $(BUILDDIR)/__DIR_LISTING__ \ + $(PROGS:%=$(BUILDDIR)/%.strip) \ + $(FILES:%=$(BUILDDIR)/%) + ( cd $(BUILDDIR); \ + $(PROJROOT)/$(410UDIR)/exec2obj __DIR_LISTING__ $(PROGS) $(FILES)) | \ + $(AS) --32 -o $@ + +include $(410UDIR)/$(UPROGDIR)/progs.mk + +include $(patsubst %.a,$(410UDIR)/%/user.mk,$(410USER_LIBS_EARLY) $(410USER_LIBS_LATE)) + +################# STUDENT LIBRARY RULES ################# + +STUU_THREAD_OBJS := $(THREAD_OBJS:%=$(STUUDIR)/libthread/%) +ALL_STUUOBJS += $(STUU_THREAD_OBJS) +STUUCLEANS += $(STUUDIR)/libthread.a +$(STUUDIR)/libthread.a: $(STUU_THREAD_OBJS) + +STUU_SYSCALL_OBJS := $(SYSCALL_OBJS:%=$(STUUDIR)/libsyscall/%) +ALL_STUUOBJS += $(STUU_SYSCALL_OBJS) +STUUCLEANS += $(STUUDIR)/libsyscall.a +$(STUUDIR)/libsyscall.a: $(STUU_SYSCALL_OBJS) + +STUU_AUTOSTACK_OBJS := $(AUTOSTACK_OBJS:%=$(STUUDIR)/libautostack/%) +ALL_STUUOBJS += $(STUU_AUTOSTACK_OBJS) +STUUCLEANS += $(STUUDIR)/libautostack.a +$(STUUDIR)/libautostack.a: $(STUU_AUTOSTACK_OBJS) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9eb0a65 --- /dev/null +++ b/Makefile @@ -0,0 +1,487 @@ + +################################################################## +# # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# # +# ##### ####### ####### ###### ### # +# # # # # # # # ### # +# # # # # # # ### # +# ##### # # # ###### # # +# # # # # # # +# # # # # # # ### # +# ##### # ####### # ### # +# # +# # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# Do not edit this file. Edit config.mk instead. # +# # +################################################################## + +#################### RULE HEADER #################### + +.PHONY: update query_update print html_doc +all: bootfd.img + +############## VARIABLE DEFINITIONS ################# + +DOC = doxygen +MAKE = gmake + +# If you are on an Andrew machine, these are in 410/bin, +# which should be on your PATH. +# If not, you'll need to arrange for programs with these +# names which work the same way to be on your PATH. Note +# that different versions of gcc generally do NOT work the +# same way. +LD = 410-ld +AR = 410-ar +OBJCOPY = 410-objcopy + +PROJROOT = $(PWD) +# All paths relative to PROJROOT unless otherwise noted +410KDIR = 410kern +410SDIR = spec +410UDIR = 410user +BOOTDIR = boot +410GDIR = 410guests +STUGDIR = guests +STUKDIR = kern +STUUDIR = user +EXTRADIR ?= 410extra +BUILDDIR = temp + +# Relative to {410,STU}UDIR +UPROGDIR = progs +UFILEDIR = files + +# By default, we are offline +UPDATE_METHOD = offline + +# Suffix for dependency files +DEP_SUFFIX = dep + +########################################################################### +# Libraries! +# These may be overwridden by {,$(STUKDIR)/,$(STUUDIR)/}config.mk +########################################################################### +410KERNEL_LIBS = \ + libboot.a \ + libelf.a \ + liblmm.a \ + libmalloc.a \ + libmisc.a \ + libRNG.a \ + libsimics.a \ + libstdio.a \ + libstdlib.a \ + libstring.a \ + libx86.a \ + libsmp.a \ + +## Can't build thrgrp by default because it depends on student-written code. +410USER_LIBS_EARLY = # libthrgrp.a +410USER_LIBS_LATE = libRNG.a libx86.a libsimics.a libstdio.a libstdlib.a \ + libstring.a libmalloc.a libtest.a +STUDENT_LIBS_EARLY = libthread.a libautostack.a +STUDENT_LIBS_LATE = libsyscall.a + +########################################################################### +# Details of library structure (you do NOT have to read this part!!) +########################################################################### +# _EARLY means "specified early in the compiler command line" and so +# can be taken to mean "can depend on all _LATE files" +# _LATE means "specified late in the compiler command line" and so +# might be taken as "there be daemons here"; in particular +# these libraries may not depend on _EARLY libraries +# or any library in the list before them. +# +# The full command line order is +# 410USER_LIBS_EARLY -- can depend on everything +# STUDENT_LIBS_EARLY -- can depend only on _LATE libs +# 410USER_LIBS_LATE -- must not depend on _EARLY libs +# STUDENT_LIBS_LATE -- must not depend on any other lib group + +################# DETERMINATION OF INCLUSION BEHAVIORS ##################### +ifeq (0,$(words $(filter %clean,$(MAKECMDGOALS)))) +ifeq (0,$(words $(filter print,$(MAKECMDGOALS)))) +ifeq (0,$(words $(filter sample,$(MAKECMDGOALS)))) +ifeq (0,$(words $(filter %update,$(MAKECMDGOALS)))) +DO_INCLUDE_DEPS=1 +endif +endif +endif +endif + + +################ CONFIGURATION INCLUSION ################# + +-include config.mk + +# Infrastructure configuration files +# These may look like fun, but they are NOT FOR STUDENT USE without +# instructor permisison. Almost anything you want to do can be done +# via the top-level config.mk. +-include $(STUKDIR)/config.mk +-include $(STUUDIR)/config.mk +-include $(EXTRADIR)/extra-early.mk + +############### TARGET VARIABLES ############### + +# FIXME 410ULIBS_LATE is a temporary gross hack; fix later + +PROGS = $(410REQPROGS) $(410REQBINPROGS) \ + $(STUDENTREQPROGS) $(410TESTS) $(STUDENTTESTS) \ + $(EXTRA_TESTS) $(EXTRA_410_TESTS) + +FILES = $(410FILES) $(STUDENTFILES) + +410ULIBS_EARLY = $(patsubst %,$(410UDIR)/%,$(410USER_LIBS_EARLY)) +410ULIBS_LATE = $(patsubst %,$(410UDIR)/%,$(410USER_LIBS_LATE)) +STUULIBS_EARLY = $(patsubst %,$(STUUDIR)/%,$(STUDENT_LIBS_EARLY)) +STUULIBS_LATE = $(patsubst %,$(STUUDIR)/%,$(STUDENT_LIBS_LATE)) + +################# MISCELLANEOUS VARAIBLES ############## + +CRT0 = $(410UDIR)/crt0.o + +LDFLAGSENTRY = --entry=_main + +########### MAKEFILE FILE INCLUSION ############## + +# These are optional so that we can use the same Makefile for P1,2,3 +# Again, these files are NOT FOR STUDENT USE, and unlike the above, +# we probably won't give you permission to overwrite these. :) + +# Boot loader P4 +-include $(BOOTDIR)/boot.mk + +# Guest P4 +-include $(410GDIR)/guests.mk + +# Include 410kern control, responsible for 410kern libraries, objects, interim +-include $(410KDIR)/kernel.mk +# Include 410user control, responsible for 410user libraries and programs +-include $(410UDIR)/user.mk +# Infrastructure +-include $(EXTRADIR)/extra-late.mk + +# Top level targets +-include $(410KDIR)/toplevel.mk + + +############# BUILD PARAMETER VARIABLES ################ +# Note that this section DEPENDS UPON THE INCLUDES ABOVE + +# When generating includes, we do so in the order we do so that it is always +# possible to match from 410kern/lib exactly, or from kern/lib +# if so desired, but that files without directory prefixes will match +# 410kern/inc, kern/, kern/inc, then the 410kern/lib/* entries according to +# 410KERNEL_LIBS, which is under external control. + +CFLAGS_COMMON = -nostdinc \ + -fno-strict-aliasing -fno-builtin -fno-stack-protector -fno-omit-frame-pointer \ + -fno-delete-null-pointer-checks -fwrapv \ + -fno-pic \ + -fcf-protection=none \ + --std=gnu99 \ + -D__STDC_NO_ATOMICS__ \ + -Wall -Werror + +CFLAGS_GCC = $(CFLAGS_COMMON) \ + -fno-aggressive-loop-optimizations \ + -gstabs+ -gstrict-dwarf -O0 -m32 + +CFLAGS_CLANG = $(CFLAGS_COMMON) \ + -gdwarf-3 -gstrict-dwarf -Og -m32 -fno-addrsig -march=i386 \ + --target=i386-unknown-none-unknown \ + -fno-blocks + +CFLAGS_CLANGALYZER = $(CFLAGS_CLANG) +CFLAGS_STUDENT_CLANGALYZER = -pedantic-errors -Weverything \ + -Wno-reserved-id-macro -Wno-unused-macros \ + -Wno-documentation -Wno-documentation-unknown-command \ + -Wno-cast-align -Wno-padded \ + -Wno-unused-parameter \ + -Wno-pointer-arith \ + -Wno-shift-sign-overflow \ + -Wno-vla \ + -Wno-missing-noreturn \ + -Wno-reserved-identifier \ + -Wno-declaration-after-statement \ + -Wno-covered-switch-default + +ANALYZER_CFLAGS = --analyze -Xanalyzer -analyzer-output=text + +ifneq (, $(findstring clangalyzer, $(CC))) + CC = 410-clang + KCFLAGS = $(CFLAGS_CLANGALYZER) + UCFLAGS = $(CFLAGS_CLANG) -mstack-alignment=2 + ANALYZE_ENABLED = YES + CFLAGS_STUDENT = $(CFLAGS_STUDENT_CLANGALYZER) +else ifneq (,$(findstring clang, $(CC))) + CC = 410-clang + KCFLAGS = $(CFLAGS_CLANG) + UCFLAGS = $(CFLAGS_CLANG) -mstack-alignment=2 +else ifneq (, $(findstring gcc, $(CC))) + CC = 410-gcc + KCFLAGS = $(CFLAGS_GCC) + UCFLAGS = $(CFLAGS_GCC) + # This prevents the gcc4 "hurr durr I'm aligning main()'s stack" + UCFLAGS += -mpreferred-stack-boundary=2 +else +$(error "Unknown CC = $(CC)") +endif + +ifneq (,$(findstring kernel,$(CONFIG_DEBUG))) + KCFLAGS += -DDEBUG +endif +ifneq (,$(findstring kernel,$(CONFIG_NDEBUG))) + KCFLAGS += -DNDEBUG +endif +KLDFLAGS = -static -Ttext 100000 --fatal-warnings -melf_i386 +# As of Ubuntu 20.04, w/o --nmagic, ld generates a program header +# which loads the ELF header below 1M. +# GRUB refuses to attempt that, thus ending booting. In theory +# using an add-on linker script with a PHDRS section should make +# this not happen, but we have not yet achieved that. Note that +# an alternate "solution" (again as of Ubuntu 20.04) is to re-enable +# our ancient custom kernel.lds -- apparently that makes things work +# w/o nmagic. +KLDFLAGS += --nmagic +# +KINCLUDES = -I$(410KDIR) -I$(410KDIR)/inc \ + -I$(410SDIR) \ + -I$(STUKDIR) -I$(STUKDIR)/inc \ + $(patsubst lib%.a,-I$(410KDIR)/%,$(410KERNEL_LIBS)) + +ifneq (,$(findstring user,$(CONFIG_DEBUG))) + UCFLAGS += -DDEBUG +endif +ifneq (,$(findstring user,$(CONFIG_NDEBUG))) + UCFLAGS += -DNDEBUG +endif +ULDFLAGS = -static -Ttext 1000000 --fatal-warnings -melf_i386 $(LDFLAGSENTRY) +UINCLUDES = -I$(410SDIR) -I$(410UDIR) -I$(410UDIR)/inc \ + -I$(STUUDIR)/inc \ + $(patsubst %.a,-I$(410UDIR)/%,$(410USER_LIBS_EARLY) $(410USER_LIBS_LATE)) \ + $(patsubst %.a,-I$(STUUDIR)/%,$(STUDENT_LIBS_EARLY) $(STUDENT_LIBS_LATE)) + +TMP_410KOBJS_NOT_DOTO = $(filter-out %.o,$(ALL_410KOBJS)) +ifneq (,$(TMP_410KOBJS_NOT_DOTO)) +$(error "Feeling nervous about '$(TMP_410KOBJS_NOT_DOTO)'") +endif +ALL_410KOBJS_DEPS = $(ALL_410KOBJS:%.o=%.$(DEP_SUFFIX)) + +TMP_410UOBJS_NOT_DOTO = $(filter-out %.o,$(ALL_410UOBJS)) +ifneq (,$(TMP_410UOBJS_NOT_DOTO)) +$(error "Feeling nervous about '$(TMP_410UOBJS_NOT_DOTO)'") +endif +ALL_410UOBJS_DEPS = $(ALL_410UOBJS:%.o=%.$(DEP_SUFFIX)) + +TMP_STUKOBJS_NOT_DOTO = $(filter-out %.o,$(ALL_STUKOBJS)) +ifneq (,$(TMP_STUKOBJS_NOT_DOTO)) +$(error "Feeling nervous about '$(TMP_STUKOBJS_NOT_DOTO)'") +endif +ALL_STUKOBJS_DEPS = $(ALL_STUKOBJS:%.o=%.$(DEP_SUFFIX)) + +TMP_STUUOBJS_NOT_DOTO = $(filter-out %.o,$(ALL_STUUOBJS)) +ifneq (,$(TMP_STUUOBJS_NOT_DOTO)) +$(error "Feeling nervous about '$(TMP_STUUOBJS_NOT_DOTO)'") +endif +ALL_STUUOBJS_DEPS = $(ALL_STUUOBJS:%.o=%.$(DEP_SUFFIX)) + +STUUPROGS_DEPS = $(STUUPROGS:%=%.dep) +410UPROGS_DEPS = $(410UPROGS:%=%.dep) + +############## UPDATE RULES ##################### + +update: + ./update.sh $(UPDATE_METHOD) + $(GUEST_UPDATE) + +query_update: + ./update.sh $(UPDATE_METHOD) query + +################### GENERIC RULES ###################### +%.o: %.S + $(CC) $(CFLAGS) -DASSEMBLER $(INCLUDES) -c -MD -MP -MF $(@:.o=.$(DEP_SUFFIX)) -MT $@ -o $@ $< + $(OBJCOPY) -R .comment -R .note -R .note.gnu.property $@ $@ + +%.o: %.s + @echo "You should use the .S file extension rather than .s" + @echo ".s does not support precompiler directives (like #include)" + @false + +# There is a bug in clang that such that the .o file will not be generated if +# the static analyzer is executed. +%.o: %.c + @expand -t $(TABSTOP) $< | awk 'length > 80 \ + { err++; \ + errs[err] = "Warning: line " NR " in $< is longer than 80 characters"; \ + } END { \ + if (err > 2 && err < 1000) for (i = 1; i <= err; i++) print errs[i];\ + exit(err > 10 && err < 1000) }' +ifeq ($(ANALYZE),YES) + $(CC) $(CFLAGS) $(ANALYZER_CFLAGS) $(INCLUDES) -c -o $@ $< +endif + $(CC) $(CFLAGS) $(INCLUDES) -c -MD -MP -MF $(@:.o=.$(DEP_SUFFIX)) -MT $@ -o $@ $< + $(OBJCOPY) -R .comment -R .note -R .note.gnu.property $@ $@ + +%.a: + rm -f $@ + $(AR) rc $@ $^ + +################ PATTERNED VARIABLE ASSIGNMENTS ################## +# Some of the oddness is that the 410 base code won't currently +# stand up to extreme scrutiny. +$(410KDIR)/%: CFLAGS=$(KCFLAGS) +$(410KDIR)/%: ANALYZE=NO +$(410KDIR)/%: INCLUDES=$(KINCLUDES) +$(410KDIR)/%: LDFLAGS=$(KLDFLAGS) +$(STUKDIR)/%: CFLAGS=$(KCFLAGS) $(CFLAGS_STUDENT) +$(STUKDIR)/%: ANALYZE=$(ANALYZE_ENABLED) +$(STUKDIR)/%: INCLUDES=$(KINCLUDES) +$(STUKDIR)/%: LDFLAGS=$(KLDFLAGS) +$(410UDIR)/%: CFLAGS=$(UCFLAGS) +$(410UDIR)/%: ANALYZE=NO +$(410UDIR)/%: INCLUDES=$(UINCLUDES) +$(410UDIR)/%: LDFLAGS=$(ULDFLAGS) +$(STUUDIR)/%: CFLAGS=$(UCFLAGS) $(CFLAGS_STUDENT) +$(STUUDIR)/%: ANALYZE=$(ANALYZE_ENABLED) +$(STUUDIR)/%: INCLUDES=$(UINCLUDES) +$(STUUDIR)/%: LDFLAGS=$(ULDFLAGS) + +################# USERLAND PROGRAM UNIFICATION RULES ################# + +$(410REQPROGS:%=$(BUILDDIR)/%): \ +$(BUILDDIR)/%: $(410UDIR)/$(UPROGDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +$(410REQBINPROGS:%=$(BUILDDIR)/%): \ +$(BUILDDIR)/%: $(410UDIR)/$(UPROGDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +$(410TESTS:%=$(BUILDDIR)/%) : \ +$(BUILDDIR)/% : $(410UDIR)/$(UPROGDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +$(EXTRA_410_TESTS:%=$(BUILDDIR)/%) : \ +$(BUILDDIR)/% : $(410UDIR)/$(UPROGDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +$(STUDENTREQPROGS:%=$(BUILDDIR)/%) : \ +$(BUILDDIR)/% : $(STUUDIR)/$(UPROGDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +$(STUDENTTESTS:%=$(BUILDDIR)/%) : \ +$(BUILDDIR)/% : $(STUUDIR)/$(UPROGDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +# 410user/files/* and user/files/* are dependencies, but +# they are not targets to be built. In particular, if +# both 410user/files/x and 410user/files/x.S exist, don't +# try to build one from the other. +.PHONY: $(410FILES:%=$(410UDIR)/$(UFILEDIR)/%) +.PHONY: $(STUDENTFILES:%=$(STUUDIR)/$(UFILEDIR)/%) + +$(410FILES:%=$(BUILDDIR)/%) : \ +$(BUILDDIR)/% : $(410UDIR)/$(UFILEDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +$(STUDENTFILES:%=$(BUILDDIR)/%) : \ +$(BUILDDIR)/% : $(STUUDIR)/$(UFILEDIR)/% + mkdir -p $(BUILDDIR) + cp $< $@ + +############## MISCELLANEOUS TARGETS ################# + +html_doc: + $(DOC) doxygen.conf + +PRINTOUT=kernel.pdf +PRINTOUTPS=$(PRINTOUT:%.pdf=%.ps) + +print: + enscript -2rG -fCourier7 -FCourier-Bold10 -p $(PRINTOUTPS) \ + $(if $(strip $(TABSTOP)),-T $(TABSTOP),) \ + README.dox \ + `find ./kern/ -type f -regex '.*\.[chS]' | sort` + ps2pdf $(PRINTOUTPS) $(PRINTOUT) + +################# CLEANING RULES ##################### +.PHONY: clean veryclean + +clean: + rm -f $(CRT0) + rm -f $(FINALCLEANS) + rm -f $(ALL_410KOBJS) + rm -f $(ALL_410KOBJS_DEPS) + rm -f $(410KCLEANS) + rm -f $(ALL_410UOBJS) + rm -f $(ALL_410UOBJS_DEPS) + rm -f $(410UCLEANS) + rm -f $(410UPROGS:%=%.o) + rm -f $(410UPROGS_DEPS) + rm -f $(ALL_STUKOBJS) + rm -f $(ALL_STUKOBJS_DEPS) + rm -f $(STUKCLEANS) + rm -f $(ALL_STUUOBJS) + rm -f $(ALL_STUUOBJS_DEPS) + rm -f $(STUUCLEANS) + rm -f $(STUUPROGS:%=%.o) + rm -f $(STUUPROGS_DEPS) + rm -f $(BOOT_CLEANS) + $(GUEST_CLEAN) + +veryclean: clean + rm -rf doc $(PRINTOUT) $(PRINTOUTPS) bootfd.img kernel kernel.log $(BUILDDIR) + rm -f $(FINALVERYCLEANS) + $(GUEST_VERYCLEAN) + +%clean: + $(error "Unknown cleaning target") + +########### DEPENDENCY FILE INCLUSION ############ +ifeq (1,$(DO_INCLUDE_DEPS)) +ifneq (,$(ALL_410KOBJS)) +-include $(ALL_410KOBJS_DEPS) +endif +ifneq (,$(ALL_STUKOBJS)) +-include $(ALL_STUKOBJS_DEPS) +endif +ifneq (,$(ALL_410UOBJS)) +-include $(ALL_410UOBJS_DEPS) +endif +ifneq (,$(ALL_STUUOBJS)) +-include $(ALL_STUUOBJS_DEPS) +endif +ifneq (,$(410UPROGS_DEPS)) +-include $(410UPROGS_DEPS) +endif +ifneq (,$(STUUPROGS_DEPS)) +-include $(STUUPROGS_DEPS) +endif +endif + +########### MANDATE CLEANING AS ONLY TARGETS ############ +ifneq (0,$(words $(filter %clean,$(MAKECMDGOALS)))) + # The target includes a make target + ifneq (0, $(words $(filter-out %clean,$(MAKECMDGOALS)))) + # There is another target on the list + $(error "Clean targets must run by themselves") + endif +endif diff --git a/README.STARTING_P4 b/README.STARTING_P4 new file mode 100644 index 0000000..f851e98 --- /dev/null +++ b/README.STARTING_P4 @@ -0,0 +1,26 @@ +To get started with P4: + +1. Make a new P4 source tree by cloning your P3 source tree. + +2. Move/copy the update.sh obtained from the proj4.tar.gz + tarball so it replaces the update.sh present in your + newly-made P4 tree. + +3. Move/copy the guests sub-directory obtained from the + proj4.tar.gz tarball to create a top-level directory + called "guests" in your newly-made P4 source tree. + +4. In your newly-made P4 source tree, run "make update". + You should see a bunch of updates. + +5. Now "make" should work. The resulting system should behave a + LOT like your unaltered P3! + +6. Read the directions in guests/README to find out how to build + guest kernels. + +See http://www.cs.cmu.edu/~410/p4/ for what you are supposed to do. + +Don't forget that your README.dox for P4 should document your P4, +not your P3! Please be sure that the documentation includes +everything we ask for. diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..067d33f --- /dev/null +++ b/config.mk @@ -0,0 +1,218 @@ +########################################################################### +# +# ##### ####### ####### ###### ### +# # # # # # # # ### +# # # # # # # ### +# ##### # # # ###### # +# # # # # # +# # # # # # # ### +# ##### # ####### # ### +# +# +# Please read the directions in README and in this config.mk carefully. +# Do -N-O-T- just dump things randomly in here until your kernel builds. +# If you do that, you run an excellent chance of turning in something +# which can't be graded. If you think the build infrastructure is +# somehow restricting you from doing something you need to do, contact +# the course staff--don't just hit it with a hammer and move on. +# +# [I REFUSE TO READ IT] +########################################################################### + +########################################################################### +# This is the include file for the make file. +# You should have to edit only this file to get things to build. +########################################################################### + +########################################################################### +# Tab stops +########################################################################### +# If you use tabstops set to something other than the international +# standard of eight characters, this is your opportunity to inform +# our print scripts. +TABSTOP = 8 + +########################################################################### +# Compiler +########################################################################### +# Selections (see handout for details): +# +# gcc - default (what we will grade with) +# clang - Clang/LLVM +# clangalyzer - Clang/LLVM plus static analyzer +# +# "gcc" may have a better Simics debugging experience +# +# "clang" may provide helpful warnings, assembly +# code may be more readable +# +# "clangalyzer" will likely complain more than "clang" +# +# Use "make veryclean" if you adjust CC. +CC = gcc + +########################################################################### +# DEBUG +########################################################################### +# You can set CONFIG_DEBUG to any mixture of the words +# "kernel" and "user" to #define the DEBUG flag when +# compiling the respective type(s) of code. The ordering +# of the words doesn't matter, and repeating a word has +# no additional effect. +# +# Use "make veryclean" if you adjust CONFIG_DEBUG. +# +CONFIG_DEBUG = user kernel + +########################################################################### +# NDEBUG +########################################################################### +# You can set CONFIG_NDEBUG to any mixture of the words +# "kernel" and "user" to #define the NDEBUG flag when +# compiling the respective type(s) of code. The ordering +# of the words doesn't matter, and repeating a word has +# no additional effect. Defining NDEBUG will cause the +# checks using assert() to be *removed*. +# +# Use "make veryclean" if you adjust CONFIG_NDEBUG. +# +CONFIG_NDEBUG = + +########################################################################### +# The method for acquiring project updates. +########################################################################### +# This should be "afs" for any Andrew machine, "web" for non-andrew machines +# and "offline" for machines with no network access. +# +# "offline" is strongly not recommended as you may miss important project +# updates. +# +UPDATE_METHOD = afs + +########################################################################### +# WARNING: When we test your code, the two TESTS variables below will be +# blanked. Your kernel MUST BOOT AND RUN if 410TESTS and STUDENTTESTS +# are blank. It would be wise for you to test that this works. +########################################################################### + +########################################################################### +# Test programs provided by course staff you wish to run +########################################################################### +# A list of the test programs you want compiled in from the 410user/progs +# directory. +# +410TESTS = + +########################################################################### +# Test programs you have written which you wish to run +########################################################################### +# A list of the test programs you want compiled in from the user/progs +# directory. +# +STUDENTTESTS = mandelbrot racer nibbles + +########################################################################### +# Data files provided by course staff to build into the RAM disk +########################################################################### +# A list of the data files you want built in from the 410user/files +# directory. +# +410FILES = + +########################################################################### +# Data files you have created which you wish to build into the RAM disk +########################################################################### +# A list of the data files you want built in from the user/files +# directory. +# +STUDENTFILES = + +########################################################################### +# Object files for your thread library +########################################################################### +THREAD_OBJS = malloc.o panic.o thread.o thread_fork.o mutex.o cond.o sem.o \ + rwlock.o mutex_lock.o rb_tcb.o + +# Thread Group Library Support. +# +# Since libthrgrp.a depends on your thread library, the "buildable blank +# P3" we give you can't build libthrgrp.a. Once you install your thread +# library and fix THREAD_OBJS above, uncomment this line to enable building +# libthrgrp.a: +410USER_LIBS_EARLY += libthrgrp.a + +########################################################################### +# Object files for your syscall wrappers +########################################################################### +SYSCALL_OBJS = syscall.o + +########################################################################### +# Object files for your automatic stack handling +########################################################################### +AUTOSTACK_OBJS = autostack.o + +########################################################################### +# Parts of your kernel +########################################################################### +# +# Kernel object files you want included from 410kern/ +# +410KERNEL_OBJS = load_helper.o +# +# Kernel object files you provide in from kern/ +# +KERNEL_OBJS = console.o kernel.o loader.o malloc_wrappers.o sync_asm.o \ + mm.o asm_instr.o sched.o sched_asm.o syscall_asm.o interrupt.o \ + paging.o timer.o interrupt_asm.o usermem.o syscall_process.o \ + syscall_memory.o syscall_thread.o common.o sync.o syscall_io.o \ + usermem_asm.o syscall_misc.o kbd.o + +########################################################################### +# WARNING: Do not put **test** programs into the REQPROGS variables. Your +# kernel will probably not build in the test harness and you will +# lose points. +########################################################################### + +########################################################################### +# Mandatory programs whose source is provided by course staff +########################################################################### +# A list of the programs in 410user/progs which are provided in source +# form and NECESSARY FOR THE KERNEL TO RUN. +# +# The shell is a really good thing to keep here. Don't delete idle +# or init unless you are writing your own, and don't do that unless +# you have a really good reason to do so. +# +410REQPROGS = \ + ack fib mem_eat_test sleep_test1 \ + actual_wait fork_bomb mem_permissions stack_test1 \ + bg fork_exit_bomb merchant swexn_basic_test \ + bistromath fork_test1 minclone_mem swexn_cookie_monster \ + cat fork_wait_bomb new_pages swexn_dispatch \ + cho2 fork_wait peon swexn_rampage \ + cho getpid_test1 print_basic swexn_regs \ + cho_variant halt_test swexn_stands_for_swextensible \ + chow idle readline_basic swexn_uninstall_test \ + ck1 init register_test wait_getpid \ + coolness knife remove_pages_test1 wild_test1 \ + deschedule_hang loader_test1 remove_pages_test2 work \ + exec_basic loader_test2 score yield_desc_mkrun \ + exec_basic_helper make_crash shell \ + exec_nonexist make_crash_helper slaughter \ + minclone_many + + +########################################################################### +# Mandatory programs whose source is provided by you +########################################################################### +# A list of the programs in user/progs which are provided in source +# form and NECESSARY FOR THE KERNEL TO RUN. +# +# Leave this blank unless you are writing custom init/idle/shell programs +# (not generally recommended). If you use STUDENTREQPROGS so you can +# temporarily run a special debugging version of init/idle/shell, you +# need to be very sure you blank STUDENTREQPROGS before turning your +# kernel in, or else your tweaked version will run and the test harness +# won't. +# +STUDENTREQPROGS = diff --git a/doxygen.conf b/doxygen.conf new file mode 100644 index 0000000..b8d9f41 --- /dev/null +++ b/doxygen.conf @@ -0,0 +1,1101 @@ +# Doxyfile 1.3.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "15-410 Project 3" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./doc + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = doxygen.warn + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ./README.dox kern + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs + +FILE_PATTERNS = *.c *.h *.S *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = ./lib ./doc + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = *.h + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# colloborations diagrams in a style similiar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = NO + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = NO + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/guests/README b/guests/README new file mode 100644 index 0000000..f67983f --- /dev/null +++ b/guests/README @@ -0,0 +1,60 @@ +This file contains directions for building guest kernels +from source. The basic idea is that each guest, e.g., +"hello", that is built from source gets its own entire +P4 build tree in, e.g., guests/hello. When you type +"make" in your top-level directory, make will also be +run in the guests/hello directory, which will hopefully +cause a kernel to be built in guests/hello/kernel. That +kernel image will then be included in your RAM disk, named +"hello". For guests/hello to be built in this way the +STUDENTGUESTS directive in config.mk must include "hello" +(guests/ directories that are not so listed will be ignored). + +Here is a step-by-step guide to building the "hello" guest +from source: + +0. If you already have a test program called "hello", + make sure to remove it from STUDENTTESTS in your + config.mk. Likewise, if you are running our pre-built + "hello" binary, remove it from 410GUESTBINS. + +1. edit config.mk so your STUDENTGUESTS directive + contains "hello" (initially you will not have + such a directive, so you will need to add one). + +2. cd guests + +3. Download a copy of the P4 tarball, proj4.tar.gz. +Note that some browsers will "helpfully" uncompress +the file for you but leave the filename unchanged. +So try one of the following two commands at random: + + tar xpvfz proj4.tar.gz + tar xpvf proj4.tar.gz + +4. mv p4 hello + +5. (cd hello && ./update.sh) + +Now you have a guests/hello directory that will build a +guest kernel, but one that does nothing interesting. The +next step is to copy the source we gave you into that build +tree. + +5. cd .. + +6. (cd 410guests/hello && tar cf - .) | (cd guests/hello && tar xpf -) + +7. Upgrade guests/hello/kern/hvstubs.S so it makes hypercalls. + +8. make + +In your top-level directory, the file "temp/hello" should +be created, and when you boot your kernel and do "ls" you +should see "hello". + +If you happen to want to build a guest kernel from source +of your own (such as your P1), you would follow steps 1 +through 5, insert a valid hvstubs.S, and then write the +rest of your guest kernel (perhaps starting from your P1 +kernel source). diff --git a/kern/asm_instr.S b/kern/asm_instr.S new file mode 100644 index 0000000..e096302 --- /dev/null +++ b/kern/asm_instr.S @@ -0,0 +1,22 @@ +/** @file asm_instr.c + * + * @brief assembly stubs. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +.text + +.global invlpg +.type invlpg, %function +invlpg: + mov 0x4(%esp), %eax + invlpg (%eax) + ret + +.global hlt +.type hlt, %function +hlt: + hlt + ret /* keep it for other platforms that do not respond to hlt */ diff --git a/kern/common.c b/kern/common.c new file mode 100644 index 0000000..93edb3d --- /dev/null +++ b/kern/common.c @@ -0,0 +1,472 @@ +/** @file common.c + * + * @brief common data structures. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ +#include + +#include + +void queue_insert_head(queue_t** queue, queue_t* t) { + if (*queue == NULL) { + t->next = t->prev = t; + } else { + t->next = *queue; + t->prev = (*queue)->prev; + (*queue)->prev->next = t; + (*queue)->prev = t; + } + *queue = t; +} + +void queue_insert_tail(queue_t** queue, queue_t* t) { + if (*queue == NULL) { + t->next = t->prev = t; + *queue = t; + } else { + t->next = *queue; + t->prev = (*queue)->prev; + (*queue)->prev->next = t; + (*queue)->prev = t; + } +} + +queue_t* queue_remove_head(queue_t** queue) { + queue_t* t = *queue; + if (t->next == t) { + *queue = NULL; + } else { + t->next->prev = t->prev; + t->prev->next = t->next; + *queue = t->next; + } + return t; +} + +queue_t* queue_remove_tail(queue_t** queue) { + queue_t* t = (*queue)->prev; + if (t->next == t) { + *queue = NULL; + } else { + t->next->prev = t->prev; + t->prev->next = t->next; + } + return t; +} + +void queue_detach(queue_t** queue, queue_t* t) { + if (*queue == t) { + if (t->next == t) { + *queue = NULL; + } else { + *queue = t->next; + } + } + t->next->prev = t->prev; + t->prev->next = t->next; +} + +int heap_init(heap_t* heap) { + return vector_init(heap, sizeof(heap_node_t), INITIAL_HEAP_SIZE); +} + +int heap_insert(heap_t* heap, heap_node_t* node) { + if (vector_push(heap, node) != 0) { + return -1; + } + int cur = vector_size(heap) - 1; + while (cur != 0) { + int parent = ((cur - 1) >> 1); + heap_node_t* cn = (heap_node_t*)vector_at(heap, cur); + heap_node_t* pn = (heap_node_t*)vector_at(heap, parent); + if (cn->key >= pn->key) { + break; + } + heap_node_t t = *pn; + *pn = *cn; + *cn = t; + cur = parent; + } + return 0; +} + +heap_node_t* heap_peak(heap_t* heap) { + return (vector_size(heap) == 0 ? NULL : (heap_node_t*)vector_at(heap, 0)); +} + +void heap_pop(heap_t* heap) { + int size = vector_size(heap); + if (size == 0) { + return; + } + *(heap_node_t*)vector_at(heap, 0) = + *(heap_node_t*)vector_at(heap, size - 1); + vector_pop(heap); + size--; + int cur = 0; + while (1) { + int lc = cur * 2 + 1; + int rc = lc + 1; + int small = cur; + heap_node_t* cn = (heap_node_t*)vector_at(heap, cur); + heap_node_t *ln, *rn, *sn = cn; + if (lc < size) { + ln = (heap_node_t*)vector_at(heap, lc); + if (ln->key < sn->key) { + small = lc; + sn = ln; + } + } + if (rc < size) { + rn = (heap_node_t*)vector_at(heap, rc); + if (rn->key < sn->key) { + small = rc; + sn = rn; + } + } + if (small == cur) { + break; + } + if (small == lc) { + heap_node_t t = *ln; + *ln = *cn; + *cn = t; + cur = lc; + } else { + heap_node_t t = *rn; + *rn = *cn; + *cn = t; + cur = rc; + } + } +} + +rb_t rb_nil = { + .color = RB_BLACK, + .parent = &rb_nil, + .left = &rb_nil, + .right = &rb_nil, +}; + +rb_t* rb_find(rb_t* root, int key) { + rb_t* p = root; + while (p != &rb_nil) { + if (key == p->key) { + return p; + } + p = (key > p->key) ? p->right : p->left; + } + return NULL; +} + +/** + * @brief left rotate on a node + * @param root rbtree root + * @param node node + */ +static void rb_rotate_left(rb_t** root, rb_t* node) { + rb_t* r = node->right; + node->right = r->left; + if (r->left != &rb_nil) { + r->left->parent = node; + } + r->parent = node->parent; + if (node->parent == &rb_nil) { + *root = r; + } else if (node == node->parent->left) { + node->parent->left = r; + } else { + node->parent->right = r; + } + r->left = node; + node->parent = r; +} + +/** + * @brief right rotate on a node + * @param root rbtree root + * @param node node + */ +static void rb_rotate_right(rb_t** root, rb_t* node) { + rb_t* l = node->left; + node->left = l->right; + if (l->right != &rb_nil) { + l->right->parent = node; + } + l->parent = node->parent; + if (node->parent == &rb_nil) { + *root = l; + } else if (node == node->parent->left) { + node->parent->left = l; + } else { + node->parent->right = l; + } + l->right = node; + node->parent = l; +} + +/** + * @brief fixup after insertion + * @param root rbtree root + * @param node node + */ +static void rb_fixup(rb_t** root, rb_t* node) { + while (node->parent->color == RB_RED) { + rb_t* grand = node->parent->parent; + if (node->parent == grand->left) { + rb_t* uncle = grand->right; + if (uncle->color == RB_RED) { + node->parent->color = RB_BLACK; + uncle->color = RB_BLACK; + node->parent->parent->color = RB_RED; + node = node->parent->parent; + } else { + if (node == node->parent->right) { + node = node->parent; + rb_rotate_left(root, node); + } + node->parent->color = RB_BLACK; + grand->color = RB_RED; + rb_rotate_right(root, grand); + } + } else { + rb_t* uncle = grand->left; + if (uncle->color == RB_RED) { + node->parent->color = RB_BLACK; + uncle->color = RB_BLACK; + node->parent->parent->color = RB_RED; + node = node->parent->parent; + } else { + if (node == node->parent->left) { + node = node->parent; + rb_rotate_right(root, node); + } + node->parent->color = RB_BLACK; + grand->color = RB_RED; + rb_rotate_left(root, grand); + } + } + } + (*root)->color = RB_BLACK; +} + +void rb_insert(rb_t** root, rb_t* node) { + rb_t *p = *root, *parent = &rb_nil; + while (p != &rb_nil) { + parent = p; + p = (node->key > p->key) ? p->right : p->left; + } + node->parent = parent; + if (parent == &rb_nil) { + *root = node; + } else if (node->key > parent->key) { + parent->right = node; + } else { + parent->left = node; + } + node->left = node->right = &rb_nil; + node->color = RB_RED; + rb_fixup(root, node); +} + +/** + * @brief move v to u's position + * @param root rbtree root + * @param u u + * @param v v + */ +static void rb_transplant(rb_t** root, rb_t* u, rb_t* v) { + if (u->parent == &rb_nil) { + *root = v; + } else if (u == u->parent->left) { + u->parent->left = v; + } else { + u->parent->right = v; + } + v->parent = u->parent; +} + +rb_t* rb_min(rb_t* root) { + while (root->left != &rb_nil) { + root = root->left; + } + return root; +} + +rb_t* rb_next(rb_t* node) { + if (node->right != &rb_nil) { + return rb_min(node->right); + } + rb_t* parent = node->parent; + while (parent != &rb_nil && node == parent->right) { + node = parent; + parent = parent->parent; + } + return parent; +} + +/** + * @brief fixup after deletion + * @param root rbtree root + * @param node node + */ +static void rb_delete_fixup(rb_t** root, rb_t* node) { + while (node != *root && node->color == RB_BLACK) { + if (node == node->parent->left) { + rb_t* r = node->parent->right; + if (r->color == RB_RED) { + r->color = RB_BLACK; + node->parent->color = RB_RED; + rb_rotate_left(root, node->parent); + r = node->parent->right; + } + if (r->left->color == RB_BLACK && r->right->color == RB_BLACK) { + r->color = RB_RED; + node = node->parent; + } else { + if (r->right->color == RB_BLACK) { + r->left->color = RB_BLACK; + r->color = RB_RED; + rb_rotate_right(root, r); + r = node->parent->right; + } + r->color = node->parent->color; + node->parent->color = RB_BLACK; + r->right->color = RB_BLACK; + rb_rotate_left(root, node->parent); + node = *root; + } + } else { + rb_t* l = node->parent->left; + if (l->color == RB_RED) { + l->color = RB_BLACK; + node->parent->color = RB_RED; + rb_rotate_right(root, node->parent); + l = node->parent->left; + } + if (l->right->color == RB_BLACK && l->left->color == RB_BLACK) { + l->color = RB_RED; + node = node->parent; + } else { + if (l->left->color == RB_BLACK) { + l->right->color = RB_BLACK; + l->color = RB_RED; + rb_rotate_left(root, l); + l = node->parent->left; + } + l->color = node->parent->color; + node->parent->color = RB_BLACK; + l->left->color = RB_BLACK; + rb_rotate_right(root, node->parent); + node = *root; + } + } + } + node->color = RB_BLACK; +} + +void rb_delete(rb_t** root, rb_t* node) { + rb_t *x, *y = node; + int orig_color = y->color; + if (node->left == &rb_nil) { + x = node->right; + rb_transplant(root, node, x); + } else if (node->right == &rb_nil) { + x = node->left; + rb_transplant(root, node, x); + } else { + y = rb_min(node->right); + orig_color = y->color; + x = y->right; + if (y->parent == node) { + x->parent = y; + } else { + rb_transplant(root, y, y->right); + y->right = node->right; + y->right->parent = y; + } + rb_transplant(root, node, y); + y->left = node->left; + y->left->parent = y; + y->color = node->color; + } + if (orig_color == RB_BLACK) { + rb_delete_fixup(root, x); + } +} + +/** do not shink small vectors as this do not bring big benefit */ +#define VECTOR_MINIMUM_SIZE 8 +/** don't shink too fast so we divide by 3 */ +#define VECTOR_SHINK_RATIO 3 + +int vector_init(vector_t* v, int elem_size, int init_size) { + v->elem_size = elem_size; + v->size = init_size; + v->array = (char*)smalloc(init_size * elem_size); + v->current = 0; + return (v->array == NULL ? -1 : 0); +} + +int vector_size(vector_t* v) { + return v->current; +} + +int vector_push(vector_t* v, void* elem) { + if (v->current == v->size) { + char* result = (char*)smalloc(v->size * v->elem_size * 2); + if (result == NULL) { + return -1; + } + memcpy(result, v->array, v->current * v->elem_size); + sfree(v->array, v->size * v->elem_size); + v->size <<= 1; + v->array = result; + } + memcpy(v->array + v->current * v->elem_size, elem, v->elem_size); + v->current++; + return 0; +} + +/** + * @brief check if a vector should shrink + * @param v vector + */ +static void vector_try_shink(vector_t* v) { + if (v->current < v->size / VECTOR_SHINK_RATIO) { + if ((v->size / 2) < VECTOR_MINIMUM_SIZE) { + return; + } + char* result = (char*)smalloc((v->size / 2) * v->elem_size); + if (result == NULL) { + return; + } + memcpy(result, v->array, v->current * v->elem_size); + sfree(v->array, v->size * v->elem_size); + v->size >>= 1; + v->array = result; + } +} + +void vector_pop(vector_t* v) { + v->current--; + vector_try_shink(v); +} + +void vector_remove(vector_t* v, int index) { + memmove(v->array + index * v->elem_size, + v->array + (index + 1) * v->elem_size, + (v->current - index - 1) * v->elem_size); + v->current--; + vector_try_shink(v); +} + +void* vector_at(vector_t* v, int index) { + return (void*)(v->array + index * v->elem_size); +} + +void vector_free(vector_t* v) { + sfree(v->array, v->size * v->elem_size); +} diff --git a/kern/console.c b/kern/console.c new file mode 100644 index 0000000..2b25fcc --- /dev/null +++ b/kern/console.c @@ -0,0 +1,212 @@ +/** @file console.c + * + * @brief Console driver implementation. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include +#include + +#include +#include + +#include + +/** how many bits in a x86 byte */ +#define NUM_OF_BITS_X86 8 +/** Mask bits for a 8-bit byte */ +#define BYTE_MASK_X86 0xFF + +/** index of the register to start displaying cursor */ +#define CRTC_CURSOR_START 10 +/** bit to start displaying cursor */ +#define CURSOR_ENABLE_BIT 0x20 + +/** + * Someone is not satisfied with the type name char_t so we use this + * to reperesent a char on screen so that nobody will mistake it with 'char' + */ +typedef struct a_char_on_screen_s { + uint8_t ch; /** char */ + uint8_t color; /** color */ +} a_char_on_screen_t; + +/** pointer to the viedo memory at B800h */ +a_char_on_screen_t (*console_mem)[CONSOLE_WIDTH] = + (a_char_on_screen_t(*)[CONSOLE_WIDTH])CONSOLE_MEM_BASE; + +/** the char used to produce blank */ +#define BLANK_CH ' ' +/** initial color of the cursor */ +#define DEFAULT_COLOR (FGND_WHITE | BGND_BLACK) + +/** x position of the cursor */ +static int cur_x = 0; +/** y position of the cursor */ +static int cur_y = 0; +/** current color of the cursor */ +static char cur_color = DEFAULT_COLOR; +/** should the cursor be displayed? */ +static int cur_shown = true; + +/** mutex for console operations */ +mutex_t console_lock = MUTEX_INIT; + +/** + * @brief Move the cursor to a position. Position is checked before calling this + * function + * @param x x + * @param y y + */ +static void move_cursor(int x, int y) { + cur_x = x; + cur_y = y; + int pos = y * CONSOLE_WIDTH + x; + outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX); + outb(CRTC_DATA_REG, pos & BYTE_MASK_X86); + outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX); + outb(CRTC_DATA_REG, pos >> NUM_OF_BITS_X86); +} + +/** + * @brief Scroll the console by one line and clean the last line + */ +static void scroll_page() { + /* move all but last line forward */ + memmove(console_mem[0], console_mem[1], + sizeof(a_char_on_screen_t) * CONSOLE_WIDTH * (CONSOLE_HEIGHT - 1)); + int i; + for (i = 0; i < CONSOLE_WIDTH; i++) { + console_mem[CONSOLE_HEIGHT - 1][i] = + (a_char_on_screen_t){BLANK_CH, cur_color}; + } +} + +int putbyte(char ch) { + if (ch == '\n') { + if (cur_y < CONSOLE_HEIGHT - 1) { + move_cursor(0, cur_y + 1); + } else { + scroll_page(); + move_cursor(0, cur_y); + } + return ch; + } + if (ch == '\r') { + move_cursor(0, cur_y); + return ch; + } + if (ch == '\b') { + if (cur_x > 0) { + move_cursor(cur_x - 1, cur_y); + + } else if (cur_y > 0) { + move_cursor(CONSOLE_WIDTH - 1, cur_y - 1); + } + console_mem[cur_y][cur_x] = (a_char_on_screen_t){BLANK_CH, cur_color}; + return ch; + } + /* save the position where we should show the char */ + int prev_x = cur_x, prev_y = cur_y; + if (cur_x < CONSOLE_WIDTH - 1) { + /* move forward */ + move_cursor(cur_x + 1, cur_y); + } else if (cur_y < CONSOLE_HEIGHT - 1) { + /* go to next line */ + move_cursor(0, cur_y + 1); + } else { + /* scroll and go to beginning of the line */ + scroll_page(); + move_cursor(0, cur_y); + prev_y -= 1; + } + console_mem[prev_y][prev_x] = (a_char_on_screen_t){ch, cur_color}; + return ch; +} + +void putbytes(const char* s, int len) { + if (s == NULL || len <= 0) { + return; + } + int i; + for (i = 0; i < len; i++) { + putbyte(s[i]); + } +} + +void draw_char(int row, int col, int ch, int color) { + if (row >= CONSOLE_HEIGHT || row < 0) { + return; + } + if (col >= CONSOLE_WIDTH || col < 0) { + return; + } + if (color > BYTE_MASK_X86 || color < 0) { + return; + } + console_mem[row][col] = (a_char_on_screen_t){ch, color}; +} + +int set_term_color(int color) { + if (color > BYTE_MASK_X86 || color < 0) { + return -1; + } + cur_color = (char)color; + return 0; +} + +void get_term_color(int* color) { + *color = cur_color; +} + +int set_cursor(int row, int col) { + if (row >= CONSOLE_HEIGHT || row < 0) { + return -1; + } + if (col >= CONSOLE_WIDTH || col < 0) { + return -1; + } + move_cursor(col, row); + return 0; +} + +void get_cursor(int* row, int* col) { + *row = cur_y; + *col = cur_x; +} + +void hide_cursor(void) { + cur_shown = 0; + outb(CRTC_IDX_REG, CRTC_CURSOR_START); + outb(CRTC_DATA_REG, inb(CRTC_DATA_REG) | CURSOR_ENABLE_BIT); +} + +void show_cursor(void) { + cur_shown = 1; + outb(CRTC_IDX_REG, CRTC_CURSOR_START); + outb(CRTC_DATA_REG, inb(CRTC_DATA_REG) & ~CURSOR_ENABLE_BIT); +} + +void clear_console(void) { + move_cursor(0, 0); + int i, j; + for (i = 0; i < CONSOLE_HEIGHT - 1; i++) { + for (j = 0; j < CONSOLE_WIDTH - 1; j++) { + console_mem[i][j] = (a_char_on_screen_t){BLANK_CH, cur_color}; + } + } +} + +char get_char(int row, int col) { + if (row >= CONSOLE_HEIGHT || row < 0) { + return BLANK_CH; + } + if (col >= CONSOLE_WIDTH || col < 0) { + return BLANK_CH; + } + return console_mem[row][col].ch; +} diff --git a/kern/inc/asm_instr.h b/kern/inc/asm_instr.h new file mode 100644 index 0000000..f323b81 --- /dev/null +++ b/kern/inc/asm_instr.h @@ -0,0 +1,25 @@ +/** @file asm_instr.h + * + * @brief assembly stubs. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _ASM_INSTR_H_ +#define _ASM_INSTR_H_ + +#include + +/** + * @brief runs invlpg on an address + * @param va addr to invalidate + */ +void invlpg(va_t va); + +/** + * @brief runs hlt + */ +void hlt(); + +#endif diff --git a/kern/inc/common.h b/kern/inc/common.h new file mode 100644 index 0000000..dad473b --- /dev/null +++ b/kern/inc/common.h @@ -0,0 +1,228 @@ +/** @file common.h + * + * @brief common data structure + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include + +/** + * a queue node + */ +typedef struct queue_s { + struct queue_s* next; + struct queue_s* prev; +} queue_t; + +/** + * @brief insert a node to the head of a queue + * @param queue queue + * @param t the node + */ +void queue_insert_head(queue_t** queue, queue_t* t); + +/** + * @brief insert a node to the tail of a queue + * @param queue queue + * @param t the node + */ +void queue_insert_tail(queue_t** queue, queue_t* t); + +/** + * @brief remove a node from the head of a queue + * @param queue queue + * @return the node removed + */ +queue_t* queue_remove_head(queue_t** queue); + +/** + * @brief remove a node from the tail of a queue + * @param queue queue + * @return the node removed + */ +queue_t* queue_remove_tail(queue_t** queue); + +/** + * @brief detach a node from the a queue + * @param queue queue + * @param t the node to be detached + */ +void queue_detach(queue_t** queue, queue_t* t); + +/** get the enclose object of a queue node */ +#define queue_data(queue, type, member) \ + (type*)((char*)queue - offsetof(type, member)) + +/** + * a rbtree node + */ +typedef struct rb_s { + int key; + int color; + struct rb_s* parent; + struct rb_s* left; + struct rb_s* right; +} rb_t; + +/** this color can have childs of any color */ +#define RB_BLACK 0 +/** this color can only have childs of the color mentioned above */ +#define RB_RED 1 + +/** used to represent NULL in rbtrees */ +extern rb_t rb_nil; + +/** + * @brief find a node with key + * @param root rbtree root + * @param key key to find + * @return rb_nil if not found, else the node + */ +rb_t* rb_find(rb_t* root, int key); + +/** + * @brief insert a node to rbtree + * @param root rbtree root + * @param node the node to insert + */ +void rb_insert(rb_t** root, rb_t* node); + +/** + * @brief delete a node from rbtree + * @param root rbtree root + * @param node the node to delete + */ +void rb_delete(rb_t** root, rb_t* node); + +/** + * @brief find the node with minimum key in rbtree + * @param root rbtree root + * @return rb_nil if rbtree is empty, otherwise the node + */ +rb_t* rb_min(rb_t* root); + +/** + * @brief find the node with the samllest key which is greater than node's key + * @param root rbtree root + * @param node the node to compare + * @return rb_nil if no such node exist, otherwise the node + */ +rb_t* rb_next(rb_t* node); + +/** get the enclose object of a rbtree node */ +#define rb_data(rb, type, member) (type*)((char*)rb - offsetof(type, member)) + +/** + * a vector + */ +typedef struct vector_s { + int current; + int size; + int elem_size; + char* array; +} vector_t; + +/** + * @brief initializa a vector + * @param v the vector + * @param elem_size size of element + * @param init_size initial size of vector + * @return -1 on failure, 0 on success + */ +int vector_init(vector_t* v, int elem_size, int init_size); + +/** + * @brief get the size of a vector + * @param v the vector + * @return size + */ +int vector_size(vector_t* v); + +/** + * @brief push an element to the back of v + * @param v vector + * @param elem element + * @return -1 on failure, 0 on success + */ +int vector_push(vector_t* v, void* elem); + +/** + * @brief remove an element from the back of v + * @param v vector + */ +void vector_pop(vector_t* v); + +/** + * @brief remove an element at index index + * @param v vector + * @param index index + */ +void vector_remove(vector_t* v, int index); + +/** + * @brief return a pointer to the element at index in v + * @param v vector + * @param index index + * @return the element + */ +void* vector_at(vector_t* v, int index); + +/** + * @brief free a vector's resource + * @param v vector + */ +void vector_free(vector_t* v); + +/** + * a node in heap + */ +typedef struct heap_node_s { + int key; + void* value; +} heap_node_t; + +/** + * a minimum heap + */ +typedef vector_t heap_t; + +/** + * heap is only used for timer and we choose this size because 8 is a common + * number in computer science and no other size make more sense than this one + */ +#define INITIAL_HEAP_SIZE (8) + +/** + * @brief initializa a heap + * @param heap the heap + * @return -1 on failure, 0 on success + */ +int heap_init(heap_t* heap); + +/** + * @brief insert a node into heap + * @param heap the heap + * @param node the node + * @return -1 on failure, 0 on success + */ +int heap_insert(heap_t* heap, heap_node_t* node); + +/** + * @brief peak the top of a heap + * @param heap the heap + * @return top node of the heap or NULL if heap is empty + */ +heap_node_t* heap_peak(heap_t* heap); + +/** + * @brief remove the top node from heap + * @param heap the heap + */ +void heap_pop(heap_t* heap); + +#endif diff --git a/kern/inc/console.h b/kern/inc/console.h new file mode 100644 index 0000000..a3649de --- /dev/null +++ b/kern/inc/console.h @@ -0,0 +1,162 @@ +/* + * + * # # + * ## # #### ##### # #### ###### + * # # # # # # # # # # + * # # # # # # # # ##### + * # # # # # # # # # + * # ## # # # # # # # + * # # #### # # #### ###### + * + * Now that it's P3 instead of P1 you are allowed + * to edit this file if it suits you. + * + * Please delete this notice. + * + */ + +/** @file console.h + * + * @brief console functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include + +#include + +/** mutex for console operations */ +extern mutex_t console_lock; + +/** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline ('\n'), the cursor is + * be moved to the beginning of the next line (scrolling if necessary). If + * the character is a carriage return ('\r'), the cursor + * is immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce ('\b') is encountered, + * the previous character is erased. See the main console.c description + * for more backspace behavior. + * + * @param ch the character to print + * @return The input character + */ +int putbyte(char ch); + +/** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string fills up the current line and then + * continues on the next line. If the string exceeds + * available space on the entire console, the screen + * scrolls up one line, and then the string + * continues on the new line. If '\n', '\r', and '\b' are + * encountered within the string, they are handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ +void putbytes(const char* s, int len); + +/** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return 0 on success or integer error code less than 0 if + * color code is invalid. + */ +int set_term_color(int color); + +/** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ +void get_term_color(int* color); + +/** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() does not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return 0 on success or integer error code less than 0 if + * cursor location is invalid. + */ +int set_cursor(int row, int col); + +/** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ +void get_cursor(int* row, int* col); + +/** @brief Hides the cursor. + * + * Subsequent calls to putbytes do not cause the + * cursor to show again. + * + * @return Void. + */ +void hide_cursor(void); + +/** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ +void show_cursor(void); + +/** @brief Clears the entire console. + * + * The cursor is reset to the first row and column + * + * @return Void. + */ +void clear_console(void); + +/** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ +void draw_char(int row, int col, int ch, int color); + +/** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ +char get_char(int row, int col); + +#endif /* _CONSOLE_H */ diff --git a/kern/inc/interrupt.h b/kern/inc/interrupt.h new file mode 100644 index 0000000..7c15ccd --- /dev/null +++ b/kern/inc/interrupt.h @@ -0,0 +1,27 @@ +/** @file interrupt.h + * + * @brief idt initializer. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _INTERRUPT_H_ +#define _INTERRUPT_H_ + +/** + * IRQ # of timer + */ +#define TIMER_IRQ 0 + +/** + * IRQ # of keyboard + */ +#define KBD_IRQ 1 + +/** + * @brief initialize idt + */ +void idt_init(); + +#endif diff --git a/kern/inc/kbd.h b/kern/inc/kbd.h new file mode 100644 index 0000000..a7350b6 --- /dev/null +++ b/kern/inc/kbd.h @@ -0,0 +1,30 @@ +/** @file kbd.h + * + * @brief keyboard functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _KBD_H_ +#define _KBD_H_ + +#include +#include +#include + +/** + * @brief read a line to userspace + * @param len max length to read + * @param buf buffer + * @return size on success, -1 on failure + */ +int do_readline(int len, va_t buf); + +/** + * @brief read a char + * @return char read + */ +int do_getchar(); + +#endif diff --git a/kern/inc/loader.h b/kern/inc/loader.h new file mode 100644 index 0000000..504a29a --- /dev/null +++ b/kern/inc/loader.h @@ -0,0 +1,46 @@ +/* The 15-410 kernel project + * + * loader.h + * + * Structure definitions, #defines, and function prototypes + * for the user process loader. + */ + +#ifndef _LOADER_H +#define _LOADER_H + +#include + +/* --- Prototypes --- */ + +/** + * @brief read size bytes from offset of filename to buf + * @param filename filename + * @param offser offset in file + * @param size size to read + * @param buf buffer + * @return returns the number of bytes copied on succes; -1 on failure + */ +int getbytes(const char* filename, int offset, int size, char* buf); + +/** shorter name for file entry */ +typedef const exec2obj_userapp_TOC_entry file_t; + +/** + * @brief read size bytes from offset of f to buf + * @param f file entry + * @param offser offset in file + * @param size size to read + * @param buf buffer + * @return returns the number of bytes copied on succes; -1 on failure + */ +int read_file(file_t* f, int offset, int size, char* buf); + +/** + * @brief find a file entry + * @param filename filename + * @return the file entry, NULL if not found + */ +file_t* find_file(const char* name); + +#endif /* _LOADER_H */ diff --git a/kern/inc/mm.h b/kern/inc/mm.h new file mode 100644 index 0000000..64499d0 --- /dev/null +++ b/kern/inc/mm.h @@ -0,0 +1,55 @@ +/** @file mm.h + * + * @brief memory management functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _MM_H_ +#define _MM_H_ + +#include + +#include +#include + +/** a invalid physical address when managing user memory */ +#define BAD_PA 0 + +/** lock for kernel memory allocation */ +extern mutex_t malloc_lock; + +/** lock for user memory management */ +extern mutex_t mm_lock; + +/** + * @brief initialize user memory system + */ +void mm_init(); + +/** + * @brief allocate physical pages + * @param num_pages number of pages to allocate + * @return physical address of pages, or BAD_PA on failure + */ +pa_t alloc_user_pages(int num_pages); + +/** + * @brief free physical pages + * @param pa physcial address of pages + * @param num_pages number of pages to allocate + */ +void free_user_pages(pa_t pa, int num_pages); + +/** + * @brief map a physical page to kernel memory, the mapping area will be reused + * after subsequent map_phys_page() calls + * @param pa physcial address of the page + * @param old_pa output argument to save old mapped page, can be NULL if no need + * to save + * @return virtual address of mapped page + */ +va_t map_phys_page(pa_t pa, pa_t* old_pa); + +#endif diff --git a/kern/inc/paging.h b/kern/inc/paging.h new file mode 100644 index 0000000..182f50f --- /dev/null +++ b/kern/inc/paging.h @@ -0,0 +1,155 @@ +/** @file paging.h + * + * @brief paging management functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _PAGING_H_ +#define _PAGING_H_ + +#include + +/* SOMEONE SUGGESTED THAT I SHOULD USE UINTPTR_T FOR PORTABILITY BUT I DON'T SEE + * ANY USE OF IT IN ANY PROVIDED CODE AND THIS COURSE HAVE ALREADY SAY WE ARE + * TARGETING X86 ARCHTECTURE SO I JUST USE A 'NON-PORTABLE' INT TYPE */ + +/** an entry in page table */ +typedef unsigned long pte_t; +/** an entry in page directory */ +typedef unsigned long pde_t; + +/** virtual address */ +typedef unsigned long va_t; + +/** physical address */ +typedef unsigned long pa_t; + +/** size of memory */ +typedef unsigned long va_size_t; + +/** a register */ +typedef unsigned int reg_t; + +#ifndef PAGE_OFFSET_MASK +/** mask of page offset bits */ +#define PAGE_OFFSET_MASK (PAGE_SIZE - 1) +#endif + +#ifndef PAGE_BASE_MASK +/** mask of page base bits */ +#define PAGE_BASE_MASK (~PAGE_OFFSET_MASK) +#endif + +/** index of entry in page directory where user memory starts */ +#define USER_PD_START (USER_MEM_START / PAGE_SIZE / NUM_PAGE_ENTRY) + +/** means a page is present */ +#define PTE_PRESENT 1 +/** means a page is writeable */ +#define PTE_RW 1 +/** means a page is not writeable */ +#define PTE_RO 0 +/** means a page can be accessed in ring 3 */ +#define PTE_USER 1 +/** means a page can only be accessed in ring 0 */ +#define PTE_SUPERVISOR 0 +#define PTE_PCD 1 +/** means a page's TLB entry should not be flushed on switching cr3 */ +#define PTE_G 1 + +/** P bit's position */ +#define PTE_P_SHIFT 0 +/** RW/RO bit's position */ +#define PTE_RW_SHIFT 1 +/** USER/SUPERVISOR bit's position */ +#define PTE_US_SHIFT 2 +/** PCD bit's position */ +#define PTE_PCD_SHIFT 4 +/** G bit's position */ +#define PTE_G_SHIFT 8 + +/** an invalid page directory entry */ +#define BAD_PDE ((pde_t)0) +/** an invalid page table entry */ +#define BAD_PTE ((pte_t)0) + +/** + * @brief create a page table entry + * @param base address of the page + * @param g g bit + * @param us user/supervisor bit + * @param rw rw/ro bit + * @param p present bit + * @return the page table entry + */ +static inline pte_t make_pte(pa_t base, int g, int us, int rw, int p) { + return ((base & PAGE_BASE_MASK) | (g << PTE_G_SHIFT) | + (us << PTE_US_SHIFT) | (rw << PTE_RW_SHIFT) | (p << PTE_P_SHIFT)); +} + +/** + * @brief create a page directory entry + * @param base address of the page + * @param us user/supervisor bit + * @param rw rw/ro bit + * @param p present bit + * @return the page directory entry + */ +static inline pde_t make_pde(pa_t base, int us, int rw, int p) { + return ((base & PAGE_BASE_MASK) | (us << PTE_US_SHIFT) | + (rw << PTE_RW_SHIFT) | (p << PTE_P_SHIFT)); +} + +#ifndef NUM_PAGE_ENTRY +/** number of entries in a page table */ +#define NUM_PAGE_ENTRY (PAGE_SIZE / sizeof(pte_t)) +#endif + +/** size of memory a page table can manage */ +#define PT_SIZE (PAGE_SIZE * NUM_PAGE_ENTRY) + +/** page directory type */ +typedef pde_t page_directory_t[PAGE_SIZE / sizeof(pde_t)]; +/** page table type */ +typedef pte_t page_table_t[PAGE_SIZE / sizeof(pde_t)]; + +/** get page table address from a pde */ +static inline pa_t get_page_table(pde_t pde) { + return (pa_t)(pde & PAGE_BASE_MASK); +} + +/** get page base address from a pte */ +static inline pa_t get_page_base(pte_t pte) { + return (pa_t)(pte & PAGE_BASE_MASK); +} + +/** get index in page directory of an address */ +static inline int get_pd_index(va_t va) { + return va / PAGE_SIZE / NUM_PAGE_ENTRY; +} + +/** get index in page table of an address */ +static inline int get_pt_index(va_t va) { + return (va / PAGE_SIZE) % NUM_PAGE_ENTRY; +} + +/** kernel's page directory which directly maps all kernel memory */ +extern page_directory_t* kernel_pd; +/** area for mapping physical pages */ +extern va_t mapped_phys_pages; +/** location of the page table entry of the mapping area */ +extern pte_t* mapped_phys_page_ptes; + +/** + * @brief initialize and enable paging + */ +void paging_init(); + +/** + * @brief enable paging + */ +void paging_enable(); + +#endif diff --git a/kern/inc/sched.h b/kern/inc/sched.h new file mode 100644 index 0000000..335f648 --- /dev/null +++ b/kern/inc/sched.h @@ -0,0 +1,361 @@ +/** @file sched.h + * + * @brief scheduling functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _SCHED_H_ +#define _SCHED_H_ + +#include +#include + +#include +#include + +#include +#include +#include + +/** name of idle process */ +#define IDLE_NAME "idle" +/** name of init process */ +#define INIT_NAME "init" + +/** we use fs to find percpu area */ +#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 +/** index of fs in gdt */ +#define SEGSEL_KERNEL_FS_IDX SEGSEL_SPARE0_IDX + +/** an allocated memory of a process */ +typedef struct region_s { + va_t addr; + va_size_t size; /* size in bytes */ + pa_t paddr; + int is_rw; +} region_t; + +/** + * default size for kernel thread, as long as kernel does not contain recursion + * and do not allocate big local variable, the kernel stack pointer will never + * overflow + */ +#define K_STACK_SIZE PAGE_SIZE + +/** initial eflags, interrupt enabled and IOPL=0 */ +#define DEFAULT_EFLAGS (EFL_IF | EFL_IOPL_RING0 | EFL_RESV1) + +/** frame used for kernel context switching */ +typedef struct yield_frame_s { + reg_t ebp; + reg_t ebx; + reg_t eflags; + reg_t raddr; +} yield_frame_t; + +/** frame used for syscall and interrupts (not faults) */ +typedef struct stack_frame_s { + reg_t gs; + reg_t fs; + reg_t es; + reg_t ds; + reg_t edi; + reg_t esi; + reg_t ebp; + reg_t dummy_esp; /* gap of pusha */ + reg_t ebx; + reg_t edx; + reg_t ecx; + reg_t eax; + reg_t eip; + reg_t cs; + reg_t eflags; + reg_t esp; /* not present if interrupted in kernel mode */ + reg_t ss; /* not present if interrupted in kernel mode */ +} stack_frame_t; + +/** process control block */ +typedef struct process_s { + int pid; + int exit_value; + struct process_s* parent; + queue_t sible_link; /* in parent process' child queue */ + + mutex_t refcount_lock; + int refcount; + queue_t* threads; + + int nchilds; /* live and dead but unclaimed childs */ + queue_t* live_childs; + queue_t* dead_childs; + + int nwaiters; /* number of threads calling wait() */ + mutex_t wait_lock; + cv_t wait_cv; + + pa_t cr3; + vector_t regions; /* record the vitural memories the user has mapped */ + mutex_t mm_lock; /* lock when operating VM */ +} process_t; + +/** status of the thread, must lock ready_lock to change it, otherwise may be + * changed back to READY by timer interrupt */ +typedef enum thr_stat_e { + THREAD_RUNNING, + THREAD_READY, + THREAD_BLOCKED, /* blocked on a mutex/cv */ + THREAD_SLEEPING, + THREAD_DESCHEDULED, + THREAD_DEAD +} thr_stat_t; + +/** thread control block */ +typedef struct thread_s { + rb_t rb_node; /* rbtree node, key is tid */ + thr_stat_t status; + spl_t status_lock; + queue_t sched_link; /* in ready queue or other queue */ + int pending_exit; /* if a task_vanish is pending */ + + queue_t process_link; /* in process_t's threads queue */ + + process_t* process; + + reg_t esp3; + reg_t eip3; + reg_t swexn_arg; + int df3; /* is a fault is currently being handled by swexn handler */ + + reg_t esp0; /* esp to use when switching from ring3 to ring0 + (fault/interrupt) */ + reg_t eip0; /* handler for faults happen in ring0 */ + + reg_t kernel_esp; /* saved kernel esp when swapped out */ + char* stack; /* kernel stack */ +} thread_t; + +/** + * @brief get next available tid + * @return tid + */ +int alloc_tid(); + +/** initial stack size for user program, 16 pages is a middle size that do not + * waste too much and big enough for arguments */ +#define DEFAULT_STACK_SIZE (65536) +/** initial stack end for user program, skip the last page as it would cause + * round bugs */ +#define DEFAULT_STACK_END (0xffffe000) +/** inital stack area start */ +#define DEFAULT_STACK_POS (DEFAULT_STACK_END - DEFAULT_STACK_SIZE) + +/** maximum arg length for exec(), a middle size */ +#define MAX_ARG_LEN 4096 +/** maximum number of args for exec(), a middle size */ +#define MAX_NUM_ARG 256 +/** maximum total arg length for exec(), save last page for argc, argv, stack_hi + * and stack_lo */ +#define MAX_TOTAL_ARG_LEN (DEFAULT_STACK_SIZE - PAGE_SIZE) + +/** + * @brief create an empty process with one thread and no user memory + * @return the thread created or NULL on failure + */ +thread_t* create_empty_process(); + +/** + * @brief create a process and load the executable and push the arguments + * @param tid tid to use, or 0 if we want to allocate a new one + * @param exec name of executable to load + * @param argc number of arguments + * @param argv array of arguments + * @return the thread created or NULL on failure + */ +thread_t* create_process(int tid, char* exe, int argc, const char** argv); + +/** + * @brief destroy a thread which is never run + * @param t the thread to destroy + */ +void destroy_thread(thread_t* t); + +/** + * @brief add a memory region to a process + * @param p the process + * @param addr virtual address + * @param n_pages number of pages in this region + * @param pa physical address + * @param is_rw is this region writeable + * @return 0 for success, -1 for failure + */ +int add_region(process_t* p, va_t vaddr, int n_pages, pa_t pa, int is_rw); + +/** + * @brief find the page table for addr, or allocate one if not present + * @param p the process + * @param addr virtual address + * @return physical address of page table or BAD_PA on failure + */ +pa_t find_or_create_pt(process_t* p, va_t vaddr); + +/** CPU specific varibles */ +typedef struct percpu_s { + thread_t* current; /* current running thread */ + thread_t* idle; /* idle thread */ + thread_t* kthread; /* original kernel thread */ + va_t mapped_phys_page; /* physical page mapping area */ + pte_t* mapped_phys_page_pte; /* pte for the mapping area */ +} percpu_t; + +/** + * @brief initialize fs segment's base to percpu structure + * @param percpu address of percpu structure + */ +void setup_percpu(percpu_t* percpu); + +/** + * @brief setup the kernel thread's control structure, which needed when + * switching to othre processes when startup + * @param kthread kernel thread's thread control structure + * @param kprocess kernel thread's process control structure + */ +void setup_kth(thread_t* kthread, process_t* kprocess); + +/** + * @brief get current running thread + * @return current running thread + */ +thread_t* get_current(); +/** + * @brief set current running thread + * @param t current running thread + */ +void set_current(thread_t* t); +/** + * @brief get idle thread + * @return idle thread + */ +thread_t* get_idle(); +/** + * @brief set idle thread + * @param t idle thread + */ +void set_idle(thread_t* t); +/** + * @brief get kernel thread + * @return kernel thread + */ +thread_t* get_kthread(); +/** + * @brief set kernel thread + * @param t kernel thread + */ +void set_kthread(thread_t* t); +/** + * @brief get physical page mapping area + * @return physical page mapping area + */ +va_t get_mapped_phys_page(); +/** + * @brief set physical page mapping area + * @param va physical page mapping area + */ +void set_mapped_phys_page(va_t va); +/** + * @brief get pte for physical page mapping area + * @return pte for physical page mapping area + */ +pte_t* get_mapped_phys_page_pte(); +/** + * @brief set pte for physical page mapping area + * @param pte pte for physical page mapping area + */ +void set_mapped_phys_page_pte(pte_t* pte); + +/** + * @brief swap current thread's process and newt's process, newt must be a new + * thread with new process, current thread must be the only thread in a process + * @param newt thread to swap + */ +void swap_process_inplace(thread_t* newt); + +/** init process */ +extern process_t* init_process; + +/** lock for ready queue */ +extern spl_t ready_lock; +/** queue of ready threads */ +extern queue_t* ready; + +/** rbtree of all threads */ +extern rb_t* threads; +/** mutex for rbtree */ +extern mutex_t threads_lock; + +/** + * @brief insert a thread to the tail of ready queue, must lock ready_lock + * before calling this function + * @param t thread to insert + */ +void insert_ready_tail(thread_t* t); + +/** + * @brief insert a thread to the head of ready queue, must lock ready_lock + * before calling this function + * @param t thread to insert + */ +void insert_ready_head(thread_t* t); + +/** + * @brief select next ready thread + * @return the thread + */ +thread_t* select_next(); + +/** + * @brief save current esp, load t's cr3, esp0 and return t's esp, must disable + * interrupt before calling + * @param t thread to load + * @param esp current esp + * @return new esp + */ +reg_t save_and_setup_env(thread_t* t, reg_t esp); + +/** + * @brief let current thread vanish + */ +void kill_current(); + +/** + * @brief switch to another stack and cleanup t's thread control block and stack + */ +void switch_stack_cleanup(reg_t esp, thread_t* t); + +/** + * @brief check pending exit request and pop saved user registers and return to + * ring 3 + */ +void return_to_user(); + +/** + * @brief find a thread from rbtree, must lock threads_lock before calling + * @param tid tid of thread + * @return the thread or NULL if not found + */ +thread_t* find_thread(int tid); + +/** + * @brief add a thread to rbtree, will automatically lock threads_lock + * @param t thread to add + */ +void add_thread(thread_t* t); + +/** + * @brief remove a thread from rbtree, will automatically lock threads_lock + * @param t thread to remove + */ +void remove_thread(thread_t* t); + +#endif diff --git a/kern/inc/sync.h b/kern/inc/sync.h new file mode 100644 index 0000000..9bc53c8 --- /dev/null +++ b/kern/inc/sync.h @@ -0,0 +1,102 @@ +/** @file sync.h + * + * @brief locks. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _SYNC_H_ +#define _SYNC_H_ + +#include + +/** declaration of thread control block */ +struct thread_s; +/** declaration of thread control block */ +typedef struct thread_s thread_t; + +/** + * @brief save eflags and disable interrupt + * @return eflags + */ +int save_clear_if(); +/** + * @brief restore eflags + * @param old_if eflags + */ +void restore_if(int old_if); + +/** spinlock structure, only needed for SMP */ +typedef struct spl_s { + int locked; +} spl_t; + +/** initial value for spinlock */ +#define SPL_INIT (spl_t){.locked = 0}; + +/** + * @brief lock the spinlock and disable interrupts + * @return original eflags + */ +int spl_lock(spl_t* spl); +/** + * @brief unlock the spinlock and restore eflags + * @param old_if eflags + */ +void spl_unlock(spl_t* spl, int old_if); + +/** + * @brief atomically yield to another thread and unlock the spinlock, eflags + * will be restored when current thread become running again + * @param t thread to yield to + * @param spl spinlock + * @param old_if eflags + */ +void yield_to_spl_unlock(thread_t* t, spl_t* spl, int old_if); + +/** mutex structure */ +typedef struct mutex_s { + spl_t guard; + int locked; + queue_t* waiters; +} mutex_t; + +/** initial value for mutex */ +#define MUTEX_INIT \ + (mutex_t){.guard = {.locked = 0}, .locked = 0, .waiters = NULL}; + +/** + * @brief lock the mutex, will be blocked if lock is held by other thread + * @param m mutex + */ +void mutex_lock(mutex_t* m); +/** + * @brief unlock the mutex, will wake up one blocked thread if there is one + * @param m mutex + */ +void mutex_unlock(mutex_t* m); + +/** cv structure */ +typedef struct cv_s { + spl_t guard; + queue_t* waiters; +} cv_t; + +/** initial value for cv */ +#define CV_INIT \ + (cv_t) { .guard = {.locked = 0}, .waiters = NULL } + +/** + * @brief unlock the mutex m and wait for other threads to call cv_signal on cv + * @param cv cv + * @param m mutex + */ +void cv_wait(cv_t* cv, mutex_t* m); +/** + * @brief signal a cv, will wake up one blocked thread if there is one + * @param cv cv + */ +void cv_signal(cv_t* cv); + +#endif diff --git a/kern/inc/timer.h b/kern/inc/timer.h new file mode 100644 index 0000000..8d6368e --- /dev/null +++ b/kern/inc/timer.h @@ -0,0 +1,24 @@ +/** @file timer.h + * + * @brief timer functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +/** ticks passed */ +extern unsigned int ticks; +/** timer heap lock */ +extern spl_t timer_lock; +/** timers of sleeping threads */ +extern heap_t timers; + +/** + * @brief initialize the timer + */ +void timer_init(); + +#endif diff --git a/kern/inc/usermem.h b/kern/inc/usermem.h new file mode 100644 index 0000000..c5622e8 --- /dev/null +++ b/kern/inc/usermem.h @@ -0,0 +1,50 @@ +/** @file usermem.h + * + * @brief userspace r/w functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#ifndef _USERMEM_H_ +#define _USERMEM_H_ + +#include + +#include + +#include + +/** + * @brief copy bytes from userspace + * @param addr address of user memory + * @param size number of bytes + * @param buf buffer + * @return 0 on success, -1 on failure + */ +int copy_from_user(va_t addr, int size, void* buf); +/** + * @brief copy bytes to userspace + * @param addr address of user memory + * @param size number of bytes + * @param buf buffer + * @return 0 on success, -1 on failure + */ +int copy_to_user(va_t addr, int size, void* buf); + +/** + * @brief try to copy a string from userspace + * @param addr address of user memory + * @param maxlen maximum length of the string including the null byte + * @return NULL on failure, a string allocated by malloc() on success + */ +char* copy_string_from_user(va_t addr, int maxlen); +/** + * @brief try to print a buffer from userspace + * @param addr address of user memory + * @param maxlen maximum length of to print + * @return 0 on success, -1 on failure + */ +int print_buf_from_user(va_t addr, int maxlen); + +#endif diff --git a/kern/interrupt.c b/kern/interrupt.c new file mode 100644 index 0000000..ad48e5f --- /dev/null +++ b/kern/interrupt.c @@ -0,0 +1,502 @@ +/** @file interrupt.c + * + * @brief idt initializer and fault/interrupt handlers. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** means this entry requires ring 0 privilige */ +#define IDT_DPL_KERNEL 0 +/** means this entry requires ring 3 privilige */ +#define IDT_DPL_USER 3 +/** means this entry is valid */ +#define IDT_P 1 +/** means this entry is a 32 bit interrupt */ +#define IDT_TYPE_I32 0xe +/** means this entry is a 32 bit trap */ +#define IDT_TYPE_T32 0xf + +/** P bit's position */ +#define IDT_P_SHIFT (47 - 32) +/** DPL's position */ +#define IDT_DPL_SHIFT (45 - 32) +/** TYPE's position */ +#define IDT_TYPE_SHIFT (40 - 32) +/** CS's position */ +#define IDT_CS_SHIFT 16 + +/** EIP's high part's bits */ +#define IDT_EIP_HI_MASK 0xffff0000 +/** EIP's low part's bits */ +#define IDT_EIP_LO_MASK 0x0000ffff + +/** + * @brief an idt entry + */ +typedef struct idt_s { + unsigned long lo; + unsigned long hi; +} idt_t; + +/** + * @brief create an idt entry + * @param eip eip + * @param type type + * @param dpl dpl + * @return the idt entry + */ +static inline idt_t make_idt(va_t eip, int type, int dpl) { + idt_t idt; + idt.hi = ((eip & IDT_EIP_HI_MASK) | (IDT_P << IDT_P_SHIFT) | + (dpl << IDT_DPL_SHIFT) | (type << IDT_TYPE_SHIFT)); + idt.lo = ((SEGSEL_KERNEL_CS << IDT_CS_SHIFT) | (eip & IDT_EIP_LO_MASK)); + return idt; +} + +/** + * @brief DE handler entry + */ +int de_handler(); +/** + * @brief DB handler entry + */ +int db_handler(); +/** + * @brief NMI handler entry + */ +int nmi_handler(); +/** + * @brief BP handler entry + */ +int bp_handler(); +/** + * @brief OF handler entry + */ +int of_handler(); +/** + * @brief BR handler entry + */ +int br_handler(); +/** + * @brief UD handler entry + */ +int ud_handler(); +/** + * @brief NM handler entry + */ +int nm_handler(); +/** + * @brief DF handler entry + */ +int df_handler(); +/** + * @brief CSO handler entry + */ +int cso_handler(); +/** + * @brief TS handler entry + */ +int ts_handler(); +/** + * @brief NP handler entry + */ +int np_handler(); +/** + * @brief SS handler entry + */ +int ss_handler(); +/** + * @brief GP handler entry + */ +int gp_handler(); +/** + * @brief PF handler entry + */ +int pf_handler(); +/** + * @brief MF handler entry + */ +int mf_handler(); +/** + * @brief AC handler entry + */ +int ac_handler(); +/** + * @brief MC handler entry + */ +int mc_handler(); +/** + * @brief XF handler entry + */ +int xf_handler(); + +/** + * @brief default handler entry + */ +int default_handler(); + +/** + * @brief timer handler entry + */ +void timer_handler(); +/** + * @brief keyboard handler entry + */ +void kbd_handler(); + +/** + * @brief fork() syscall entry + */ +void sys_fork(); +/** + * @brief exec() syscall entry + */ +void sys_exec(); +/** + * @brief wait() syscall entry + */ +void sys_wait(); +/** + * @brief yield() syscall entry + */ +void sys_yield(); +/** + * @brief deschedule() syscall entry + */ +void sys_deschedule(); +/** + * @brief make_runnable() syscall entry + */ +void sys_make_runnable(); +/** + * @brief gettid() syscall entry + */ +void sys_gettid(); +/** + * @brief new_pages() syscall entry + */ +void sys_new_pages(); +/** + * @brief remove_pages() syscall entry + */ +void sys_remove_pages(); +/** + * @brief sleep() syscall entry + */ +void sys_sleep(); +/** + * @brief getchar() syscall entry + */ +void sys_getchar(); +/** + * @brief readline() syscall entry + */ +void sys_readline(); +/** + * @brief print() syscall entry + */ +void sys_print(); +/** + * @brief set_term_color() syscall entry + */ +void sys_set_term_color(); +/** + * @brief set_cursor_pos() syscall entry + */ +void sys_set_cursor_pos(); +/** + * @brief get_cursor() syscall entry + */ +void sys_get_cursor_pos(); +/** + * @brief thread() syscall entry + */ +void sys_thread_fork(); +/** + * @brief get_ticks() syscall entry + */ +void sys_get_ticks(); +/** + * @brief misbehave() syscall entry + */ +void sys_misbehave(); +/** + * @brief halt() syscall entry + */ +void sys_halt(); +/** + * @brief task_vanish() syscall entry + */ +void sys_task_vanish(); +/** + * @brief set_status() syscall entry + */ +void sys_set_status(); +/** + * @brief vanish() syscall entry + */ +void sys_vanish(); +/** + * @brief readfile() syscall entry + */ +void sys_readfile(); +/** + * @brief swexn() syscall entry + */ +void sys_swexn(); + +/** + * @brief all other syscall entries + */ +void sys_enosys(); + +/** index of first syscall */ +#define IDT_SYSCALL_START (X86_PIC_MASTER_IRQ_BASE + 16) + +void idt_init() { + idt_t* idt = (idt_t*)idt_base(); + + int i; + for (i = 0; i < IDT_SYSCALL_START; i++) { + idt[i] = make_idt((va_t)default_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + } + + idt[IDT_DE] = make_idt((va_t)de_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_DB] = make_idt((va_t)db_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_NMI] = make_idt((va_t)nmi_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_BP] = make_idt((va_t)bp_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_OF] = make_idt((va_t)of_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_BR] = make_idt((va_t)br_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_UD] = make_idt((va_t)ud_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_NM] = make_idt((va_t)nm_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_DF] = make_idt((va_t)df_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_CSO] = make_idt((va_t)cso_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_TS] = make_idt((va_t)ts_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_NP] = make_idt((va_t)np_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_SS] = make_idt((va_t)ss_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_GP] = make_idt((va_t)gp_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_PF] = make_idt((va_t)pf_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_MF] = make_idt((va_t)mf_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_AC] = make_idt((va_t)ac_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_MC] = make_idt((va_t)mc_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[IDT_XF] = make_idt((va_t)xf_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + + idt[TIMER_IDT_ENTRY] = + make_idt((va_t)timer_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[KEY_IDT_ENTRY] = + make_idt((va_t)kbd_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + + for (i = IDT_SYSCALL_START; i < IDT_ENTS; i++) { + idt[i] = make_idt((va_t)sys_enosys, IDT_TYPE_T32, IDT_DPL_USER); + } + + idt[FORK_INT] = make_idt((va_t)sys_fork, IDT_TYPE_T32, IDT_DPL_USER); + idt[EXEC_INT] = make_idt((va_t)sys_exec, IDT_TYPE_T32, IDT_DPL_USER); + idt[WAIT_INT] = make_idt((va_t)sys_wait, IDT_TYPE_T32, IDT_DPL_USER); + idt[YIELD_INT] = make_idt((va_t)sys_yield, IDT_TYPE_T32, IDT_DPL_USER); + idt[DESCHEDULE_INT] = + make_idt((va_t)sys_deschedule, IDT_TYPE_T32, IDT_DPL_USER); + idt[MAKE_RUNNABLE_INT] = + make_idt((va_t)sys_make_runnable, IDT_TYPE_T32, IDT_DPL_USER); + idt[GETTID_INT] = make_idt((va_t)sys_gettid, IDT_TYPE_T32, IDT_DPL_USER); + idt[NEW_PAGES_INT] = + make_idt((va_t)sys_new_pages, IDT_TYPE_T32, IDT_DPL_USER); + idt[REMOVE_PAGES_INT] = + make_idt((va_t)sys_remove_pages, IDT_TYPE_T32, IDT_DPL_USER); + idt[SLEEP_INT] = make_idt((va_t)sys_sleep, IDT_TYPE_T32, IDT_DPL_USER); + idt[GETCHAR_INT] = make_idt((va_t)sys_getchar, IDT_TYPE_T32, IDT_DPL_USER); + idt[READLINE_INT] = + make_idt((va_t)sys_readline, IDT_TYPE_T32, IDT_DPL_USER); + idt[PRINT_INT] = make_idt((va_t)sys_print, IDT_TYPE_T32, IDT_DPL_USER); + idt[SET_TERM_COLOR_INT] = + make_idt((va_t)sys_set_term_color, IDT_TYPE_T32, IDT_DPL_USER); + idt[SET_CURSOR_POS_INT] = + make_idt((va_t)sys_set_cursor_pos, IDT_TYPE_T32, IDT_DPL_USER); + idt[GET_CURSOR_POS_INT] = + make_idt((va_t)sys_get_cursor_pos, IDT_TYPE_T32, IDT_DPL_USER); + idt[THREAD_FORK_INT] = + make_idt((va_t)sys_thread_fork, IDT_TYPE_T32, IDT_DPL_USER); + idt[GET_TICKS_INT] = + make_idt((va_t)sys_get_ticks, IDT_TYPE_T32, IDT_DPL_USER); + idt[MISBEHAVE_INT] = + make_idt((va_t)sys_misbehave, IDT_TYPE_T32, IDT_DPL_USER); + idt[HALT_INT] = make_idt((va_t)sys_halt, IDT_TYPE_T32, IDT_DPL_USER); + idt[TASK_VANISH_INT] = + make_idt((va_t)sys_task_vanish, IDT_TYPE_T32, IDT_DPL_USER); + idt[SET_STATUS_INT] = + make_idt((va_t)sys_set_status, IDT_TYPE_T32, IDT_DPL_USER); + idt[VANISH_INT] = make_idt((va_t)sys_vanish, IDT_TYPE_T32, IDT_DPL_USER); + idt[READFILE_INT] = + make_idt((va_t)sys_readfile, IDT_TYPE_T32, IDT_DPL_USER); + idt[SWEXN_INT] = make_idt((va_t)sys_swexn, IDT_TYPE_T32, IDT_DPL_USER); +} + +/** string explanation of fault */ +const static char* reasons[] = {"Division Error", + "Debug", + "Non-maskable Interrupt", + "Breakpoint", + "Overflow", + "Bound Range Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Exception", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved"}; + +/** + * @brief dump register information + * @param frame ureg registers + */ +static void dump_fault(ureg_t* frame); + +/** + * @brief handle a fault + * @param frame ureg registers + */ +void handle_fault(ureg_t* frame) { + thread_t* current = get_current(); + if (frame->cause == SWEXN_CAUSE_PAGEFAULT && frame->cr2 >= USER_MEM_START) { + /* check ZFOD */ + pa_t old_pa; + page_directory_t* pd = + (page_directory_t*)map_phys_page(current->process->cr3, &old_pa); + pde_t* pde = &(*pd)[get_pd_index(frame->cr2)]; + if (*pde != BAD_PDE) { + pa_t pt_pa = get_page_table(*pde); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + pte_t* pte = &(*pt)[get_pt_index(frame->cr2)]; + if (*pte != BAD_PTE && + ((*pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0)) { + *pte = (*pte | (PTE_PRESENT << PTE_P_SHIFT)); + invlpg(frame->cr2); + memset((void*)(frame->cr2 & PAGE_BASE_MASK), 0, PAGE_SIZE); + map_phys_page(old_pa, NULL); + return; + } + } + map_phys_page(old_pa, NULL); + } + if (frame->cs == SEGSEL_KERNEL_CS) { + /* recover from accessing user memory */ + if ((frame->cause == SWEXN_CAUSE_PAGEFAULT || + frame->cause == SWEXN_CAUSE_PROTFAULT) && + current->eip0 != 0) { + frame->eip = current->eip0; + return; + } + /* all other non recoverable fault */ + dump_fault(frame); + while (1) { + } + } + /* send to user swexn */ + if (current->eip3 != 0 && current->df3 == 0) { + va_t esp3 = (va_t)current->esp3; + esp3 -= sizeof(ureg_t); + esp3 = (esp3 & (~(sizeof(va_t) - 1))); + /* push ureg */ + if (copy_to_user(esp3, sizeof(ureg_t), frame) != 0) { + goto kill_thread; + } + /* push swexn args (return address, swexn arg, ureg) + * swexn handler must call swexn to jump back, we use 0 address to cause + * a GP on function return + */ + unsigned long stack[3] = {0, current->swexn_arg, (unsigned long)esp3}; + unsigned long* new_esp = (unsigned long*)esp3; + new_esp -= 3; + if (copy_to_user((va_t)new_esp, 3 * sizeof(unsigned long), stack) != + 0) { + goto kill_thread; + } + frame->edi = 0; + frame->esi = 0; + frame->ebp = 0; + frame->zero = 0; + frame->ebx = 0; + frame->edx = 0; + frame->ecx = 0; + frame->eax = 0; + frame->eip = current->eip3; + frame->eflags = DEFAULT_EFLAGS; + frame->esp = (unsigned int)new_esp; + current->df3 = 1; + current->eip3 = 0; + return; + } + /* no swexn handler or fault inside swexn */ +kill_thread: + sim_printf("LWP %d killed: %s", current->rb_node.key, + reasons[frame->cause]); + printf("LWP %d killed: %s\n", current->rb_node.key, reasons[frame->cause]); + if (current->process->refcount == 1) { + current->process->exit_value = -2; + } + kill_current(); +} + +static void dump_fault(ureg_t* frame) { + sim_printf("Fault: %s Error Code: %08x", reasons[frame->cause], + frame->error_code); + sim_printf("CS:EIP=%04x:%08x EFLAGS=%08x", frame->cs, frame->eip, + frame->eflags); + sim_printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x", frame->eax, frame->ebx, + frame->ecx, frame->edx); + sim_printf("ESI=%08x EDI=%08x ESP=%08x EBP=%08x", frame->esi, frame->edi, + frame->esp, frame->ebp); + printf("=========================\n"); + printf("Fault: %s Error Code: %08x\n", reasons[frame->cause], + frame->error_code); + printf("CS:EIP=%04x:%08x EFLAGS=%08x\n", frame->cs, frame->eip, + frame->eflags); + printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", frame->eax, frame->ebx, + frame->ecx, frame->edx); + printf("ESI=%08x EDI=%08x ESP=%08x EBP=%08x\n", frame->esi, frame->edi, + frame->esp, frame->ebp); +} diff --git a/kern/interrupt_asm.S b/kern/interrupt_asm.S new file mode 100644 index 0000000..99176e4 --- /dev/null +++ b/kern/interrupt_asm.S @@ -0,0 +1,134 @@ +/** @file interrupt_asm.S + * + * @brief fault and interrupt handlers. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include + +#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 + +.global default_handler +default_handler: + iret + +.macro FAULT_HANDLER_ERR name cause +.global \name\()_handler +.type \name\()_handler, %function +\name\()_handler: + pusha /* save a ureg_t structure */ + push %gs + push %fs + push %es + push %ds + mov %cr2, %eax + push %eax + push $\cause + mov $SEGSEL_KERNEL_DS, %eax + mov %ax, %ds + mov %ax, %es + mov $SEGSEL_KERNEL_FS, %eax + mov %ax, %fs + cld + push %esp + call handle_fault + add $0xc, %esp /* skip cr2, cause and argument */ + pop %ds + pop %es + pop %fs + pop %gs + popa + add $0x4, %esp /* skip error code */ + iret +.endm + +.macro FAULT_HANDLER_NOERR name cause +.global \name\()_handler +.type \name\()_handler, %function +\name\()_handler: + sub $0x4, %esp /* dummy error code */ + pusha + push %gs + push %fs + push %es + push %ds + mov %cr2, %eax + push %eax + push $\cause + mov $SEGSEL_KERNEL_DS, %eax + mov %ax, %ds + mov %ax, %es + mov $SEGSEL_KERNEL_FS, %eax + mov %ax, %fs + cld + push %esp + call handle_fault + add $0xc, %esp /* skip cr2, cause and argument */ + pop %ds + pop %es + pop %fs + pop %gs + popa + add $0x4, %esp /* skip error code */ + iret +.endm + +FAULT_HANDLER_NOERR de 0x0 +FAULT_HANDLER_NOERR db 0x1 +FAULT_HANDLER_NOERR nmi 0x2 +FAULT_HANDLER_NOERR bp 0x3 +FAULT_HANDLER_NOERR of 0x4 +FAULT_HANDLER_NOERR br 0x5 +FAULT_HANDLER_NOERR ud 0x6 +FAULT_HANDLER_NOERR nm 0x7 +FAULT_HANDLER_ERR df 0x8 +FAULT_HANDLER_NOERR cso 0x9 +FAULT_HANDLER_ERR ts 0xa +FAULT_HANDLER_ERR np 0xb +FAULT_HANDLER_ERR ss 0xc +FAULT_HANDLER_ERR gp 0xd +FAULT_HANDLER_ERR pf 0xe +FAULT_HANDLER_NOERR mf 0x10 +FAULT_HANDLER_ERR ac 0x11 +FAULT_HANDLER_NOERR mc 0x12 +FAULT_HANDLER_NOERR xf 0x13 + +#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 + +.global timer_handler +.type timer_handler, %function +timer_handler: + pusha /* save a stack_frame_t structure */ + push %ds + push %es + push %fs + push %gs + mov $SEGSEL_KERNEL_DS, %eax + mov %ax, %ds + mov %ax, %es + mov $SEGSEL_KERNEL_FS, %eax + mov %ax, %fs + cld + call timer_handler_real + jmp return_to_user /* check pending exit before iret */ + + +.global kbd_handler +.type kbd_handler, %function +kbd_handler: + pusha /* save a stack_frame_t structure */ + push %ds + push %es + push %fs + push %gs + mov $SEGSEL_KERNEL_DS, %eax + mov %ax, %ds + mov %ax, %es + mov $SEGSEL_KERNEL_FS, %eax + mov %ax, %fs + cld + call kbd_handler_real + jmp return_to_user /* check pending exit before iret */ diff --git a/kern/kbd.c b/kern/kbd.c new file mode 100644 index 0000000..5ba1bcb --- /dev/null +++ b/kern/kbd.c @@ -0,0 +1,218 @@ +/** @file kbd.c + * + * @brief Keyboard handler implementation. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** a node in queue of threads requesting keyboard access */ +typedef struct kbd_request_s { + thread_t* t; + queue_t node; +} kbd_request_t; + +/** size of scancode ring buffer, a big buffer enough for someone pressing + * keyboard fast */ +#define SC_RING_SIZE PAGE_SIZE +/** size of character ring buffer, a big buffer enough for someone pressing + * keyboard fast */ +#define CHR_RING_SIZE PAGE_SIZE +/** maximum readline size */ +#define MAX_READLINE (CHR_RING_SIZE - 1) + +/** queue of threads requesting keyboard access */ +static queue_t* inputs = NULL; + +/** mutex for keyboard request queue */ +static mutex_t kbd_request_lock = MUTEX_INIT; +/** signal for a thread leaving request queue */ +static cv_t kbd_request_cv = CV_INIT; + +/** mutex for new scancode input */ +static mutex_t input_lock = MUTEX_INIT; +/** signal for new scancode input */ +static cv_t input_cv = CV_INIT; +/** need pic acknowlege */ +static int need_ack = 0; + +/** scancode ring buffer */ +static unsigned char sc_ring[SC_RING_SIZE]; +/** read pointer of scancode ring buffer */ +static int sc_r_pos = 0; +/** write pointer of scancode ring buffer */ +static int sc_w_pos = 0; + +/** character ring buffer */ +static char chr_ring[CHR_RING_SIZE]; +/** read pointer of character ring buffer */ +static int chr_r_pos = 0; +/** write pointer of character ring buffer */ +static int chr_w_pos = 0; + +/** + * @brief keyboard inturrupt handler + */ +void kbd_handler_real() { + unsigned char sc = inb(KEYBOARD_PORT); + int next_w_pos = (sc_w_pos + 1) % SC_RING_SIZE; + if (next_w_pos != sc_r_pos) { + sc_ring[sc_w_pos] = sc; + sc_w_pos = next_w_pos; + pic_acknowledge(KBD_IRQ); + } else { + /* let processing thread ack after processing scancode */ + need_ack = 1; + } + cv_signal(&input_cv); +} + +/** + * @brief process scancode until a char is produced + * @return char produced + */ +static int sc_process(); + +/** + * @brief flush a line to user buffer + * @param len length of buffer + * @param buf buffer + * @return size of chars flushed, -1: buf invalid + */ +static int flush_line(int len, va_t buf); + +int do_readline(int len, va_t buf) { + if (len < 0 || len > MAX_READLINE) { + return -1; + } + if (len == 0) { + return 0; + } + kbd_request_t req; + req.t = get_current(); + /* wait until our turn */ + mutex_lock(&kbd_request_lock); + queue_insert_tail(&inputs, &req.node); + while (inputs != &req.node) { + cv_wait(&kbd_request_cv, &kbd_request_lock); + } + mutex_unlock(&kbd_request_lock); + int should_flush = 0; + if (chr_r_pos != chr_w_pos) { + int i; + for (i = chr_r_pos; i != chr_w_pos; i = (i + 1) % CHR_RING_SIZE) { + if (chr_ring[i] == '\n') { + should_flush = 1; + break; + } + } + /* check if ring is full */ + if (chr_r_pos == (chr_w_pos + 1) % CHR_RING_SIZE) { + should_flush = 1; + } + } + while (should_flush == 0) { + /* wait for more chars */ + char c = sc_process(); + if (c == '\b') { + if (chr_w_pos != chr_r_pos) { + putbyte(c); + chr_w_pos = (chr_w_pos + CHR_RING_SIZE - 1) % CHR_RING_SIZE; + } + } else { + chr_ring[chr_w_pos] = c; + chr_w_pos = (chr_w_pos + 1) % CHR_RING_SIZE; + putbyte(c); + should_flush = + (c == '\n') || (chr_r_pos == (chr_w_pos + 1) % CHR_RING_SIZE); + } + } + int result = flush_line(len, buf); + mutex_lock(&kbd_request_lock); + queue_detach(&inputs, &req.node); + cv_signal(&kbd_request_cv); + mutex_unlock(&kbd_request_lock); + return result; +} + +int do_getchar() { + kbd_request_t req; + req.t = get_current(); + mutex_lock(&kbd_request_lock); + queue_insert_tail(&inputs, &req.node); + while (inputs != &req.node) { + cv_wait(&kbd_request_cv, &kbd_request_lock); + } + mutex_unlock(&kbd_request_lock); + int result; + if (chr_r_pos != chr_w_pos) { + result = chr_ring[chr_r_pos]; + chr_r_pos = (chr_r_pos + 1) % CHR_RING_SIZE; + } else { + result = sc_process(); + } + mutex_lock(&kbd_request_lock); + queue_detach(&inputs, &req.node); + cv_signal(&kbd_request_cv); + mutex_unlock(&kbd_request_lock); + return result; +} + +static int flush_line(int len, va_t buf) { + int size = 0, i; + for (i = chr_r_pos; i != chr_w_pos; i = (i + 1) % CHR_RING_SIZE) { + size++; + if (chr_ring[i] == '\n') { + break; + } + } + if (size > len) { + size = len; + } + for (i = 0; i < size; i++) { + if (copy_to_user(buf + i, 1, + &chr_ring[(chr_r_pos + i) % CHR_RING_SIZE]) != 0) { + /* failed to flush, do not discard anything */ + return -1; + } + } + chr_r_pos = (chr_r_pos + i) % CHR_RING_SIZE; + return size; +} + +static int sc_process() { + while (1) { + /* wait for more scancode */ + mutex_lock(&input_lock); + while (sc_r_pos == sc_w_pos) { + cv_wait(&input_cv, &input_lock); + } + int sc = sc_ring[sc_r_pos]; + sc_r_pos = (sc_r_pos + 1) % SC_RING_SIZE; + mutex_unlock(&input_lock); + if (need_ack == 1) { + need_ack = 0; + pic_acknowledge(KBD_IRQ); + } + kh_type kh = process_scancode(sc); + if (KH_HASDATA(kh) && KH_ISMAKE(kh)) { + return KH_GETCHAR(kh); + } + } +} diff --git a/kern/kernel.c b/kern/kernel.c new file mode 100644 index 0000000..e473022 --- /dev/null +++ b/kern/kernel.c @@ -0,0 +1,109 @@ +/** @file kernel.c + * + * @brief kernel entry. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include + +/* libc includes. */ +#include /* lprintf() */ +#include +#include + +/* multiboot header file */ +#include +#include /* boot_info */ +#include + +/* x86 specific includes */ +#include /* enable_interrupts() */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief entry for a cpu core + * @param cpuid cpuid + */ +static void kernel_smp_entry(int cpuid); + +/** + * @brief main function for a cpu core + */ +static void kernel_smp_main(); + +/** @brief Kernel entrypoint. + * + * This is the entrypoint for the kernel. + * + * @return Does not return + */ +int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) { + int smp_good = (smp_init(mbinfo) == 0); + paging_init(); + percpu_t percpu; + setup_percpu(&percpu); + thread_t kthread; + process_t kprocess; + setup_kth(&kthread, &kprocess); + set_mapped_phys_page(mapped_phys_pages); + set_mapped_phys_page_pte(mapped_phys_page_ptes); + + idt_init(); + mm_init(); + timer_init(); + clear_console(); + + const char* init_args[] = {INIT_NAME}; + thread_t* init = create_process(0, INIT_NAME, 1, init_args); + init_process = init->process; + add_thread(init); + insert_ready_tail(init); + + if (smp_good && smp_num_cpus() > 1 && 0) { + /* SMP not enabled */ + smp_boot(kernel_smp_entry); + } + + kernel_smp_main(); + return -1; +} + +static void kernel_smp_entry(int cpuid) { + paging_enable(); + percpu_t percpu; + setup_percpu(&percpu); + thread_t kthread; + process_t kprocess; + setup_kth(&kthread, &kprocess); + set_mapped_phys_page(mapped_phys_pages + cpuid * PAGE_SIZE); + set_mapped_phys_page_pte(mapped_phys_page_ptes + cpuid); + kernel_smp_main(); +} + +static void kernel_smp_main() { + const char* idle_args[] = {IDLE_NAME}; + thread_t* idle = create_process(0, IDLE_NAME, 1, idle_args); + add_thread(idle); + set_idle(idle); + + while (1) { + int old_if = spl_lock(&ready_lock); + thread_t* t = select_next(); + yield_to_spl_unlock(t, &ready_lock, old_if); + /* when a thread borrow kthread's stack and free itself, it will return + * here and we continue yielding + */ + } + panic("kthread should not return"); +} diff --git a/kern/loader.c b/kern/loader.c new file mode 100644 index 0000000..2dfd8e3 --- /dev/null +++ b/kern/loader.c @@ -0,0 +1,58 @@ +/** + * The 15-410 kernel project. + * @name loader.c + * + * Functions for the loading + * of user programs from binary + * files should be written in + * this file. The function + * elf_load_helper() is provided + * for your use. + */ + +/* --- Includes --- */ +#include +#include +#include +#include +#include +#include + +/* --- Local function prototypes --- */ + +/** + * Copies data from a file into a buffer. + * + * @param filename the name of the file to copy data from + * @param offset the location in the file to begin copying from + * @param size the number of bytes to be copied + * @param buf the buffer to copy the data into + * + * @return returns the number of bytes copied on succes; -1 on failure + */ +int getbytes(const char* filename, int offset, int size, char* buf) { + file_t* f = find_file(filename); + if (f == NULL || offset > f->execlen) { + return -1; + } + return read_file(f, offset, size, buf); +} + +int read_file(file_t* f, int offset, int size, char* buf) { + int src_size = size; + if (f->execlen - offset < size) { + src_size = f->execlen - offset; + } + memcpy(buf, f->execbytes + offset, src_size); + return src_size; +} + +file_t* find_file(const char* name) { + int i; + for (i = 0; i < exec2obj_userapp_count; i++) { + if (strcmp(name, exec2obj_userapp_TOC[i].execname) == 0) { + return &exec2obj_userapp_TOC[i]; + } + } + return NULL; +} diff --git a/kern/malloc_wrappers.c b/kern/malloc_wrappers.c new file mode 100644 index 0000000..6b4d525 --- /dev/null +++ b/kern/malloc_wrappers.c @@ -0,0 +1,70 @@ +/** @file malloc_wrappers.c + * + * @brief locked malloc functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include + +#include + +mutex_t malloc_lock = MUTEX_INIT; + +/* safe versions of malloc functions */ +void* malloc(size_t size) { + mutex_lock(&malloc_lock); + void* mem = _malloc(size); + mutex_unlock(&malloc_lock); + return mem; +} + +void* memalign(size_t alignment, size_t size) { + mutex_lock(&malloc_lock); + void* mem = _memalign(alignment, size); + mutex_unlock(&malloc_lock); + return mem; +} + +void* calloc(size_t nelt, size_t eltsize) { + mutex_lock(&malloc_lock); + void* mem = _calloc(nelt, eltsize); + mutex_unlock(&malloc_lock); + return mem; +} + +void* realloc(void* buf, size_t new_size) { + mutex_lock(&malloc_lock); + void* mem = _realloc(buf, new_size); + mutex_unlock(&malloc_lock); + return mem; +} + +void free(void* buf) { + mutex_lock(&malloc_lock); + _free(buf); + mutex_unlock(&malloc_lock); +} + +void* smalloc(size_t size) { + mutex_lock(&malloc_lock); + void* mem = _smalloc(size); + mutex_unlock(&malloc_lock); + return mem; +} + +void* smemalign(size_t alignment, size_t size) { + mutex_lock(&malloc_lock); + void* mem = _smemalign(alignment, size); + mutex_unlock(&malloc_lock); + return mem; +} + +void sfree(void* buf, size_t size) { + mutex_lock(&malloc_lock); + _sfree(buf, size); + mutex_unlock(&malloc_lock); +} diff --git a/kern/mm.c b/kern/mm.c new file mode 100644 index 0000000..2c40af8 --- /dev/null +++ b/kern/mm.c @@ -0,0 +1,318 @@ +/** @file mm.c + * + * @brief memory management functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** header of a free page */ +typedef struct page_head_s { + int size; + pa_t prev; + pa_t next; +} page_head_t; + +/** footer of a free page */ +typedef struct page_foot_s { + char padding[PAGE_SIZE - sizeof(int)]; + int size; +} page_foot_t; + +/** total user pages */ +static int num_user_pages; + +/** bitmap to track page usage */ +static unsigned char* user_page_bitmap; + +/** bins from 4k to 1m, which is normal request size */ +#define NUM_BINS 9 +/** minimum size of last bin */ +#define LAST_BIN_SIZE (1 << (NUM_BINS - 1)) +/** bins for free chunks */ +static pa_t bins[9]; + +mutex_t mm_lock = MUTEX_INIT; + +/** + * @brief is a page inuse + * @param pn physical page number + * @return 1 inuse, 0 free + */ +static int is_page_inuse(int pn) { + return (user_page_bitmap[(pn + 1) / 8] & (1 << ((pn + 1) % 8))) != 0; +} + +/** + * @brief mark a page inuse + * @param pn physical page number + */ +static void set_page_inuse(int pn) { + user_page_bitmap[(pn + 1) / 8] |= (1 << ((pn + 1) % 8)); +} + +/** + * @brief mark a page free + * @param pn physical page number + */ +static void set_page_free(int pn) { + user_page_bitmap[(pn + 1) / 8] &= (~(1 << ((pn + 1) % 8))); +} + +/** + * @brief convert physical address to page number + * @param pa physical address + * @return physical page number + */ +static int pa_to_pn(pa_t pa) { + return (pa - USER_MEM_START) / PAGE_SIZE; +} + +/** + * @brief convert page number to physical address + * @param pn physical page number + * @return physical address + */ +static int pn_to_pa(int pn) { + return pn * PAGE_SIZE + USER_MEM_START; +} + +/** + * @brief find which bin a free chunk belongs to + * @param size size of chunk + * @return bin + */ +static int find_bin(int size) { + if (size >= LAST_BIN_SIZE) { + return NUM_BINS - 1; + } + int i; + for (i = NUM_BINS - 2; i > 0; i--) { + if ((size & (1 << i)) != 0) { + return i; + } + } + return 0; +} + +/** + * @brief add a chunk to bins + * @param pn physical page number + * @param size size of chunk + */ +static void add_to_bins(int pn, int size); + +/** + * @brief remove a chunk from bins + * @param pn physical page number + */ +static void remove_from_bins(int pn); + +/** + * @brief allocate a memory from a bin + * @param bin bin + * @param size size of chunk + * @return address of chunk, BAD_PA on failure + */ +static pa_t alloc_from_bin(pa_t* bin, int size); + +void mm_init() { + num_user_pages = machine_phys_frames() - (USER_MEM_START / PAGE_SIZE); + assert(num_user_pages > 0); + user_page_bitmap = smalloc((num_user_pages + 2) / 8); + assert(user_page_bitmap != NULL); + memset(user_page_bitmap, 0, (num_user_pages + 2) / 8); + memset(bins, 0, sizeof(bins)); + + set_page_inuse(-1); + set_page_inuse(num_user_pages); + add_to_bins(pa_to_pn(USER_MEM_START), num_user_pages); +} + +pa_t alloc_user_pages(int num_pages) { + mutex_lock(&mm_lock); + int bn = find_bin(num_pages); + while (bn < NUM_BINS) { + pa_t result = alloc_from_bin(&bins[bn], num_pages); + if (result != BAD_PA) { + mutex_unlock(&mm_lock); + return result; + } + bn++; + } + mutex_unlock(&mm_lock); + return BAD_PA; +} + +void free_user_pages(pa_t pa, int num_pages) { + mutex_lock(&mm_lock); + int pn = pa_to_pn(pa); + int final_pn = pn, final_size = num_pages; + + /* merge with prev */ + int prev_inuse = is_page_inuse(pn - 1); + if (prev_inuse == 0) { + int old_if = save_clear_if(); + page_foot_t* prev_foot = + (page_foot_t*)map_phys_page(pn_to_pa(pn - 1), NULL); + int prev_size = prev_foot->size; + restore_if(old_if); + int prev_pn = pn - prev_size; + remove_from_bins(prev_pn); + final_pn = prev_pn; + final_size += prev_size; + } + + /* merge with next */ + int next_pn = pn + num_pages; + int next_inuse = is_page_inuse(next_pn); + if (next_inuse == 0) { + int old_if = save_clear_if(); + page_head_t* next_head = + (page_head_t*)map_phys_page(pn_to_pa(next_pn), NULL); + int next_size = next_head->size; + restore_if(old_if); + remove_from_bins(next_pn); + final_size += next_size; + } + + add_to_bins(final_pn, final_size); + mutex_unlock(&mm_lock); +} + +va_t map_phys_page(pa_t pa, pa_t* old_pa) { + pte_t* pte = get_mapped_phys_page_pte(); + if (old_pa != NULL) { + *old_pa = get_page_base(*pte); + } + *pte = make_pte(pa, 0, PTE_SUPERVISOR, PTE_RW, PTE_PRESENT); + va_t va = get_mapped_phys_page(); + invlpg(va); + return va; +} + +/** + * @brief insert a chunk to a bin + * @param bin bin + * @param this_chunk chunk + * @param size size of chunk + */ +static void bin_insert(pa_t* bin, pa_t this_chunk, int size) { + int old_if = save_clear_if(); + if (*bin == BAD_PA) { + page_head_t* this_head = (page_head_t*)map_phys_page(this_chunk, NULL); + this_head->next = this_head->prev = this_chunk; + this_head->size = size; + } else { + pa_t head_chunk = *bin; + page_head_t* head_head = (page_head_t*)map_phys_page(head_chunk, NULL); + pa_t tail_chunk = head_head->prev; + head_head->prev = this_chunk; + page_head_t* this_head = (page_head_t*)map_phys_page(this_chunk, NULL); + this_head->next = head_chunk; + this_head->prev = tail_chunk; + this_head->size = size; + page_head_t* tail_head = (page_head_t*)map_phys_page(tail_chunk, NULL); + tail_head->next = this_chunk; + } + restore_if(old_if); + *bin = this_chunk; +} + +/** + * @brief remove a chunk from a bin + * @param bin bin + * @param this_chunk chunk + */ +static void bin_delete(pa_t* bin, pa_t this_chunk) { + int old_if = save_clear_if(); + page_head_t* this_head = (page_head_t*)map_phys_page(this_chunk, NULL); + pa_t next_chunk = this_head->next; + if (*bin == this_chunk) { + *bin = (next_chunk == this_chunk ? BAD_PA : next_chunk); + } + if (next_chunk != this_chunk) { + pa_t prev_chunk = this_head->prev; + page_head_t* next_head = (page_head_t*)map_phys_page(next_chunk, NULL); + next_head->prev = prev_chunk; + page_head_t* prev_head = (page_head_t*)map_phys_page(prev_chunk, NULL); + prev_head->next = next_chunk; + } + restore_if(old_if); +} + +static void add_to_bins(int pn, int size) { + set_page_free(pn); + set_page_free(pn + (size - 1)); + pa_t this_chunk = pn_to_pa(pn); + pa_t* bin = &bins[find_bin(size)]; + + bin_insert(bin, this_chunk, size); + + int old_if = save_clear_if(); + page_foot_t* this_foot = + (page_foot_t*)map_phys_page(pn_to_pa(pn + (size - 1)), NULL); + this_foot->size = size; + restore_if(old_if); +} + +static void remove_from_bins(int pn) { + pa_t this_chunk = pn_to_pa(pn); + int old_if = save_clear_if(); + page_head_t* this_head = (page_head_t*)map_phys_page(this_chunk, NULL); + int size = this_head->size; + restore_if(old_if); + pa_t* bin = &bins[find_bin(size)]; + bin_delete(bin, this_chunk); +} + +static pa_t alloc_from_bin(pa_t* bin, int size) { + if (*bin == BAD_PA) { + return BAD_PA; + } + pa_t r_pa = BAD_PA; + pa_t r_pn = 0; + pa_t this_chunk = *bin, end = *bin; + do { + int old_if = save_clear_if(); + page_head_t* this_head = (page_head_t*)map_phys_page(this_chunk, NULL); + int this_size = this_head->size; + pa_t next_chunk = this_head->next; + restore_if(old_if); + if (this_size > size) { + bin_delete(bin, this_chunk); + r_pa = this_chunk; + r_pn = pa_to_pn(r_pa); + add_to_bins(r_pn + size, this_size - size); + break; + } else if (this_size == size) { + bin_delete(bin, this_chunk); + r_pa = this_chunk; + r_pn = pa_to_pn(r_pa); + break; + } + this_chunk = next_chunk; + } while (this_chunk != end); + if (r_pa == BAD_PA) { + return BAD_PA; + } + set_page_inuse(r_pn); + set_page_inuse(r_pn + (size - 1)); + return r_pa; +} diff --git a/kern/paging.c b/kern/paging.c new file mode 100644 index 0000000..568db84 --- /dev/null +++ b/kern/paging.c @@ -0,0 +1,76 @@ +/** @file paging.c + * + * @brief paging management functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/** number of page tables for kernel memory */ +#define NUM_KERNEL_PT (USER_MEM_START / PAGE_SIZE / NUM_PAGE_ENTRY) + +page_directory_t* kernel_pd; +/** page tables for kernel memory */ +static page_table_t* kernel_pt; + +va_t mapped_phys_pages; +pte_t* mapped_phys_page_ptes; + +void paging_init() { + kernel_pd = (page_directory_t*)_smemalign(PAGE_SIZE, PAGE_SIZE); + kernel_pt = (page_table_t*)_smemalign(PAGE_SIZE, PAGE_SIZE * NUM_KERNEL_PT); + + int num_cpus = smp_num_cpus(); + mapped_phys_pages = (va_t)_smemalign(PAGE_SIZE, num_cpus * PAGE_SIZE); + mapped_phys_page_ptes = (pte_t*)kernel_pt + (mapped_phys_pages / PAGE_SIZE); + + if (kernel_pd == NULL || kernel_pt == NULL || mapped_phys_pages == 0 || + mapped_phys_page_ptes == NULL) { + panic("no space for kernel page table"); + } + + int i, j; + pa_t base = 0; + memset(kernel_pd, 0, sizeof(page_directory_t)); + for (i = 0; i < (USER_MEM_START / PT_SIZE); i++) { + (*kernel_pd)[i] = + make_pde((pa_t)&kernel_pt[i], PTE_SUPERVISOR, PTE_RW, PTE_PRESENT); + for (j = 0; j < NUM_PAGE_ENTRY; j++) { + kernel_pt[i][j] = + make_pte(base, PTE_G, PTE_SUPERVISOR, PTE_RW, PTE_PRESENT); + base += PAGE_SIZE; + } + } + + pa_t lapic_pa = (pa_t)smp_lapic_base(); + pte_t* lapic_pte = (pte_t*)kernel_pt + (LAPIC_VIRT_BASE / PAGE_SIZE); + *lapic_pte = + (make_pte(lapic_pa, PTE_G, PTE_SUPERVISOR, PTE_RW, PTE_PRESENT) | + (PTE_PCD << PTE_PCD_SHIFT)); + invlpg(LAPIC_VIRT_BASE); + + set_cr4(get_cr4() | CR4_PSE | CR4_PGE); + set_cr3((uint32_t)kernel_pd); + set_cr0(get_cr0() | CR0_PE | CR0_PG); +} + +void paging_enable() { + set_cr4(get_cr4() | CR4_PSE | CR4_PGE); + set_cr3((uint32_t)kernel_pd); + set_cr0(get_cr0() | CR0_PE | CR0_PG); +} diff --git a/kern/sched.c b/kern/sched.c new file mode 100644 index 0000000..eb8d334 --- /dev/null +++ b/kern/sched.c @@ -0,0 +1,762 @@ +/** @file sched.c + * + * @brief scheduling functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* .text, .rodata, .data+bss, stack and a heap and one for future new_pages */ +#define INIT_NUM_REGIONS 6 + +/** + * @brief load a elf to memory space + * @param p process + * @param elf elf header + * @param exe elf file name + * @return 0 on success, -1 on failure + */ +static int process_load_elf(process_t* p, simple_elf_t* elf, char* exe); +/** + * @brief load a elf segment to memory space + * @param p process + * @param f elf file entry, NULL for empty segments + * @param offset offset in elf file + * @param f_len length of data in elf file + * @param vaddr addr to load to + * @param m_len length of segment + * @param is_rw is segment writable + * @return 0 on success, -1 on failure + */ +static int load_segment(process_t* p, + file_t* f, + int offset, + int f_len, + va_t vaddr, + int m_len, + int is_rw); + +process_t* init_process; + +spl_t ready_lock = SPL_INIT; +queue_t* ready = NULL; + +rb_t* threads = &rb_nil; +mutex_t threads_lock = MUTEX_INIT; + +/* G means global segment */ +#define GDT_G_BIT 0x0080000000000000ull +/* FLAG is control flags for segment */ +#define GDT_FLAG_MASK 0x00f0ff0000000000ull +/* high part of base address */ +#define GDT_BASE_MASK_HI 0xff000000ull +/* low part of base address */ +#define GDT_BASE_MASK_LO 0x00ffffffull +/* position of high part of base address */ +#define GDT_BASE_SHIFT_HI (64 - 32) +/* position of low part of base address */ +#define GDT_BASE_SHIFT_LO (40 - 24) +/* high part of limit */ +#define GDT_LIMIT_MASK_HI 0xf0000ull +/* low part of limit */ +#define GDT_LIMIT_MASK_LO 0x0ffffull +/* position of high part of limit */ +#define GDT_LIMIT_SHIFT_HI (52 - 20) +/* position of low part of limit */ +#define GDT_LIMIT_SHIFT_LO (16 - 16) + +/** + * @brief set fs + * @param fs fs + */ +void set_fs(reg_t fs); + +void setup_percpu(percpu_t* percpu) { + uint64_t* gdt = (uint64_t*)gdt_base(); + uint64_t ds = gdt[SEGSEL_KERNEL_DS_IDX]; + /* copy ds's flags so we do not need to create one */ + uint64_t ds_flags = (ds & GDT_FLAG_MASK); + uint64_t base = (uint64_t)(uint32_t)percpu; + uint64_t limit = base + sizeof(percpu_t) - 1; + uint64_t fs = (((base & GDT_BASE_MASK_HI) << GDT_BASE_SHIFT_HI) | + ((base & GDT_BASE_MASK_LO) << GDT_BASE_SHIFT_LO) | + ((limit & GDT_LIMIT_MASK_HI) << GDT_LIMIT_SHIFT_HI) | + ((limit & GDT_LIMIT_MASK_LO) << GDT_LIMIT_SHIFT_LO) | + (ds_flags & (~GDT_G_BIT))); + gdt[SEGSEL_KERNEL_FS_IDX] = fs; + lgdt(gdt, GDT_SEGS * sizeof(uint64_t) - 1); + set_fs(SEGSEL_KERNEL_FS); +} + +void setup_kth(thread_t* kthread, process_t* kprocess) { + memset(kthread, 0, sizeof(thread_t)); + memset(kprocess, 0, sizeof(process_t)); + kprocess->refcount = 1; + kprocess->cr3 = (pa_t)kernel_pd; + kthread->process = kprocess; + set_current(kthread); + set_kthread(kthread); +} + +/* exit value when all tasks vanish and status is never set, no religious + * meaning + */ +#define DEFAULT_EXIT_VALUE 666 + +thread_t* create_empty_process() { + process_t* p = smalloc(sizeof(process_t)); + if (p == NULL) { + goto alloc_pcb_fail; + } + thread_t* t = smalloc(sizeof(thread_t)); + if (t == NULL) { + goto alloc_tcb_fail; + } + t->stack = smalloc(K_STACK_SIZE); + if (t->stack == NULL) { + goto alloc_thread_stack_fail; + } + p->exit_value = DEFAULT_EXIT_VALUE; + p->parent = NULL; + p->refcount_lock = MUTEX_INIT; + p->refcount = 1; + p->threads = NULL; + p->nchilds = 0; + p->live_childs = NULL; + p->dead_childs = NULL; + p->nwaiters = 0; + p->wait_lock = MUTEX_INIT; + p->wait_cv = CV_INIT; + if (vector_init(&p->regions, sizeof(region_t), INIT_NUM_REGIONS) != 0) { + goto alloc_region_fail; + } + + p->cr3 = alloc_user_pages(1); + if (p->cr3 == 0) { + goto alloc_pd_fail; + } + int old_if = save_clear_if(); + page_directory_t* pd = (page_directory_t*)map_phys_page(p->cr3, NULL); + memset(pd, 0, PAGE_SIZE); + int i; + /* copy kernel direct mapping */ + for (i = 0; i < USER_PD_START; i++) { + (*pd)[i] = (*kernel_pd)[i]; + } + restore_if(old_if); + p->mm_lock = MUTEX_INIT; + + t->status = THREAD_DEAD; + t->status_lock = SPL_INIT; + t->pending_exit = 0; + queue_insert_head(&p->threads, &t->process_link); + t->rb_node.parent = NULL; /* mark that the thread is not added to rbtree */ + t->process = p; + t->eip3 = 0; + t->esp0 = t->kernel_esp = (reg_t)&t->stack[K_STACK_SIZE]; + t->eip0 = 0; + t->df3 = 0; + return t; + +alloc_pd_fail: + vector_free(&p->regions); +alloc_region_fail: + sfree(t->stack, K_STACK_SIZE); +alloc_thread_stack_fail: + sfree(t, sizeof(thread_t)); +alloc_tcb_fail: + sfree(p, sizeof(process_t)); +alloc_pcb_fail: + return NULL; +} + +static int process_load_elf(process_t* p, simple_elf_t* elf, char* exe) { + file_t* f = find_file(exe); + + if (elf->e_txtlen != 0 && + load_segment(p, f, elf->e_txtoff, elf->e_txtlen, elf->e_txtstart, + elf->e_txtlen, 0) != 0) { + goto load_segment_fail; + } + if (elf->e_rodatlen != 0 && + load_segment(p, f, elf->e_rodatoff, elf->e_rodatlen, elf->e_rodatstart, + elf->e_rodatlen, 0) != 0) { + goto load_segment_fail; + } + if (elf->e_datlen != 0 && + load_segment(p, f, elf->e_datoff, elf->e_datlen, elf->e_datstart, + elf->e_datlen, 1) != 0) { + goto load_segment_fail; + } + /* if data segment is loaded, try to load bss after data */ + if (elf->e_datlen != 0) { + if (elf->e_bsslen != 0) { + /* allow bss to start from unaligned/overlapped address */ + va_t bss_start = (elf->e_bssstart & PAGE_BASE_MASK); + va_t bss_end = ((elf->e_bssstart + elf->e_bsslen + PAGE_SIZE) & + PAGE_BASE_MASK); + va_t data_start = (elf->e_datstart & PAGE_BASE_MASK); + va_t data_end = ((elf->e_datstart + elf->e_datlen + PAGE_SIZE) & + PAGE_BASE_MASK); + if (bss_start >= data_start && bss_start < data_end) { + /* append bss after data */ + bss_start = data_end; + } + /* let add_region handle overlap/overflow problem */ + if ((bss_end > bss_start) && + load_segment(p, NULL, 0, 0, bss_start, bss_end - bss_start, + 1) != 0) { + goto load_segment_fail; + }; + } + } else { + if (elf->e_bsslen != 0 && load_segment(p, NULL, 0, 0, elf->e_bssstart, + elf->e_bsslen, 1) != 0) { + goto load_segment_fail; + } + } + + if (load_segment(p, NULL, 0, 0, DEFAULT_STACK_POS, DEFAULT_STACK_SIZE, 1)) { + goto load_segment_fail; + } + return 0; + +load_segment_fail: + return -1; +} + +thread_t* create_process(int tid, char* exe, int argc, const char** argv) { + thread_t* t = create_empty_process(); + if (t == NULL) { + goto alloc_tcb_fail; + } + t->process->pid = t->rb_node.key = ((tid == 0) ? alloc_tid() : tid); + + /* temporarily use new process's cr3 to load elf */ + reg_t old_cr3 = get_current()->process->cr3; + get_current()->process->cr3 = t->process->cr3; + set_cr3(t->process->cr3); + + simple_elf_t elf; + if (elf_load_helper(&elf, exe) != ELF_SUCCESS || + process_load_elf(t->process, &elf, exe) != 0) { + goto load_elf_fail; + } + + unsigned long* argv_addrs = smalloc(argc * sizeof(unsigned long)); + if (argv_addrs == NULL) { + goto alloc_argc_addr_fail; + } + char* esp = (char*)(DEFAULT_STACK_END); + int i, len, total = 0; + for (i = argc - 1; i >= 0; i--) { + len = strlen(argv[i]); + if (len + total > MAX_TOTAL_ARG_LEN) { + goto load_elf_fail; + } + esp -= (len + 1); + memcpy(esp, argv[i], len + 1); + argv_addrs[i] = (unsigned long)esp; + } + unsigned long* new_esp = + (unsigned long*)(((va_t)esp) & (~(sizeof(va_t) - 1))); + --new_esp; + *new_esp = 0; + for (i = argc - 1; i >= 0; i--) { + --new_esp; + *new_esp = argv_addrs[i]; + } + unsigned long new_argv = (unsigned long)new_esp; + sfree(argv_addrs, argc * sizeof(unsigned long)); + + new_esp -= 5; + new_esp[0] = 0; /* return address */ + new_esp[1] = argc; /* argc */ + new_esp[2] = new_argv; /* argv */ + new_esp[3] = DEFAULT_STACK_END; /* stack_hi */ + new_esp[4] = DEFAULT_STACK_POS; /* stack_lo */ + + get_current()->process->cr3 = old_cr3; + set_cr3(old_cr3); + + t->kernel_esp -= sizeof(stack_frame_t); + stack_frame_t* frame = (stack_frame_t*)t->kernel_esp; + frame->eip = (reg_t)elf.e_entry; + frame->cs = SEGSEL_USER_CS; + frame->eflags = DEFAULT_EFLAGS; + frame->esp = (reg_t)new_esp; + frame->ss = SEGSEL_USER_DS; + frame->eax = 0; + frame->ecx = 0; + frame->edx = 0; + frame->ebx = 0; + frame->ebp = 0; + frame->esi = 0; + frame->edi = 0; + frame->ds = SEGSEL_USER_DS; + frame->es = SEGSEL_USER_DS; + frame->fs = SEGSEL_USER_DS; + frame->gs = SEGSEL_USER_DS; + + t->kernel_esp -= sizeof(yield_frame_t); + yield_frame_t* yf = (yield_frame_t*)t->kernel_esp; + yf->eflags = DEFAULT_EFLAGS; + yf->raddr = (reg_t)return_to_user; + return t; + +alloc_argc_addr_fail: +load_elf_fail: + get_current()->process->cr3 = old_cr3; + set_cr3(old_cr3); + destroy_thread(t); +alloc_tcb_fail: + return NULL; +} + +void destroy_thread(thread_t* t) { + process_t* p = t->process; + sfree(t->stack, K_STACK_SIZE); + sfree(t, sizeof(thread_t)); + mutex_lock(&p->refcount_lock); + queue_detach(&p->threads, &t->process_link); + p->refcount--; + if (p->refcount != 0) { + mutex_unlock(&p->refcount_lock); + return; + } + mutex_unlock(&p->refcount_lock); + int i, n = vector_size(&p->regions); + for (i = 0; i < n; i++) { + region_t* r = (region_t*)vector_at(&p->regions, i); + free_user_pages(r->paddr, r->size / PAGE_SIZE); + } + vector_free(&p->regions); + + int old_if = save_clear_if(); + for (i = USER_PD_START; i < NUM_PAGE_ENTRY; i++) { + page_directory_t* pd = (page_directory_t*)map_phys_page(p->cr3, NULL); + if ((*pd)[i] != BAD_PDE) { + pa_t pt = get_page_table((*pd)[i]); + free_user_pages(pt, 1); + } + } + restore_if(old_if); + free_user_pages(p->cr3, 1); + sfree(p, sizeof(process_t)); +} + +int alloc_tid() { + static int tid = 1; + static int next_check = (1 << 31); + if (tid == next_check) { + /* allocated all pids */ + mutex_lock(&threads_lock); + rb_t *p, *q; + p = rb_min(threads); + if (p == &rb_nil) { + /* no pid inuse */ + tid = 1; + next_check = (1 << 31); + } else { + while (1) { + q = rb_next(p); + if (q == &rb_nil) { + /* available tids are p+1 ~ 0x7fffffff */ + if (p->key + 1 == (1 << 31)) { + /* all pids inuse */ + panic("too many threads"); + } + tid = p->key + 1; + next_check = (1 << 31); + break; + } + /* check until q-p>1, which gives us some free tids */ + if (q->key == p->key + 1) { + p = q; + continue; + } + tid = p->key + 1; + next_check = q->key; + break; + } + } + mutex_unlock(&threads_lock); + } + return tid++; +} + +static int load_segment(process_t* p, + file_t* f, + int f_off, + int f_len, + va_t m_off, + int m_len, + int is_rw) { + va_t m_start = (m_off & PAGE_BASE_MASK); + va_t m_end = ((m_off + m_len + (PAGE_SIZE - 1)) & PAGE_BASE_MASK); + int n_pages = (m_end - m_start) / PAGE_SIZE; + pa_t paddr = alloc_user_pages(n_pages); + if (paddr == 0) { + goto alloc_segment_fail; + } + /* handle address check and overlapping issues */ + if (add_region(p, m_start, n_pages, paddr, is_rw) != 0) { + goto add_region_fail; + } + + int rw = (is_rw ? PTE_RW : PTE_RO); + int i = 0; + int offset = 0; + /* file page table one entry per loop */ + pa_t pt_pa = find_or_create_pt(p, m_start); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + do { + offset = i * PAGE_SIZE; + int pt_index = get_pt_index(m_start + offset); + if (pt_index == 0) { + /* step to next page table */ + pt_pa = find_or_create_pt(p, m_start + offset); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + } + + int old_if = save_clear_if(); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + /* do not set P bit for ZFOD */ + (*pt)[pt_index] = make_pte(paddr + offset, 0, PTE_USER, rw, 0); + restore_if(old_if); + invlpg(m_start + offset); + } while (++i < n_pages); + + if (f != NULL) { + read_file(f, f_off, f_len, (char*)m_off); + } + return 0; + +add_pt_fail: + /* page tables are reachable from page directory so no need to free them */ + vector_pop(&p->regions); +add_region_fail: + free_user_pages(paddr, n_pages); +alloc_segment_fail: + return -1; +} + +pa_t find_or_create_pt(process_t* p, va_t vaddr) { + int old_if = save_clear_if(); + page_directory_t* pd = (page_directory_t*)map_phys_page(p->cr3, NULL); + pde_t* pde = &(*pd)[get_pd_index(vaddr)]; + if (*pde == BAD_PDE) { + /* add a page table */ + pa_t pt = alloc_user_pages(1); + if (pt == 0) { + return 0; + } + va_t pt_addr = map_phys_page(pt, NULL); + memset((void*)pt_addr, 0, PAGE_SIZE); + + map_phys_page(p->cr3, NULL); + *pde = make_pde(pt, PTE_USER, PTE_RW, PTE_PRESENT); + invlpg(vaddr); + restore_if(old_if); + return pt; + } + pa_t result = get_page_table(*pde); + restore_if(old_if); + return result; +} + +int add_region(process_t* p, va_t start, int n_pages, pa_t pa, int is_rw) { + if (start > DEFAULT_STACK_END || start < USER_MEM_START) { + return -1; + } + va_t end = start + n_pages * PAGE_SIZE; + if (end < start) { + return -1; + } + int i, n = vector_size(&p->regions); + for (i = 0; i < n; i++) { + /* check overlapping */ + region_t* r = (region_t*)vector_at(&p->regions, i); + va_t this_start = r->addr; + va_t this_end = this_start + r->size; + if (start >= this_start && start < this_end) { + return -1; + } + if (end > this_start && end <= this_end) { + return -1; + } + if (this_start >= start && this_start < end) { + return -1; + } + if (this_end > start && this_end <= end) { + return -1; + } + } + region_t newr; + newr.addr = start; + newr.size = n_pages * PAGE_SIZE; + newr.paddr = pa; + newr.is_rw = is_rw; + return vector_push(&p->regions, &newr); +} + +thread_t* select_next() { + thread_t* t; + if (ready != NULL) { + t = queue_data(queue_remove_head(&ready), thread_t, sched_link); + } else { + t = get_idle(); + } + return t; +} + +void insert_ready_tail(thread_t* t) { + t->status = THREAD_READY; + queue_insert_tail(&ready, &t->sched_link); +} + +void insert_ready_head(thread_t* t) { + t->status = THREAD_READY; + queue_insert_head(&ready, &t->sched_link); +} + +reg_t save_and_setup_env(thread_t* t, reg_t esp) { + get_current()->kernel_esp = esp; + set_current(t); + t->status = THREAD_RUNNING; + set_esp0(t->esp0); + set_cr3(t->process->cr3); + return t->kernel_esp; +} + +void swap_process_inplace(thread_t* newt) { + disable_interrupts(); + thread_t* oldt = get_current(); + process_t* oldp = oldt->process; + process_t* newp = newt->process; + pa_t cr3 = oldp->cr3; + vector_t regions = oldp->regions; + queue_t* p_threads = oldp->threads; + oldp->cr3 = newp->cr3; + oldp->regions = newp->regions; + oldp->threads = newp->threads; + newp->cr3 = cr3; + newp->regions = regions; + newp->threads = p_threads; + newt->process = oldp; + oldt->process = newp; + set_cr3(newp->cr3); + mutex_lock(&threads_lock); + /* move oldt's rbtree node to newt */ + newt->rb_node = oldt->rb_node; + if (threads == &oldt->rb_node) { + threads = &newt->rb_node; + }; + if (newt->rb_node.left != &rb_nil) { + newt->rb_node.left->parent = &newt->rb_node; + } + if (newt->rb_node.right != &rb_nil) { + newt->rb_node.right->parent = &newt->rb_node; + } + if (newt->rb_node.parent != &rb_nil) { + if (newt->rb_node.parent->left == &oldt->rb_node) { + newt->rb_node.parent->left = &newt->rb_node; + } else { + newt->rb_node.parent->right = &newt->rb_node; + } + } + oldt->rb_node.parent = NULL; + mutex_unlock(&threads_lock); + enable_interrupts(); +} + +void kill_current() { + thread_t* current = get_current(); + process_t* p = current->process; + /* respawn important process */ + if (current == get_idle()) { + if (p->refcount == 1) { + const char* idle_args[] = {IDLE_NAME}; + thread_t* new_idle = + create_process(current->rb_node.key, IDLE_NAME, 1, idle_args); + if (new_idle == NULL) { + panic("no space to allocate idle process"); + } + swap_process_inplace(new_idle); + set_idle(new_idle); + } + } else if (p == init_process) { + if (p->refcount == 1) { + mutex_lock(&p->wait_lock); + /* reclaim dead childs */ + while (p->dead_childs != NULL) { + queue_t* node = p->dead_childs; + queue_detach(&p->dead_childs, node); + process_t* child_process = + queue_data(node, process_t, sible_link); + sfree(child_process, sizeof(process_t)); + p->nchilds--; + } + mutex_unlock(&p->wait_lock); + const char* init_args[] = {INIT_NAME}; + thread_t* new_init = + create_process(current->rb_node.key, INIT_NAME, 1, init_args); + if (new_init == NULL) { + panic("no space to allocate init process"); + } + swap_process_inplace(new_init); + int old_if = spl_lock(&ready_lock); + insert_ready_tail(new_init); + spl_unlock(&ready_lock, old_if); + } + } + + if (current->rb_node.parent != NULL) { + remove_thread(current); + } + + p = current->process; + mutex_lock(&p->refcount_lock); + p->refcount--; + queue_detach(&p->threads, ¤t->process_link); + int is_last = (p->refcount == 0); + mutex_unlock(&p->refcount_lock); + if (is_last != 0) { + /* move childs to init process */ + mutex_lock(&p->wait_lock); + mutex_lock(&init_process->wait_lock); + while (p->live_childs != NULL) { + queue_t* node = p->live_childs; + queue_detach(&p->live_childs, node); + queue_insert_tail(&init_process->live_childs, node); + process_t* child_process = queue_data(node, process_t, sible_link); + child_process->parent = init_process; + init_process->nchilds++; + } + while (p->dead_childs != NULL) { + queue_t* node = p->dead_childs; + queue_detach(&p->dead_childs, node); + queue_insert_tail(&init_process->dead_childs, node); + process_t* child_process = queue_data(node, process_t, sible_link); + child_process->parent = init_process; + init_process->nchilds++; + cv_signal(&init_process->wait_cv); + } + mutex_unlock(&init_process->wait_lock); + mutex_unlock(&p->wait_lock); + + /* free userspace memory */ + pa_t old_cr3 = p->cr3; + p->cr3 = (pa_t)kernel_pd; + set_cr3((pa_t)kernel_pd); + int i, n = vector_size(&p->regions); + for (i = 0; i < n; i++) { + region_t* r = (region_t*)vector_at(&p->regions, i); + free_user_pages(r->paddr, r->size / PAGE_SIZE); + } + vector_free(&p->regions); + + int old_if = save_clear_if(); + for (i = USER_PD_START; i < NUM_PAGE_ENTRY; i++) { + page_directory_t* pd = + (page_directory_t*)map_phys_page(old_cr3, NULL); + if ((*pd)[i] != BAD_PDE) { + pa_t pt = get_page_table((*pd)[i]); + free_user_pages(pt, 1); + } + } + restore_if(old_if); + free_user_pages(old_cr3, 1); + } + + /* make sure we do not get swapped out before borrowing kthread's stack */ + mutex_lock(&malloc_lock); + disable_interrupts(); + current->status = THREAD_DEAD; + if (is_last != 0) { + /* we cannot switch back after p is reclaimed so we must put cv_signal + * after disable_interrupts + */ + if (p->parent != NULL) { + mutex_lock(&p->parent->wait_lock); + queue_detach(&p->parent->live_childs, &p->sible_link); + queue_insert_tail(&p->parent->dead_childs, &p->sible_link); + cv_signal(&p->parent->wait_cv); + mutex_unlock(&p->parent->wait_lock); + } else { + _sfree(p, sizeof(process_t)); + } + } + /* borrow kth's stack for freeing thread control block + * we can make sure kthread is not running since we are the running thread + * and kthread's IF is cleared so it will not be interrupted + */ + thread_t* kth = get_kthread(); + set_current(kth); + switch_stack_cleanup(kth->kernel_esp, current); +} + +/** + * @brief clean thread control block and its stack + * @param t thread + */ +void cleanup_dead_thread(thread_t* t) { + _sfree(t->stack, K_STACK_SIZE); + _sfree(t, sizeof(thread_t)); + mutex_unlock(&malloc_lock); + /* we will return to kthread's loop and it will yield + * cannot do yield here since it increases stack + */ +} + +/** + * @brief check if a task_vanish is pending and if so, do vanish + * @param f saved regs + */ +void check_pending_exit(stack_frame_t* f) { + /* only vanish before returning to userspace, otherwise some kernel + * structure may be jammed + */ + if (get_current()->pending_exit != 0 && f->cs == SEGSEL_USER_CS) { + kill_current(); + } +} + +thread_t* find_thread(int tid) { + rb_t* result = rb_find(threads, tid); + if (result == NULL) { + return NULL; + } + return rb_data(result, thread_t, rb_node); +} + +void add_thread(thread_t* t) { + mutex_lock(&threads_lock); + rb_insert(&threads, &t->rb_node); + mutex_unlock(&threads_lock); +} + +void remove_thread(thread_t* t) { + mutex_lock(&threads_lock); + rb_delete(&threads, &t->rb_node); + mutex_unlock(&threads_lock); +} diff --git a/kern/sched_asm.S b/kern/sched_asm.S new file mode 100644 index 0000000..747598e --- /dev/null +++ b/kern/sched_asm.S @@ -0,0 +1,67 @@ +/** @file sched_asm.S + * + * @brief scheduling functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include + +.text + +.global set_fs +.type set_fs, %function +set_fs: + push 0x4(%esp) + pop %fs + ret + +.macro PERCPU_GETSET name offset +.global get_\name +.type get_\name, %function +get_\name: + xor %eax, %eax + mov %fs:\offset(%eax), %eax + ret + +.global set_\name +.type set_\name, %function +set_\name: + xor %esi, %esi + mov 0x4(%esp), %eax + mov %eax, %fs:\offset(%esi) + ret +.endm + +PERCPU_GETSET current 0x0 +PERCPU_GETSET idle 0x4 +PERCPU_GETSET kthread 0x8 +PERCPU_GETSET mapped_phys_page 0xc +PERCPU_GETSET mapped_phys_page_pte 0x10 + +.global return_to_user +.type return_to_user, %function +return_to_user: + push %esp + call check_pending_exit + add $0x4, %esp + pop %gs /* restore from stack_frame_t structure */ + pop %fs + pop %es + pop %ds + popa + iret + +.global switch_stack_cleanup +.type switch_stack_cleanup, %function +switch_stack_cleanup: + mov 0x8(%esp), %eax + mov 0x4(%esp), %esp + push %eax + call cleanup_dead_thread + add $0x4, %esp + pop %ebp + pop %ebx + popf + ret diff --git a/kern/sync.c b/kern/sync.c new file mode 100644 index 0000000..4e4e6de --- /dev/null +++ b/kern/sync.c @@ -0,0 +1,78 @@ +/** @file sync.c + * + * @brief locks. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include + +#include +#include +#include + +void mutex_lock(mutex_t* m) { + thread_t* current = get_current(); + int old_if = spl_lock(&m->guard); + if (m->locked == 0) { + m->locked = 1; + spl_unlock(&m->guard, old_if); + return; + } + queue_insert_tail(&m->waiters, ¤t->sched_link); + current->status = THREAD_BLOCKED; + int old_if2 = spl_lock(&ready_lock); + thread_t* t = select_next(); + spl_unlock(&ready_lock, old_if2); + /* release m->gaurd last, otherwise other thread may switch to us before + * yielding + */ + yield_to_spl_unlock(t, &m->guard, old_if); +} + +void mutex_unlock(mutex_t* m) { + int old_if = spl_lock(&m->guard); + if (m->waiters == NULL) { + m->locked = 0; + spl_unlock(&m->guard, old_if); + return; + } + /* transfer lock ownership to t */ + thread_t* t = + queue_data(queue_remove_head(&m->waiters), thread_t, sched_link); + int old_if2 = spl_lock(&ready_lock); + insert_ready_head(t); + spl_unlock(&ready_lock, old_if2); + spl_unlock(&m->guard, old_if); +} + +void cv_wait(cv_t* cv, mutex_t* m) { + thread_t* current = get_current(); + int old_if = spl_lock(&cv->guard); + queue_insert_tail(&cv->waiters, ¤t->sched_link); + current->status = THREAD_BLOCKED; + mutex_unlock(m); + int old_if2 = spl_lock(&ready_lock); + thread_t* t = select_next(); + spl_unlock(&ready_lock, old_if2); + yield_to_spl_unlock(t, &cv->guard, old_if); + /* some threads may jump in so a condition check in a while loop is required + * outside + */ + mutex_lock(m); +} + +void cv_signal(cv_t* cv) { + int old_if = spl_lock(&cv->guard); + if (cv->waiters == NULL) { + spl_unlock(&cv->guard, old_if); + return; + } + thread_t* t = + queue_data(queue_remove_head(&cv->waiters), thread_t, sched_link); + int old_if2 = spl_lock(&ready_lock); + insert_ready_head(t); + spl_unlock(&ready_lock, old_if2); + spl_unlock(&cv->guard, old_if); +} diff --git a/kern/sync_asm.S b/kern/sync_asm.S new file mode 100644 index 0000000..b3fc852 --- /dev/null +++ b/kern/sync_asm.S @@ -0,0 +1,75 @@ +/** @file sync_asm.S + * + * @brief locks. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +.text + +#define EFL_IF 0x00000200 + +.global save_clear_if +.type save_clear_if, %function +save_clear_if: + pushf + pop %eax + cli + ret + +.global restore_if +.type restore_if, %function +restore_if: + mov 0x4(%esp), %eax + push %eax + popf + ret + +.global spl_lock +.type spl_lock, %function +spl_lock: + pushf + pop %edx + cli + mov 0x4(%esp), %esi + mov $1, %edi +.spl_lock_try: + xor %eax, %eax + lock cmpxchg %edi, (%esi) + test %eax, %eax + jnz .spl_lock_try + mov %edx, %eax + ret + +.global spl_unlock +.type spl_unlock, %function +spl_unlock: + mov 0x8(%esp), %eax + mov 0x4(%esp), %esi + xor %edx, %edx + mov %edx, (%esi) + push %eax + popf + ret + +.global yield_to_spl_unlock +.type yield_to_spl_unlock, %function +yield_to_spl_unlock: + mov 0xc(%esp), %edi + mov 0x8(%esp), %esi + mov 0x4(%esp), %eax + push %edi /* old_if, will be restored when switching back */ + push %ebx + push %ebp + mov %esi, %ebx + push %esp + push %eax + call save_and_setup_env + mov %eax, %esp + xor %eax, %eax + mov %eax, (%ebx) + pop %ebp + pop %ebx + popf + ret diff --git a/kern/syscall_asm.S b/kern/syscall_asm.S new file mode 100644 index 0000000..050788a --- /dev/null +++ b/kern/syscall_asm.S @@ -0,0 +1,61 @@ +/** @file syscall_asm.S + * + * @brief syscall entries. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include + +#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 + +.macro SYSCALL name +.global sys_\name +.type sys_\name, %function +sys_\name: + pusha /* save a stack_frame_t structure */ + push %ds + push %es + push %fs + push %gs + mov $SEGSEL_KERNEL_DS, %eax + mov %ax, %ds + mov %ax, %es + mov $SEGSEL_KERNEL_FS, %eax + mov %ax, %fs + cld + push %esp + call sys_\name\()_real + add $0x4, %esp + jmp return_to_user /* check pending exit before iret */ +.endm + +SYSCALL fork +SYSCALL exec +SYSCALL wait +SYSCALL yield +SYSCALL deschedule +SYSCALL make_runnable +SYSCALL gettid +SYSCALL new_pages +SYSCALL remove_pages +SYSCALL sleep +SYSCALL getchar +SYSCALL readline +SYSCALL print +SYSCALL set_term_color +SYSCALL set_cursor_pos +SYSCALL get_cursor_pos +SYSCALL thread_fork +SYSCALL get_ticks +SYSCALL misbehave +SYSCALL halt +SYSCALL task_vanish +SYSCALL set_status +SYSCALL vanish +SYSCALL readfile +SYSCALL swexn + +SYSCALL enosys diff --git a/kern/syscall_io.c b/kern/syscall_io.c new file mode 100644 index 0000000..3a9dc99 --- /dev/null +++ b/kern/syscall_io.c @@ -0,0 +1,151 @@ +/** @file syscall_io.c + * + * @brief IO syscalls. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief print() syscall handler + * @param f saved regs + */ +void sys_print_real(stack_frame_t* f) { + reg_t esi = f->esi; + int len; + if (copy_from_user((va_t)esi, sizeof(int), &len) != 0) { + goto read_fail; + } + if (len < 0) { + goto bad_length; + } + va_t base; + if (copy_from_user((va_t)esi + sizeof(va_t), sizeof(va_t), &base) != 0) { + goto read_fail; + } + mutex_lock(&console_lock); + f->eax = (reg_t)print_buf_from_user(base, len); + mutex_unlock(&console_lock); + return; + +read_fail: + f->eax = (reg_t)-1; + return; + +bad_length: + f->eax = (reg_t)-2; +} + +/** + * @brief set_term_color() syscall handler + * @param f saved regs + */ +void sys_set_term_color_real(stack_frame_t* f) { + reg_t esi = f->esi; + mutex_lock(&console_lock); + f->eax = (reg_t)set_term_color((int)esi); + mutex_unlock(&console_lock); +} + +/** + * @brief set_cursor_pos() syscall handler + * @param f saved regs + */ +void sys_set_cursor_pos_real(stack_frame_t* f) { + reg_t esi = f->esi; + int row, col; + if (copy_from_user((va_t)esi, sizeof(int), &row) != 0) { + goto read_arg_fail; + } + if (copy_from_user((va_t)(esi + sizeof(va_t)), sizeof(int), &col) != 0) { + goto read_arg_fail; + } + mutex_lock(&console_lock); + f->eax = (reg_t)set_cursor(row, col); + mutex_unlock(&console_lock); + return; + +read_arg_fail: + f->eax = (reg_t)-1; + return; +} + +/** + * @brief get_cursor_pos() syscall handler + * @param f saved regs + */ +void sys_get_cursor_pos_real(stack_frame_t* f) { + reg_t esi = f->esi; + va_t prow, pcol; + if (copy_from_user((va_t)esi, sizeof(va_t), &prow) != 0) { + goto read_arg_fail; + } + if (copy_from_user((va_t)(esi + sizeof(va_t)), sizeof(va_t), &pcol) != 0) { + goto read_arg_fail; + } + int row, col; + mutex_lock(&console_lock); + get_cursor(&row, &col); + mutex_unlock(&console_lock); + if (copy_to_user(prow, sizeof(int), &row) != 0) { + goto bad_arg; + } + if (copy_to_user(pcol, sizeof(int), &col) != 0) { + goto bad_arg; + } + f->eax = 0; + return; + +bad_arg: +read_arg_fail: + f->eax = (reg_t)-1; + return; +} + +/** + * @brief getchar() syscall handler + * @param f saved regs + */ +void sys_getchar_real(stack_frame_t* f) { + f->eax = (reg_t)do_getchar(); +} + +/** + * @brief readline() syscall handler + * @param f saved regs + */ +void sys_readline_real(stack_frame_t* f) { + int len; + va_t buf; + reg_t esi = f->esi; + if (copy_from_user((va_t)esi, sizeof(int), &len) != 0) { + goto read_arg_fail; + } + if (copy_from_user((va_t)(esi + sizeof(va_t)), sizeof(va_t), &buf) != 0) { + goto read_arg_fail; + } + f->eax = (reg_t)do_readline(len, buf); + return; + +read_arg_fail: + f->eax = (reg_t)-1; + return; +} diff --git a/kern/syscall_memory.c b/kern/syscall_memory.c new file mode 100644 index 0000000..288d6df --- /dev/null +++ b/kern/syscall_memory.c @@ -0,0 +1,137 @@ +/** @file syscall_memory.c + * + * @brief memory syscalls. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * @brief new_pages() syscall handler + * @param f saved regs + */ +void sys_new_pages_real(stack_frame_t* f) { + reg_t esi = f->esi; + va_t base; + if (copy_from_user((va_t)esi, sizeof(va_t), &base) != 0) { + goto read_fail; + } + if ((base & PAGE_OFFSET_MASK) != 0) { + goto read_fail; + } + int len; + if (copy_from_user((va_t)esi + sizeof(va_t), sizeof(int), &len) != 0) { + goto read_fail; + } + if ((len & PAGE_OFFSET_MASK) != 0) { + goto read_fail; + } + + process_t* p = get_current()->process; + mutex_lock(&p->mm_lock); + int n_pages = len / PAGE_SIZE; + pa_t paddr = alloc_user_pages(n_pages); + if (paddr == 0) { + goto alloc_segment_fail; + } + if (add_region(p, base, n_pages, paddr, 1) != 0) { + goto add_region_fail; + } + + int i = 0; + int offset = 0; + /* file page table one entry per loop */ + pa_t pt_pa = find_or_create_pt(p, base); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + do { + offset = i * PAGE_SIZE; + /* step to next page table */ + int pt_index = get_pt_index(base + offset); + if (pt_index == 0) { + pt_pa = find_or_create_pt(p, base + offset); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + } + + int old_if = save_clear_if(); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + (*pt)[pt_index] = make_pte(paddr + offset, 0, PTE_USER, PTE_RW, 0); + restore_if(old_if); + invlpg(base + offset); + } while (++i < n_pages); + mutex_unlock(&p->mm_lock); + f->eax = 0; + return; + +add_pt_fail: + /* page tables are reachable from page directory so no need to free them */ + vector_pop(&p->regions); +add_region_fail: + free_user_pages(paddr, n_pages); +alloc_segment_fail: + mutex_unlock(&p->mm_lock); +read_fail: + f->eax = (reg_t)-1; +} + +/** + * @brief remove_pages() syscall handler + * @param f saved regs + */ +void sys_remove_pages_real(stack_frame_t* f) { + process_t* p = get_current()->process; + mutex_lock(&p->mm_lock); + va_t base = (va_t)f->esi; + int i, j, n = vector_size(&p->regions); + for (i = 0; i < n; i++) { + region_t* r = (region_t*)vector_at(&p->regions, i); + if (base == r->addr) { + int n_pages = r->size / PAGE_SIZE; + j = 0; + int offset = 0; + pa_t pt_pa = find_or_create_pt(p, base); + do { + offset = j * PAGE_SIZE; + int pt_index = get_pt_index(base + offset); + if (pt_index == 0) { + pt_pa = find_or_create_pt(p, base + offset); + } + + int old_if = save_clear_if(); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + (*pt)[pt_index] = BAD_PDE; + restore_if(old_if); + invlpg(base + offset); + } while (++j < n_pages); + + free_user_pages(r->paddr, r->size / PAGE_SIZE); + vector_remove(&p->regions, i); + mutex_unlock(&p->mm_lock); + f->eax = 0; + return; + } + } + /* no such region */ + mutex_unlock(&p->mm_lock); + f->eax = (reg_t)-1; +} diff --git a/kern/syscall_misc.c b/kern/syscall_misc.c new file mode 100644 index 0000000..4c94513 --- /dev/null +++ b/kern/syscall_misc.c @@ -0,0 +1,169 @@ +/** @file syscall_misc.c + * + * @brief miscellaneous syscalls. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief misbehave() syscall handler + * @param f saved regs + */ +void sys_misbehave_real(stack_frame_t* f) { + f->eax = 0; +} + +/** + * @brief all other syscalls handler + * @param f saved regs + */ +void sys_enosys_real(stack_frame_t* f) { + f->eax = (reg_t)-1; +} + +/** + * @brief halt() syscall handler + * @param f saved regs + */ +void sys_halt_real(stack_frame_t* f) { + sim_halt(); + hlt(); +} + +/** + * @brief read the "." file to user buf + * @param buf buffer + * @param count size + * @param offset offset + * @return number of bytes read, or -1 on failure + */ +static reg_t read_dot_file(va_t buf, int count, int offset); + +/** + * @brief readfile() syscall handler + * @param f saved regs + */ +void sys_readfile_real(stack_frame_t* f) { + reg_t esi = f->esi; + va_t pfilename, buf; + int count, offset; + if (copy_from_user((va_t)esi, sizeof(va_t), &pfilename) != 0) { + goto read_arg_fail; + } + if (copy_from_user((va_t)(esi + sizeof(va_t)), sizeof(va_t), &buf) != 0) { + goto read_arg_fail; + } + if (copy_from_user((va_t)(esi + 2 * sizeof(va_t)), sizeof(int), &count) != + 0) { + goto read_arg_fail; + } + if (copy_from_user((va_t)(esi + 3 * sizeof(va_t)), sizeof(int), &offset) != + 0) { + goto read_arg_fail; + } + if (count < 0 || offset < 0) { + goto read_arg_fail; + } + char* filename = copy_string_from_user(pfilename, MAX_EXECNAME_LEN); + if (filename == NULL) { + goto read_arg_fail; + } + if (strcmp(filename, ".") == 0) { + free(filename); + f->eax = read_dot_file(buf, count, offset); + return; + } + file_t* fp = find_file(filename); + if (fp == NULL) { + goto no_such_file; + } + if (offset > fp->execlen) { + goto offset_too_big; + } + int size = fp->execlen - offset; + if (count < size) { + size = count; + } + if (copy_to_user(buf, size, (void*)(fp->execbytes + offset)) != 0) { + goto bad_buffer; + } + f->eax = (reg_t)size; + return; + +bad_buffer: +offset_too_big: +no_such_file: + free(filename); +read_arg_fail: + f->eax = (reg_t)-1; + return; +} + +static reg_t read_dot_file(va_t buf, int count, int offset) { + file_t* fp; + int i = 0; + int cur = 0; + int written = 0, left = count; + while (i < exec2obj_userapp_count && left > 0) { + fp = &exec2obj_userapp_TOC[i]; + int len = strlen(fp->execname) + 1; + if (cur + len <= offset) { + /* before offset */ + cur += len; + i++; + continue; + } + int size = len; + const char* start = fp->execname; + /* write this entry to buffer */ + if (cur < offset) { + size -= (offset - cur); + start += (offset - cur); + } + if (left < size) { + size = left; + } + if (copy_to_user((va_t)buf + written, size, (void*)start) != 0) { + return (reg_t)-1; + } + cur += len; + written += size; + left -= size; + i++; + } + /* write extra null byte */ + if (left != 0) { + char nul = '\0'; + if (copy_to_user((va_t)buf + written, 1, &nul) != 0) { + return (reg_t)-1; + } + written++; + } + return (reg_t)written; +} diff --git a/kern/syscall_process.c b/kern/syscall_process.c new file mode 100644 index 0000000..6007bcd --- /dev/null +++ b/kern/syscall_process.c @@ -0,0 +1,397 @@ +/** @file syscall_process.c + * + * @brief process management syscalls. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief gettid() syscall handler + * @param f saved regs + */ +void sys_gettid_real(stack_frame_t* f) { + f->eax = (reg_t)get_current()->rb_node.key; +} + +/** + * @brief copy a region of current process to a process + * @param p target process + * @param src source region + * @return 0 on success, or -1 on failure + */ +static int copy_region(process_t* p, region_t* src); + +/** + * @brief fork() syscall handler + * @param f saved regs + */ +void sys_fork_real(stack_frame_t* f) { + thread_t* current = get_current(); + process_t* p = current->process; + mutex_lock(&p->refcount_lock); + if (p->refcount != 1) { + /* reject multithread fork() */ + mutex_unlock(&p->refcount_lock); + goto fork_multiple_threads; + } + mutex_unlock(&p->refcount_lock); + thread_t* t = create_empty_process(); + if (t == NULL) { + goto create_thread_fail; + } + int tid = alloc_tid(); + t->process->pid = t->rb_node.key = tid; + int i, n = vector_size(&p->regions); + for (i = 0; i < n; i++) { + int result = + copy_region(t->process, (region_t*)vector_at(&p->regions, i)); + if (result != 0) { + goto copy_region_fail; + } + } + t->esp3 = current->esp3; + t->eip3 = current->eip3; + t->swexn_arg = current->swexn_arg; + t->eip0 = current->eip0; + + t->kernel_esp -= sizeof(stack_frame_t); + stack_frame_t* frame = (stack_frame_t*)t->kernel_esp; + *frame = *f; + frame->eax = 0; /* child process will get 0 from fork() */ + + t->kernel_esp -= sizeof(yield_frame_t); + yield_frame_t* yf = (yield_frame_t*)t->kernel_esp; + yf->eflags = DEFAULT_EFLAGS; + yf->raddr = (reg_t)return_to_user; + + t->process->parent = p; + mutex_lock(&p->wait_lock); + queue_insert_head(&p->live_childs, &t->process->sible_link); + p->nchilds++; + mutex_unlock(&p->wait_lock); + add_thread(t); + int old_if = spl_lock(&ready_lock); + insert_ready_tail(t); + spl_unlock(&ready_lock, old_if); + f->eax = (reg_t)tid; + return; + +copy_region_fail: + destroy_thread(t); +create_thread_fail: + f->eax = (reg_t)-1; + return; + +fork_multiple_threads: + f->eax = (reg_t)-2; + return; +} + +static int copy_region(process_t* p, region_t* src) { + process_t* cur_p = get_current()->process; + int n_pages = src->size / PAGE_SIZE; + pa_t paddr = alloc_user_pages(n_pages); + if (paddr == 0) { + goto alloc_segment_fail; + } + if (add_region(p, src->addr, n_pages, paddr, src->is_rw) != 0) { + goto add_region_fail; + } + + int rw = (src->is_rw ? PTE_RW : PTE_RO); + int i = 0; + int offset = 0; + /* file page table one entry per loop */ + pa_t dst_pt_pa = find_or_create_pt(p, src->addr); + if (dst_pt_pa == BAD_PA) { + goto add_pt_fail; + } + pa_t src_pt_pa = find_or_create_pt(cur_p, src->addr); + do { + offset = i * PAGE_SIZE; + /* step to next page table */ + int pt_index = get_pt_index(src->addr + offset); + if (pt_index == 0) { + dst_pt_pa = find_or_create_pt(p, src->addr + offset); + if (dst_pt_pa == BAD_PA) { + goto add_pt_fail; + } + src_pt_pa = find_or_create_pt(cur_p, src->addr); + } + + int old_if = save_clear_if(); + /* check if source page is never accessed */ + page_table_t* src_pt = (page_table_t*)map_phys_page(src_pt_pa, NULL); + if (((*src_pt)[pt_index] & (PTE_PRESENT << PTE_P_SHIFT)) != 0) { + /* need to copy non zero page */ + page_table_t* dst_pt = + (page_table_t*)map_phys_page(dst_pt_pa, NULL); + (*dst_pt)[pt_index] = + make_pte(paddr + offset, 0, PTE_USER, rw, PTE_PRESENT); + char* page = (char*)map_phys_page(paddr + offset, NULL); + memcpy(page, (char*)(src->addr + offset), PAGE_SIZE); + } else { + /* source page is waiting for ZFOD, so dest page will also ZFOD */ + page_table_t* dst_pt = + (page_table_t*)map_phys_page(dst_pt_pa, NULL); + (*dst_pt)[pt_index] = make_pte(paddr + offset, 0, PTE_USER, rw, 0); + } + restore_if(old_if); + } while (++i < n_pages); + return 0; + +add_pt_fail: + /* page tables are reachable from page directory so no need to free them */ + vector_pop(&p->regions); +add_region_fail: + free_user_pages(paddr, n_pages); +alloc_segment_fail: + return -1; +} + +/** + * @brief task_vanish() syscall handler + * @param f saved regs + */ +void sys_task_vanish_real(stack_frame_t* f) { + process_t* p = get_current()->process; + p->exit_value = (int)f->esi; + mutex_lock(&p->refcount_lock); + queue_t *node = p->threads, *end = p->threads; + do { + /* send a pending exit to all other threads, + * blocked threads will exit when the thread blocking it exits + * sleeping threads will exit when timer is reached + * threads waiting for input will exit after getting input + */ + thread_t* t = queue_data(node, thread_t, process_link); + t->pending_exit = 1; + int old_if = spl_lock(&t->status_lock); + /* wakeup descheduled threads */ + if (t->status == THREAD_DESCHEDULED) { + int old_if2 = spl_lock(&ready_lock); + insert_ready_tail(t); + spl_unlock(&ready_lock, old_if2); + } + spl_unlock(&t->status_lock, old_if); + node = node->next; + } while (node != end); + mutex_unlock(&p->refcount_lock); + kill_current(); +} + +/** + * @brief set_status() syscall handler + * @param f saved regs + */ +void sys_set_status_real(stack_frame_t* f) { + get_current()->process->exit_value = (int)f->esi; +} + +/** + * @brief exec() syscall handler + * @param f saved regs + */ +void sys_exec_real(stack_frame_t* f) { + thread_t* current = get_current(); + process_t* p = current->process; + mutex_unlock(&p->refcount_lock); + if (p->refcount != 1) { + /* reject multithread exec() */ + mutex_unlock(&p->refcount_lock); + goto exec_multiple_threads; + } + mutex_unlock(&p->refcount_lock); + reg_t esi = f->esi; + va_t pexe; + if (copy_from_user((va_t)esi, sizeof(va_t), &pexe) != 0) { + goto read_exe_fail; + } + char* exe = copy_string_from_user(pexe, MAX_EXECNAME_LEN); + if (exe == NULL) { + goto read_exe_fail; + } + va_t pargv; + if (copy_from_user((va_t)esi + sizeof(va_t), sizeof(va_t), &pargv) != 0) { + goto read_argv_fail; + } + int argc = 0; + while (1) { + if (argc > MAX_NUM_ARG) { + goto read_argv_fail; + } + va_t argv; + if (copy_from_user(pargv + argc * sizeof(va_t), sizeof(va_t), &argv) != + 0) { + goto read_argv_fail; + } + if (argv == 0) { + break; + } + argc++; + } + char** argv_buf = smalloc(argc * sizeof(char*)); + if (argv_buf == NULL) { + goto read_argv_fail; + } + int i; + for (i = 0; i < argc; i++) { + argv_buf[i] = copy_string_from_user(((va_t*)pargv)[i], MAX_ARG_LEN); + if (argv_buf[i] == NULL) { + goto read_argv_buf_fail; + } + } + + /* we create a new process and swap to it so we can recover if process + * creation fails + */ + thread_t* t = + create_process(current->rb_node.key, exe, argc, (const char**)argv_buf); + if (t == NULL) { + goto create_process_fail; + } + for (i = argc - 1; i >= 0; i--) { + free(argv_buf[i]); + } + sfree(argv_buf, argc * sizeof(char*)); + free(exe); + swap_process_inplace(t); + int old_if = spl_lock(&ready_lock); + insert_ready_tail(t); + spl_unlock(&ready_lock, old_if); + kill_current(); + +create_process_fail: +read_argv_buf_fail: + for (i--; i >= 0; i--) { + free(argv_buf[i]); + } + sfree(argv_buf, argc * sizeof(char*)); +read_argv_fail: + free(exe); +read_exe_fail: + f->eax = (reg_t)-1; + return; + +exec_multiple_threads: + f->eax = (reg_t)-2; + return; +} + +/** + * @brief wait() syscall handler + * @param f saved regs + */ +void sys_wait_real(stack_frame_t* f) { + /* it may be possible that pstatus is not valid when calling wait() and then + * become valid after other thread allocates pages so we do not do check + * now + */ + va_t pstatus = f->esi; + thread_t* current = get_current(); + process_t* p = current->process; + /* it is possible that a process create multiple child processes and then + * create multiple threads and then call wait() in these threads, so we need + * to handle this case and count the waiting threads + */ + mutex_lock(&p->wait_lock); + if (p->nchilds <= p->nwaiters) { + /* Pigeonhole principle prevents us to get a child in future even if + * there are some childs + */ + mutex_unlock(&p->wait_lock); + goto no_child_to_wait; + } + p->nwaiters++; + while (p->dead_childs == NULL) { + cv_wait(&p->wait_cv, &p->wait_lock); + } + process_t* child = queue_data(p->dead_childs, process_t, sible_link); + /* copy the exit status first so we do not need to put the child back to the + * queue if copy fails + */ + if (pstatus != 0 && + copy_to_user(pstatus, sizeof(int), &child->exit_value) != 0) { + p->nwaiters--; + mutex_unlock(&p->wait_lock); + goto bad_pstatus; + } + queue_remove_head(&p->dead_childs); + p->nchilds--; + p->nwaiters--; + mutex_unlock(&p->wait_lock); + f->eax = (reg_t)child->pid; + sfree(child, sizeof(process_t)); + return; + +bad_pstatus: + f->eax = (reg_t)-1; + return; + +no_child_to_wait: + f->eax = (reg_t)-2; + return; +} + +/** + * @brief sleep() syscall handler + * @param f saved regs + */ +void sys_sleep_real(stack_frame_t* f) { + int dt = (int)f->esi; + if (dt <= 0) { + f->eax = (reg_t)dt; + return; + } + thread_t* current = get_current(); + heap_node_t node; + node.key = ticks + dt; + node.value = (void*)current; + int old_if = spl_lock(&timer_lock); + if (heap_insert(&timers, &node) != 0) { + spl_unlock(&timer_lock, old_if); + f->eax = (reg_t)-2; + return; + } + int old_if2 = spl_lock(&ready_lock); + current->status = THREAD_SLEEPING; + thread_t* t = select_next(); + spl_unlock(&ready_lock, old_if2); + yield_to_spl_unlock(t, &timer_lock, old_if); + f->eax = 0; + return; +} + +/** + * @brief get_ticks() syscall handler + * @param f saved regs + */ +void sys_get_ticks_real(stack_frame_t* f) { + f->eax = (reg_t)ticks; + return; +} diff --git a/kern/syscall_thread.c b/kern/syscall_thread.c new file mode 100644 index 0000000..d8984b0 --- /dev/null +++ b/kern/syscall_thread.c @@ -0,0 +1,274 @@ +/** @file syscall_thread.c + * + * @brief thread management syscalls. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief thread_fork() syscall handler + * @param f saved regs + */ +void sys_thread_fork_real(stack_frame_t* f) { + thread_t* current = get_current(); + process_t* p = current->process; + thread_t* t = smalloc(sizeof(thread_t)); + if (t == NULL) { + goto alloc_tcb_fail; + } + t->stack = smemalign(PAGE_SIZE, K_STACK_SIZE); + if (t->stack == NULL) { + goto alloc_thread_stack_fail; + } + int tid = alloc_tid(); + t->rb_node.key = tid; + t->status = THREAD_DEAD; + t->status_lock = SPL_INIT; + t->pending_exit = current->pending_exit; + t->esp3 = current->esp3; + t->eip3 = current->eip3; + t->df3 = current->df3; + t->swexn_arg = current->swexn_arg; + t->esp0 = t->kernel_esp = (reg_t)&t->stack[K_STACK_SIZE]; + t->eip0 = current->eip0; + + t->kernel_esp -= sizeof(stack_frame_t); + stack_frame_t* frame = (stack_frame_t*)t->kernel_esp; + *frame = *f; + frame->eax = 0; + + t->kernel_esp -= sizeof(yield_frame_t); + yield_frame_t* yf = (yield_frame_t*)t->kernel_esp; + yf->eflags = DEFAULT_EFLAGS; + yf->raddr = (reg_t)return_to_user; + + t->process = p; + mutex_lock(&p->refcount_lock); + p->refcount++; + queue_insert_tail(&p->threads, &t->process_link); + mutex_unlock(&p->refcount_lock); + add_thread(t); + int old_if = spl_lock(&ready_lock); + insert_ready_tail(t); + spl_unlock(&ready_lock, old_if); + f->eax = (reg_t)tid; + return; + +alloc_thread_stack_fail: + sfree(t, sizeof(thread_t)); +alloc_tcb_fail: + f->eax = (reg_t)-1; +} + +/** + * @brief deschedule() syscall handler + * @param f saved regs + */ +void sys_deschedule_real(stack_frame_t* f) { + va_t preject = (va_t)f->esi; + int reject; + thread_t* current = get_current(); + int old_if = spl_lock(¤t->status_lock); + if (copy_from_user(preject, sizeof(int), &reject) != 0) { + spl_unlock(¤t->status_lock, old_if); + f->eax = (reg_t)-1; + return; + } + if (reject != 0 || current->pending_exit != 0) { + spl_unlock(¤t->status_lock, old_if); + f->eax = (reg_t)0; + return; + } + int old_if2 = spl_lock(&ready_lock); + current->status = THREAD_DESCHEDULED; + thread_t* t = select_next(); + spl_unlock(&ready_lock, old_if2); + /* release status_lock last to make sure nobody make us runnable before + * deschedule + */ + yield_to_spl_unlock(t, ¤t->status_lock, old_if); + f->eax = (reg_t)0; + return; +} + +/** + * @brief make_runnable() syscall handler + * @param f saved regs + */ +void sys_make_runnable_real(stack_frame_t* f) { + int tid = (int)f->esi; + mutex_lock(&threads_lock); + thread_t* t = find_thread(tid); + if (t == NULL) { + mutex_unlock(&threads_lock); + f->eax = (reg_t)-2; + return; + } + int old_if = spl_lock(&t->status_lock); + /* we must hold threads_lock before making sure t is descheduled, otherwise + * if t is running/ready, t can be freed at any time + */ + if (t->status != THREAD_DESCHEDULED) { + spl_unlock(&t->status_lock, old_if); + mutex_unlock(&threads_lock); + f->eax = (reg_t)-3; + return; + } + mutex_unlock(&threads_lock); + /* must lock ready lock before setting status to READY otherwise yield() may + * yield to it before we insert it into ready queue + */ + int old_if2 = spl_lock(&ready_lock); + t->status = THREAD_READY; + insert_ready_tail(t); + spl_unlock(&ready_lock, old_if2); + spl_unlock(&t->status_lock, old_if); + f->eax = (reg_t)0; + return; +} + +/** + * @brief vanish() syscall handler + * @param f saved regs + */ +void sys_vanish_real(stack_frame_t* f) { + kill_current(); +} + +/** + * @brief yield() syscall handler + * @param f saved regs + */ +void sys_yield_real(stack_frame_t* f) { + int tid = (int)f->esi; + if (tid == -1) { + int old_if = spl_lock(&ready_lock); + insert_ready_tail(get_current()); + thread_t* t = select_next(); + yield_to_spl_unlock(t, &ready_lock, old_if); + f->eax = (reg_t)0; + return; + } + mutex_lock(&threads_lock); + thread_t* t = find_thread(tid); + if (t == NULL) { + mutex_unlock(&threads_lock); + f->eax = (reg_t)-2; + return; + } + /* we must hold threads_lock and ready_lock before making sure t is ready + * if we do not have threads_lock, t may be freed + * if we do not have ready_lock, t may be turned from ready to running by + * other processors + */ + int old_if = spl_lock(&ready_lock); + if (t->status == THREAD_RUNNING) { + /* t is running or other processor, no need to yield */ + t = select_next(); + } else if (t->status == THREAD_READY) { + queue_detach(&ready, &t->sched_link); + } else { + spl_unlock(&ready_lock, old_if); + mutex_unlock(&threads_lock); + f->eax = (reg_t)-1; + return; + } + /* if we are sure t is ready and remove it from ready queue, it will not + * suddenly run so we can make sure t will not be freed + */ + mutex_unlock(&threads_lock); + insert_ready_tail(get_current()); + yield_to_spl_unlock(t, &ready_lock, old_if); + f->eax = (reg_t)0; + return; +} + +/* eflags fields that are allowed to be changed by user */ +#define EFLAGS_USER_MASK \ + (EFL_CF | EFL_PF | EFL_AF | EFL_ZF | EFL_SF | EFL_TF | EFL_DF | EFL_OF | \ + EFL_RF) + +/** + * @brief swexn() syscall handler + * @param f saved regs + */ +void sys_swexn_real(stack_frame_t* f) { + thread_t* current = get_current(); + reg_t args[4]; /* esp3, eip3, arg, ureg */ + reg_t esi = f->esi; + if (copy_from_user(esi, 4 * sizeof(reg_t), args) != 0) { + goto read_arg_fail; + } + reg_t esp3 = args[0], eip3 = args[1], pureg = args[3]; + if (esp3 != 0 && eip3 != 0) { + /* for unlcear "stack end" definition */ + esp3 = (esp3 & (~(sizeof(va_t) - 1))); + /* check first, will register after successful ureg copy */ + if (eip3 < USER_MEM_START || eip3 >= DEFAULT_STACK_END || + esp3 < USER_MEM_START || esp3 >= DEFAULT_STACK_END) { + goto bad_user_entry; + } + } + if (pureg != 0) { + ureg_t ureg; + if (copy_from_user((va_t)pureg, sizeof(ureg_t), &ureg) != 0) { + goto bad_user_entry; + } + /* segment regs are ignored since they cannot be changed */ + /* only user fields in eflags are allowed to be changed */ + if ((ureg.eflags & (~EFLAGS_USER_MASK)) != DEFAULT_EFLAGS) { + goto bad_user_entry; + } + f->eip = ureg.eip; + f->eflags = ureg.eflags; + f->esp = ureg.esp; + f->eax = ureg.eax; + f->ecx = ureg.ecx; + f->edx = ureg.edx; + f->ebx = ureg.ebx; + f->ebp = ureg.ebp; + f->esi = ureg.esi; + f->edi = ureg.edi; + } else { + f->eax = 0; + } + if (esp3 != 0 && eip3 != 0) { + current->esp3 = esp3; + current->eip3 = eip3; + current->swexn_arg = args[2]; + } else { + current->eip3 = 0; + } + /* clear swexn flag after success swexn call */ + current->df3 = 0; + return; + +bad_user_entry: + f->eax = (reg_t)-2; + return; + +read_arg_fail: + f->eax = (reg_t)-1; + return; +} diff --git a/kern/timer.c b/kern/timer.c new file mode 100644 index 0000000..7f39f06 --- /dev/null +++ b/kern/timer.c @@ -0,0 +1,74 @@ +/** @file timer.c + * + * @brief timer functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +unsigned int ticks = 0; + +spl_t timer_lock = SPL_INIT; + +heap_t timers; + +/* we want a 2ms thread switch but since sometimes interrupts are disabled, we + * set a higher rate to compensate this + */ +#define TIMER_FREQ 1000 + +void timer_init() { + int counter = TIMER_RATE / TIMER_FREQ; + outb(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE); + outb(TIMER_PERIOD_IO_PORT, counter & 0xFF); + outb(TIMER_PERIOD_IO_PORT, (counter >> 8) & 0xFF); + if (heap_init(&timers) != 0) { + panic("no space to initialize timer heap"); + } +} + +/** + * @brief check expired timers + */ +static void check_timers() { + int old_if = spl_lock(&timer_lock); + heap_node_t* node; + while ((node = heap_peak(&timers)) != NULL) { + if (node->key > ticks) { + break; + } + thread_t* t = (thread_t*)node->value; + heap_pop(&timers); + int old_if2 = spl_lock(&ready_lock); + insert_ready_tail(t); + spl_unlock(&ready_lock, old_if2); + } + spl_unlock(&timer_lock, old_if); +} + +void timer_handler_real() { + pic_acknowledge(TIMER_IRQ); + ticks++; + check_timers(); + int old_if = spl_lock(&ready_lock); + thread_t* current = get_current(); + if (current != get_idle()) { + insert_ready_tail(current); + } + thread_t* t = select_next(); + yield_to_spl_unlock(t, &ready_lock, old_if); +} diff --git a/kern/usermem.c b/kern/usermem.c new file mode 100644 index 0000000..717cdbe --- /dev/null +++ b/kern/usermem.c @@ -0,0 +1,153 @@ +/** @file usermem.c + * + * @brief userspace r/w functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +/** + * @brief try to read a byte from userspace + * @param addr address + * @param output output byte if successful + * @return 0 on success, jump to usermem_fail on failure + */ +int try_read(va_t addr, char* output); +/** + * @brief try to write a byte to userspace + * @param addr address + * @param c byte to write + * @return 0 on success, jump to usermem_fail on failure + */ +int try_write(va_t addr, char c); + +/** + * @brief tell the calling function the r/w failed + * @return -1 + */ +int usermem_fail(); + +/** + * @brief setup fault handler before r/w + * @return old fault handler + */ +static reg_t usermem_setup() { + thread_t* current = get_current(); + reg_t old_eip0 = current->eip0; + current->eip0 = (reg_t)usermem_fail; + return old_eip0; +} + +/** + * @brief restore old fault handler + * @param old_eip0 old fault handler + */ +static void usermem_finish(reg_t old_eip0) { + get_current()->eip0 = old_eip0; +} + +int copy_from_user(va_t addr, int size, void* buf) { + va_t end = addr + size; + if (addr < USER_MEM_START || end < addr || end >= DEFAULT_STACK_END) { + return -1; + } + reg_t old_eip0 = usermem_setup(); + int i, result = 0; + for (i = 0; i < size; i++) { + if (try_read(addr + i, (char*)buf + i) != 0) { + result = -1; + break; + } + } + usermem_finish(old_eip0); + return result; +} + +int copy_to_user(va_t addr, int size, void* buf) { + va_t end = addr + size; + if (addr < USER_MEM_START || end < addr || end >= DEFAULT_STACK_END) { + return -1; + } + reg_t old_eip0 = usermem_setup(); + int i, result = 0; + for (i = 0; i < size; i++) { + if (try_write(addr + i, *((char*)buf + i)) != 0) { + result = -1; + break; + } + } + usermem_finish(old_eip0); + return result; +} + +char* copy_string_from_user(va_t addr, int maxlen) { + if (addr < USER_MEM_START || addr >= DEFAULT_STACK_END) { + return NULL; + } + if (DEFAULT_STACK_END - addr < maxlen) { + maxlen = DEFAULT_STACK_END - addr; + } + reg_t old_eip0 = usermem_setup(); + int len = 0, buflen = 3 * sizeof(int); + char* buf = malloc(buflen); + char c; + if (buf == NULL) { + goto read_string_finished; + } + while (1) { + if (len >= maxlen || try_read(addr + len, &c) != 0) { + free(buf); + buf = NULL; + break; + } + + buf[len++] = c; + if (c == '\0') { + break; + } + + if (len >= buflen) { + buflen <<= 1; + char* result = realloc(buf, buflen); + if (result == NULL) { + free(buf); + buf = NULL; + break; + } + buf = result; + } + } +read_string_finished: + usermem_finish(old_eip0); + return buf; +} + +int print_buf_from_user(va_t addr, int len) { + va_t end = addr + len; + if (addr < USER_MEM_START || end < addr || end >= DEFAULT_STACK_END) { + return -1; + } + reg_t old_eip0 = usermem_setup(); + int i, result = 0; + char c; + for (i = 0; i < len; i++) { + if (try_read(addr + i, &c) != 0) { + result = -1; + break; + } + putbyte(c); + } + usermem_finish(old_eip0); + return result; +} diff --git a/kern/usermem_asm.S b/kern/usermem_asm.S new file mode 100644 index 0000000..0eee6f8 --- /dev/null +++ b/kern/usermem_asm.S @@ -0,0 +1,35 @@ +/** @file usermem_asm.S + * + * @brief userspace r/w functions. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +.text + +.global try_read +.type try_read, %function +try_read: + mov 0x4(%esp), %eax + mov 0x8(%esp), %esi + mov (%eax), %al + mov %al, (%esi) + xor %eax, %eax + ret + +.global try_write +.type try_write, %function +try_write: + mov 0x4(%esp), %eax + mov 0x8(%esp), %edx + mov %dl, (%eax) + xor %eax, %eax + ret + +/* unsuccessful r/w will jump to this function and we return 1 */ +.global usermem_fail +.type usermem_fail, %function +usermem_fail: + mov $0xffffffff, %eax + ret diff --git a/spec/common_kern.h b/spec/common_kern.h new file mode 100644 index 0000000..0cd862f --- /dev/null +++ b/spec/common_kern.h @@ -0,0 +1,56 @@ +#ifndef _SPEC_COMMON_KERN_H_ +#define _SPEC_COMMON_KERN_H_ + +/*********************************************************************/ +/* */ +/* Interface between Multiboot and our kernel */ +/* */ +/*********************************************************************/ + +/** @brief Query whether we are running as a hypervisor guest. + * + * @return True if we are a guest. + */ +int hv_isguest(void); + +/** @brief Fetch virtual-address cap set by hypervisor. + * + * @return Largest virtual address we are allowed to use. + */ +void *hv_maxvaddr(void); + +/** @brief Return total number of frames (each of PAGE_SIZE bytes) + * that our machine is currently configured with. + * + * @return Frame count. + */ +int machine_phys_frames(void); + +#include + + /** @brief User kernel entrypoint + * + * @param mbinfo The kernel's multiboot information structure. + * @param argc Argument count, as parsed from multiboot. + * @param argv Argument vector, as parsed from multiboot. + * @param envp Environment, as parsed from multiboot. + * + * @pre malloc_lmm will have been initialized, stripped of regions that + * are potentially hazardous, and bounded between 1 and 16M. + * + * @note If you plan to write your own allocator for space, you should + * still treat LMM as the official mechanism of getting physical + * frames in the kernel region, unless you are planning to parse + * the multiboot information and/or e820 yourself. + */ +int kernel_main(mbinfo_t *mbinfo, int argc, char **argv, char **envp); + +/*********************************************************************/ +/* */ +/* Kernel memory layout requirements */ +/* */ +/*********************************************************************/ + +#define USER_MEM_START 0x01000000 + +#endif /* _SPEC_COMMON_KERN_H_ */ diff --git a/spec/compiler.h b/spec/compiler.h new file mode 100644 index 0000000..b626f1a --- /dev/null +++ b/spec/compiler.h @@ -0,0 +1,23 @@ +/** @file spec/compiler.h + * @brief Useful macros. Inspired by Linux compiler*.h and kernel.h. + * @author bblum S2011 + */ + +#ifndef _SPEC_COMPILER_H +#define _SPEC_COMPILER_H + +/* Function annotations */ +#ifndef NORETURN +#define NORETURN __attribute__((__noreturn__)) +#endif + +#define MUST_CHECK __attribute__((__warn_unused_result__)) + +/* Force a compilation error if condition is false */ +#define STATIC_ZERO_ASSERT(condition) switch(0){case 0:case (condition):;} +#define STATIC_NULL_ASSERT(condition) STATIC_ZERO_ASSERT(condition) + +/* Force a compilation error if condition is false */ +#define STATIC_ASSERT(condition) STATIC_ZERO_ASSERT(condition) + +#endif /* !_SPEC_COMPILER_H */ diff --git a/spec/contracts.h b/spec/contracts.h new file mode 100644 index 0000000..251caad --- /dev/null +++ b/spec/contracts.h @@ -0,0 +1,32 @@ +/* Debugging with contracts; simulating cc0 -d + * Enable with gcc -DDEBUG ... + * + * 15-122 Principles of Imperative Computation + * Frank Pfenning + */ + +#include + +/* Unlike typical header files, "contracts.h" may be + * included multiple times, with and without DEBUG defined. + * For this to succeed we first undefine the macros in + * question in order to avoid a redefinition warning. + */ + +#undef ASSERT +#undef REQUIRES +#undef ENSURES + +#ifdef DEBUG + +#define ASSERT(COND) assert(COND) +#define REQUIRES(COND) assert(COND) +#define ENSURES(COND) assert(COND) + +#else + +#define ASSERT(COND) ((void)0) +#define REQUIRES(COND) ((void)0) +#define ENSURES(COND) ((void)0) + +#endif diff --git a/spec/hvcall.h b/spec/hvcall.h new file mode 100644 index 0000000..be877b4 --- /dev/null +++ b/spec/hvcall.h @@ -0,0 +1,135 @@ +/** @file hvcall.h + * + * Prototypes for PebPeb hypervisor calls. + * + * @author jwise + * @author de0u + * @author relong + */ + +#ifndef _HVCALL_H +#define _HVCALL_H + +/* vIDT slots match regular x86-32 numbers from x86/idt.h, plus these */ +#define HV_TICKBACK 0x20 /**< vIDT slot for virtual timer interrupt */ +#define HV_KEYBOARD 0x21 /**< vIDT slot for virtual keyboard interrupt */ + +#define HV_MAGIC 0xC001C0DE /**< hv_magic() value for v2 of PebPeb API */ +#define HV_SETIDT_PRIVILEGED 1 +#define HV_PRINT_MAX 410 + +#ifdef ASSEMBLER +#define GUEST_LAUNCH_EAX 0x15410DE0 /**< Value for %EAX at guest launch */ +#else /* ASSEMBLER */ +#define GUEST_LAUNCH_EAX 0x15410DE0U /**< Value for %EAX at guest launch */ +#endif /* ASSEMBLER */ +#define GUEST_CRASH_STATUS 0xDEADC0DE /**< For simulated hv_exit() */ +#define GUEST_INTERRUPT_UMODE 0x13370000 /**< Guest was interrupted in user mode */ +#define GUEST_INTERRUPT_KMODE 0x00001337 /**< Guest was interrupted in kernel mode */ + +#ifndef ASSEMBLER + +#ifndef NORETURN +#define NORETURN __attribute__((__noreturn__)) +#endif + +/** @brief verify we are running under a v2 PebPeb hypervisor + * @return HV_MAGIC + */ +unsigned int hv_magic(void); + +/** @brief Cease execution and pass status to parent task + * @param status Status code to pass to parent task + */ +void hv_exit(int status) NORETURN; + +/** @brief Atomically activate a new privilege level/execution context + * @param eip New value for %eip + * @param eflags New value for %eflags + * @param esp New value for %esp + * @param esp0 If zero, IRET into guest-kernel mode; + * else, remember virtual %esp0 for later and IRET + * into guest-user mode + * @param eax New value for %eax + * + * @note If eflags is invalid, the hypervisor will crash the guest + * @note eip, esp, esp0 addresses are guest-virtual + */ +void hv_iret(void *eip, unsigned int eflags, void *esp, void *esp0, unsigned int eax); + +/** @brief Install a virtual interrupt handler + * @param irqno IDT slot index + * @param eip Address of first instruction of handler + * @param privileged if non-zero only kernel access, else user access permitted + * @note If a slot's eip value is zero when that event happens, the guest crashes + * @note When guest kernel launches, all slots have eip == 0 + * @note eip address is guest-virtual + * @note See HV_SETIDT_PRIVILEGED definition above + */ +void hv_setidt(int irqno, void *eip, int privileged); + +/** @brief Suspend delivery of virtual interrupts (not virtual exceptions) + */ +void hv_disable_interrupts(void); + +/** @brief Begin/resume delivery of virtual interrupts (not virtual exceptions) + */ +void hv_enable_interrupts(void); + +/** @brief Activate an address space + * @param pdbase Base of page directory + * @param wp If non-zero, guest kernel can't write into user-level + * read-only pages (see Intel's description of bit 16 of %cr0) + * @pre pdbase must be page-aligned + * @note pdbase address is guest-physical + */ +void hv_setpd(void *pdbase, int wp); + +/** @brief Re-validate/invalidate/update the mapping + * of one virtual-to-physical translation + * @param addr Base of page whose mapping status has changed + * @pre addr must be page-aligned + * @note addr address is guest-virtual + */ +void hv_adjustpg(void *addr); + +/** @brief Print to console + * @param len Count of bytes to print (must be less than HV_PRINT_MAX) + * @param buf Address of first byte to print + * @note buf address is guest-virtual + */ +void hv_print(int len, unsigned char *buf); + +/** @brief Change printing color + * @param color VGA color code + */ +void hv_cons_set_term_color(int color); + +/** @brief Set cursor position + * @param row Row cursor should be moved to + * @param col Column cursor should be moved to + */ +void hv_cons_set_cursor_pos(int row, int col); + +/** @brief Get cursor position + * @param rowp Pointer to where cursor row should be stored + * @param colp Pointer to where cursor column should be stored + * @note both addresses are guest-virtual + */ +void hv_cons_get_cursor_pos(int *rowp, int *colp); + +/** @brief Print to the console + * @param len Count of bytes to print (must be less than HV_PRINT_MAX) + * @param buf Address of first byte to print + * @param color VGA color code for printing this string + * @param row Row this string should be printed on + * @param col Column this string should be printed at + * @note This moves the cursor, changes the print color, prints, + * then restores the cursor position and print color. + * @note buf address is guest-virtual + */ +void hv_print_at(int len, unsigned char *buf, int row, int col, int color); + +#endif /* ASSEMBLER */ + +#endif /* _HVCALL_H */ diff --git a/spec/hvcall_int.h b/spec/hvcall_int.h new file mode 100644 index 0000000..cc00df4 --- /dev/null +++ b/spec/hvcall_int.h @@ -0,0 +1,49 @@ +/** @file hvcall_int.h + * + * Hypervisor call numbers + * + * @author jwise + */ + +#ifndef _HVCALL_INT_H +#define _HVCALL_INT_H + +/* Protocol: + * + * 1. Parameters on stack in "natural push order" + * 2. Operation number (HV_xxx_OP) in %eax + * 3. INT $HV_INT + */ + +#define HV_INT 0xDE + +#define HV_MAGIC_OP 0x00 +#define HV_EXIT_OP 0x01 +#define HV_IRET_OP 0x02 +#define HV_SETIDT_OP 0x03 +#define HV_DISABLE_OP 0x04 +#define HV_ENABLE_OP 0x05 +#define HV_SETPD_OP 0x06 +#define HV_ADJUSTPG_OP 0x07 +#define HV_PRINT_OP 0x08 +#define HV_SET_COLOR_OP 0x09 +#define HV_SET_CURSOR_OP 0x0A +#define HV_GET_CURSOR_OP 0x0B +#define HV_PRINT_AT_OP 0x0C + +/* The calls in here, INCLUSIVE, are promised not to be + * probed by any grading scripts; as such you are welcome + * to extend the spec by making use of these hvcall numbers + */ +#define HV_RESERVED_START 0x20 +#define HV_RESERVED_0 0x20 +#define HV_RESERVED_1 0x21 +#define HV_RESERVED_2 0x22 +#define HV_RESERVED_3 0x23 +#define HV_RESERVED_4 0x24 +#define HV_RESERVED_5 0x25 +#define HV_RESERVED_6 0x26 +#define HV_RESERVED_7 0x27 +#define HV_RESERVED_END 0x27 + +#endif /* _HVCALL_INT_H */ diff --git a/spec/limits.h b/spec/limits.h new file mode 100644 index 0000000..431d181 --- /dev/null +++ b/spec/limits.h @@ -0,0 +1,36 @@ +/** @file 410kern/inc/limits.h + * @author elly1 U2009 + * @brief Type size limits. + */ + +#ifndef LIMITS_H +#define LIMITS_H + +#define CHAR_BIT 8 + +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 + +#define UCHAR_MAX 255 + +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 + +#define USHRT_MAX 65535 + +#define INT_MIN ((signed int)0x80000000) +#define INT_MAX ((signed int)0x7fffffff) + +#define UINT_MAX ((unsigned int)0xffffffff) + +#define LONG_MIN ((signed long)0x80000000L) +#define LONG_MAX ((signed long)0x7FFFFFFFL) + +#define ULONG_MAX ((unsigned long)0xFFFFFFFFL) + +#define LLONG_MIN ((signed long long)0x8000000000000000LL) +#define LLONG_MAX ((signed long long)0x7FFFFFFFFFFFFFFFLL) + +#define ULLONG_MAX ((unsigned long long)0xFFFFFFFFFFFFFFFFLL) + +#endif /* !LIMITS_H */ diff --git a/spec/syscall.h b/spec/syscall.h new file mode 100644 index 0000000..a40fc60 --- /dev/null +++ b/spec/syscall.h @@ -0,0 +1,98 @@ +/* The 15-410 kernel. + * syscall.h + * + * Prototypes for the user-land C library interface + * to system calls. + * + */ + +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#ifndef NORETURN +#define NORETURN __attribute__((__noreturn__)) +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE 0x0001000 /* 4096 */ +#endif + +/* Life cycle */ +int fork(void); +int exec(char *execname, char *argvec[]); +void set_status(int status); +void vanish(void) NORETURN; +int wait(int *status_ptr); +void task_vanish(int status) NORETURN; + +/* Thread management */ +int gettid(void); +int yield(int pid); +int deschedule(int *flag); +int make_runnable(int pid); +unsigned int get_ticks(void); +int sleep(int ticks); + +/* Memory management */ +int new_pages(void * addr, int len); +int remove_pages(void * addr); + +/* Console I/O */ +int getchar(void); +int readline(int size, char *buf); +int print(int size, char *buf); +int set_term_color(int color); +int set_cursor_pos(int row, int col); +int get_cursor_pos(int *row, int *col); + +/* Color values for set_term_color() */ +#define FGND_BLACK 0x0 +#define FGND_BLUE 0x1 +#define FGND_GREEN 0x2 +#define FGND_CYAN 0x3 +#define FGND_RED 0x4 +#define FGND_MAG 0x5 +#define FGND_BRWN 0x6 +#define FGND_LGRAY 0x7 /* Light gray. */ +#define FGND_DGRAY 0x8 /* Dark gray. */ +#define FGND_BBLUE 0x9 /* Bright blue. */ +#define FGND_BGRN 0xA /* Bright green. */ +#define FGND_BCYAN 0xB /* Bright cyan. */ +#define FGND_PINK 0xC +#define FGND_BMAG 0xD /* Bright magenta. */ +#define FGND_YLLW 0xE +#define FGND_WHITE 0xF + +#define BGND_BLACK 0x00 +#define BGND_BLUE 0x10 +#define BGND_GREEN 0x20 +#define BGND_CYAN 0x30 +#define BGND_RED 0x40 +#define BGND_MAG 0x50 +#define BGND_BRWN 0x60 +#define BGND_LGRAY 0x70 /* Light gray. */ + +/* Miscellaneous */ +void halt(void); +int readfile(char *filename, char *buf, int count, int offset); + +/* "Special" */ +void misbehave(int mode); + +/* Project 4 F2010 */ +#include /* may be directly included by kernel guts */ +typedef void (*swexn_handler_t)(void *arg, ureg_t *ureg); +int swexn(void *esp3, swexn_handler_t eip, void *arg, ureg_t *newureg); + +/* Project 4 F2017 */ +int new_console(void); + +/* Previous API */ +/* +void exit(int status) NORETURN; +void task_exit(int status) NORETURN; +int cas2i_runflag(int tid, int *oldp, int ev1, int nv1, int ev2, int nv2); +int ls(int size, char *buf); +*/ + +#endif /* _SYSCALL_H */ diff --git a/spec/syscall_int.h b/spec/syscall_int.h new file mode 100644 index 0000000..aa0365d --- /dev/null +++ b/spec/syscall_int.h @@ -0,0 +1,69 @@ +/* The 15-410 reference kernel. + * syscall_int.h + * + * Prototypes for assembly language wrappers for the + * system call interface. + * + * Adam Chlipala (adamc) + * Jorge Vittes (jvittes) + * Zachary Anderson (zra) + */ + +#ifndef _SYSCALL_INT_H +#define _SYSCALL_INT_H + +#define FORK_INT 0x41 +#define EXEC_INT 0x42 +/* #define EXIT_INT 0x43 */ +#define WAIT_INT 0x44 +#define YIELD_INT 0x45 +#define DESCHEDULE_INT 0x46 +#define MAKE_RUNNABLE_INT 0x47 +#define GETTID_INT 0x48 +#define NEW_PAGES_INT 0x49 +#define REMOVE_PAGES_INT 0x4A +#define SLEEP_INT 0x4B +#define GETCHAR_INT 0x4C +#define READLINE_INT 0x4D +#define PRINT_INT 0x4E +#define SET_TERM_COLOR_INT 0x4F +#define SET_CURSOR_POS_INT 0x50 +#define GET_CURSOR_POS_INT 0x51 +#define THREAD_FORK_INT 0x52 +#define GET_TICKS_INT 0x53 +#define MISBEHAVE_INT 0x54 +#define HALT_INT 0x55 +/* #define LS_INT 0x56 */ +#define TASK_VANISH_INT 0x57 /* previously known as TASK_EXIT_INT */ +#define NEW_CONSOLE_INT 0x58 +#define SET_STATUS_INT 0x59 +#define VANISH_INT 0x60 +/* #define CAS2I_RUNFLAG_INT 0x61 */ +#define READFILE_INT 0x62 + +#define SWEXN_INT 0x74 + +/* The syscalls in here, INCLUSIVE, are promised not to be + * probed by any grading scripts; as such you are welcome + * to extend the spec by making use of these syscall numbers + */ +#define SYSCALL_RESERVED_START 0x80 +#define SYSCALL_RESERVED_0 0x80 +#define SYSCALL_RESERVED_1 0x81 +#define SYSCALL_RESERVED_2 0x82 +#define SYSCALL_RESERVED_3 0x83 +#define SYSCALL_RESERVED_4 0x84 +#define SYSCALL_RESERVED_5 0x85 +#define SYSCALL_RESERVED_6 0x86 +#define SYSCALL_RESERVED_7 0x87 +#define SYSCALL_RESERVED_8 0x88 +#define SYSCALL_RESERVED_9 0x89 +#define SYSCALL_RESERVED_10 0x8A +#define SYSCALL_RESERVED_11 0x8B +#define SYSCALL_RESERVED_12 0x8C +#define SYSCALL_RESERVED_13 0x8D +#define SYSCALL_RESERVED_14 0x8E +#define SYSCALL_RESERVED_15 0x8F +#define SYSCALL_RESERVED_END 0x8F + +#endif /* _SYSCALL_INT_H */ diff --git a/spec/ureg.h b/spec/ureg.h new file mode 100644 index 0000000..2183d59 --- /dev/null +++ b/spec/ureg.h @@ -0,0 +1,50 @@ +#ifndef _UREG_H_ +#define _UREG_H_ + +/* See intel-sys.pdf section 5.12, "Exception and Interrupt Reference" */ +#define SWEXN_CAUSE_DIVIDE 0x00 /* Very clever, Intel */ +#define SWEXN_CAUSE_DEBUG 0x01 +#define SWEXN_CAUSE_BREAKPOINT 0x03 +#define SWEXN_CAUSE_OVERFLOW 0x04 +#define SWEXN_CAUSE_BOUNDCHECK 0x05 +#define SWEXN_CAUSE_OPCODE 0x06 /* SIGILL */ +#define SWEXN_CAUSE_NOFPU 0x07 /* FPU missing/disabled/busy */ +#define SWEXN_CAUSE_SEGFAULT 0x0B /* segment not present */ +#define SWEXN_CAUSE_STACKFAULT 0x0C /* ouch */ +#define SWEXN_CAUSE_PROTFAULT 0x0D /* aka GPF */ +#define SWEXN_CAUSE_PAGEFAULT 0x0E /* cr2 is valid! */ +#define SWEXN_CAUSE_FPUFAULT 0x10 /* old x87 FPU is angry */ +#define SWEXN_CAUSE_ALIGNFAULT 0x11 +#define SWEXN_CAUSE_SIMDFAULT 0x13 /* SSE/SSE2 FPU is angry */ + +#ifndef ASSEMBLER + +typedef struct ureg_t { + unsigned int cause; + unsigned int cr2; /* Or else zero. */ + + unsigned int ds; + unsigned int es; + unsigned int fs; + unsigned int gs; + + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int zero; /* Dummy %esp, set to zero */ + unsigned int ebx; + unsigned int edx; + unsigned int ecx; + unsigned int eax; + + unsigned int error_code; + unsigned int eip; + unsigned int cs; + unsigned int eflags; + unsigned int esp; + unsigned int ss; +} ureg_t; + +#endif /* ASSEMBLER */ + +#endif /* _UREG_H_ */ diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..e9aa5e1 --- /dev/null +++ b/update.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +# This is a shell script for keeping the support code +# for the 15-410 kernel up to date. +# +# Ivan Jager (aij) +# +########################################################### +# Usage: +# update.sh [query] +# +# : +# afs - update files by comparing md5sums +# taken from course afs space. If +# files don't match digests, grab +# updated files from course afs space. +# +# web - same but from course webspace. +# +# offline - build support libraries using +# code present in local directories. +# This method is *not* recommended for +# typical use. +# +########################################################### + + +# location of official support code and libraries +AFS_PATH=${AFS_PATH-/afs/cs.cmu.edu/academic/class/15410-s23/Web/update/proj4} +WEB_URL=${WEB_URL-'http://www.cs.cmu.edu/~410-s23/update/proj4'} + +# the name of the file containing the MD5s for the files we want to update +WHAT=all.md5s + +#fetches a file from the update area, either to a specific destination, or +# to the same relative filename if no destination is specified +function fetch () { + local mode=$1 + local from=$2 + local to=${3:-$2} + # make the directory to put the file in if it doesn't exist + test -d `dirname "$to"` || mkdir -p `dirname "$to"` + + case "$METHOD" in + afs) + cp "$AFS_PATH/$from" "$to.tmp" && mv "$to.tmp" "$to" ;; + web) + wget -nv "$WEB_URL/$from" -O "$to.tmp" && mv "$to.tmp" "$to" ;; + query) + test -f "$to" && echo "$from hasn't been updated since `stat -c %y $to`" || echo "File $to is missing" + NEEDS_UPDATING=true + return ;; + *) echo fetch: method invalid: $METHOD; exit 2 ;; + esac && + chmod $mode "$to" +} + +# reads a list of md5s to check and update from stdin +function do_update () { + rc=0 + while read mode md5 filename + #for filename in `md5sum -c | tee >(cat >&3) | grep -v OK$ | sed 's/: FAILED.*//g'` + do + current=`md5sum "$filename" | cut -d ' ' -f 1` + if [ "$current" != "$md5" ] + then + echo Update "$filename" + fetch $mode "$filename" || rc=$? + fi + done 3>&1 + test -z "$NEEDS_UPDATING" || { /bin/echo -e '****\nUpdates are available. Please run make update sometime soon.\n****\7'; sleep 1; /bin/echo -e '\7'; sleep 1; /bin/echo -e '\7'; } + return $rc +} + + +# find out what method we were told to use +# One of afs, web, or offline. (rsync coming "soon") +case $1 in + '') + { test -d $AFS_PATH && METHOD=afs ; } || \ + { which wget >/dev/null 2>&1 && METHOD=web ; } || \ + METHOD=offline + ;; + afs|web|offline) + METHOD=$1 + ;; + *) + echo usage: $0 'afs|web|offline' '[query]' + exit 9 + ;; +esac + +if [ "$METHOD" = offline ] ; then + echo UPDATE METHOD IS OFFLINE. This is not recommended. + echo Be sure to update and make sure your code works before handing it in. + sleep 3 + exit +fi + +# this could be changed to not make a copy when updating from AFS +fetch 644 $WHAT .md5s || { echo Failed to fetch the list of MD5s.; exit 1; } +echo "# Fetched by $0 $@ at `date`" >>.md5s + +test "$2" = query && METHOD=query + +grep -v '^#' .md5s | do_update + diff --git a/user/files/README b/user/files/README new file mode 100644 index 0000000..325c8fa --- /dev/null +++ b/user/files/README @@ -0,0 +1,5 @@ +It is possible to build non-executable files from 410user/files into the +"RAM disk" by listing them in 410FILES in your config.mk. + +It is possible to build non-executable files from user/files into the +"RAM disk" by listing them in STUDENTFILES in your config.mk. diff --git a/user/inc/README.userinc b/user/inc/README.userinc new file mode 100644 index 0000000..3f2d0b9 --- /dev/null +++ b/user/inc/README.userinc @@ -0,0 +1,2 @@ +This directory exists for you to store header files that are not +private to your libraries; those can go in user/libfoo/. diff --git a/user/inc/cond_type.h b/user/inc/cond_type.h new file mode 100644 index 0000000..41e56f4 --- /dev/null +++ b/user/inc/cond_type.h @@ -0,0 +1,32 @@ +/** + * @file cond_type.h + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief cv structure + * @date 2023-02-22 + * + */ +#ifndef COND_TYPE_H +#define COND_TYPE_H + +#include + +/** + * @brief a node in condition vairable wait queue + */ +typedef struct cond_node_s { + int tid; + int signaled; /* is this thread signaled by othres */ + struct cond_node_s* next; + struct cond_node_s* prev; +} cond_node_t; + +/** + * @brief condition vairable + */ +typedef struct cond_s { + mutex_t lock; + cond_node_t* queue; /* waiters on this cv */ +} cond_t; + +#endif diff --git a/user/inc/mutex_type.h b/user/inc/mutex_type.h new file mode 100644 index 0000000..0d46d71 --- /dev/null +++ b/user/inc/mutex_type.h @@ -0,0 +1,38 @@ +/** + * @file mutex_type.h + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief mutex structure + * @date 2023-02-22 + * + */ +#ifndef MUTEX_TYPE_H +#define MUTEX_TYPE_H + +#include +#include + +/* decleration of thread control block */ +struct tcb_s; + +/** + * @brief mutex structure + */ +typedef struct mutex_s { + uint32_t locked; /* status of the mutex */ + uint32_t w_lock; /* lock for the waiter list below */ + struct tcb_s* w_list; /* waiter list */ +} mutex_t; + +/** + * @brief static mutex initialization + */ +#define MUTEX_INIT \ + { .locked = 0, .w_lock = 0, .w_list = NULL } + +/** + * @brief unlock the mutex and call vanish without using stack + */ +void mutex_unlock_vanish(mutex_t* mp); + +#endif diff --git a/user/inc/rwlock_type.h b/user/inc/rwlock_type.h new file mode 100644 index 0000000..ca5b7e8 --- /dev/null +++ b/user/inc/rwlock_type.h @@ -0,0 +1,41 @@ +/** + * @file rwlock_type.h + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief rwlock structure + * @date 2023-02-22 + * + */ +#ifndef RWLOCK_TYPE_H +#define RWLOCK_TYPE_H + +#include +#include + +/** + * @brief indicates that the rwlock is unlocked + */ +#define RWLOCK_STATUS_UNLOCK 0 + +/** + * @brief indicates that the rwlock is locked by at least 1 reader + */ +#define RWLOCK_STATUS_READ 1 + +/** + * @brief indicates that the rwlock is locked by a writer + */ +#define RWLOCK_STATUS_WRITE 2 + +/** + * @brief rwlock structure + */ +typedef struct rwlock_s { + mutex_t status_lock; /* mutex to protect other structures */ + int num_reader; /* number of readers holding this rwlock */ + cond_t reader_cv; /* cv to wait for read availability */ + cond_t writer_cv; /* cv to wait for write availability */ + int status; /* status of this rwlock */ +} rwlock_t; + +#endif diff --git a/user/inc/sem_type.h b/user/inc/sem_type.h new file mode 100644 index 0000000..c0bdf56 --- /dev/null +++ b/user/inc/sem_type.h @@ -0,0 +1,24 @@ +/** + * @file sem.h + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief semaphore structure + * @date 2023-02-22 + * + */ +#ifndef SEM_TYPE_H +#define SEM_TYPE_H + +#include +#include + +/** + * @brief semaphore structure + */ +typedef struct sem_s { + int value; + mutex_t value_lock; /* mutex to protect the value */ + cond_t value_cv; /* cv to wait for value increment */ +} sem_t; + +#endif diff --git a/user/inc/thr_internals.h b/user/inc/thr_internals.h new file mode 100644 index 0000000..e0ad52e --- /dev/null +++ b/user/inc/thr_internals.h @@ -0,0 +1,74 @@ +/** + * @file thr_internals.h + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief tcb structure and management functions and excpetion stack + * @date 2023-02-22 + * + */ + +#ifndef THR_INTERNALS_H +#define THR_INTERNALS_H + +#include + +#include +#include +#include + +/** + * @brief stack for excpetion handler + */ +extern char ex_stack[]; + +/** + * @brief pointer to the highest address of exception stack + */ +extern void* ex_stack_end; + +/** + * @brief thread control block structure + */ +typedef struct tcb_s { + int tid; /* thread id */ + uintptr_t stack_lo; /* low limit of stack */ + uintptr_t stack_hi; /* high limit of stack */ + int is_main; /* is main thread */ + + int color; /* rbtree color */ + struct tcb_s* parent; /* rbtree parent */ + struct tcb_s* left; /* rbtree left node */ + struct tcb_s* right; /* rbtree right node */ + + struct tcb_s* mutex_next; /* queue for block on mutex */ + struct tcb_s* mutex_prev; /* queue for block on mutex */ + int mutex_resume; /* flag to show is other thread is going to resume this + thread */ + + int waiter; /* tid of other thread that called thr_join on it */ + int exited; /* is exited */ + void* exit_value; /* return value */ + cond_t wait_cv; /* cv to wait for thread exit */ +} tcb_t; + +/** + * @brief tcb for main thread + */ +extern tcb_t main_tcb; + +/** + * @brief find tcb by thread id + */ +tcb_t* rb_find_tcb(int tid); +/** + * @brief insert tcb into rbtree + */ +void rb_insert_tcb(tcb_t* tcb); +/** + * @brief delete tcb from rbtree + */ +void rb_delete_tcb(tcb_t* tcb); + +#define PAGE_ALIGN_MASK ((uintptr_t) ~((uintptr_t)(PAGE_SIZE - 1))) + +#endif diff --git a/user/libautostack/autostack.c b/user/libautostack/autostack.c new file mode 100644 index 0000000..d0bea43 --- /dev/null +++ b/user/libautostack/autostack.c @@ -0,0 +1,71 @@ +/** + * @file autostack.c + * @author Hanjie Wu (hanjiew) + * @brief autostack implementation + * @date 2023-02-22 + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +/** + * @brief test if the page fault is caused by page not present + */ +#define IS_PF_NP(error_code) (((error_code)&0x1) == 0) + +/** + * @brief a stack size which is enough for our swexn handlers + */ +#define EX_STACK_SIZE (1 << 14) + +char ex_stack[EX_STACK_SIZE]; +void* ex_stack_end = &ex_stack[sizeof(ex_stack)]; +/** + * @brief a stack size which is enough for common programs + */ +#define AUTOSYACK_SIZE (1 << 24) +/** + * @brief size limit of autostack growth + */ +const static unsigned int stack_limit = AUTOSYACK_SIZE; + +/** + * @brief autostack swexn handler + */ +static void swexn_handler(void* arg, ureg_t* reg) { + /* check cause */ + if (reg->cause == SWEXN_CAUSE_PAGEFAULT && IS_PF_NP(reg->error_code)) { + /* check stack limit */ + if (reg->cr2 < main_tcb.stack_lo && + reg->cr2 > main_tcb.stack_lo - stack_limit) { + uintptr_t aligned = reg->cr2 & PAGE_ALIGN_MASK; + if (new_pages((void*)aligned, (int)(main_tcb.stack_lo - aligned)) != + 0) { + task_vanish(-2); + } + main_tcb.stack_lo = aligned; + swexn(ex_stack_end, swexn_handler, NULL, reg); + } + } + task_vanish(-2); +} + +/** + * @brief install autostack handler + */ +void install_autostack(void* stack_high, void* stack_low) { + /* use main_tcb to record stack limits */ + main_tcb.stack_hi = (unsigned int)stack_high; + main_tcb.stack_lo = (unsigned int)stack_low; + main_tcb.tid = gettid(); + main_tcb.is_main = 1; + rb_insert_tcb(&main_tcb); + swexn(ex_stack_end, swexn_handler, NULL, NULL); +} diff --git a/user/libsyscall/syscall.S b/user/libsyscall/syscall.S new file mode 100644 index 0000000..d661cf8 --- /dev/null +++ b/user/libsyscall/syscall.S @@ -0,0 +1,218 @@ +#include + +.global deschedule + +# int deschedule(int *flag); +deschedule: + mov 0x4(%esp), %esi + int $DESCHEDULE_INT + ret + +.global exec + +# int exec(char *execname, char *argvec[]); +exec: + mov 0x8(%esp), %esi + push %esi + mov 0x8(%esp), %esi + push %esi + mov %esp, %esi + int $EXEC_INT + add $0x8, %esp + ret + +.global fork + +# int fork(void); +fork: + int $FORK_INT + ret + +.global getchar + +getchar: + int $GETCHAR_INT + ret + +.global get_cursor_pos + +get_cursor_pos: + mov 0x8(%esp), %esi + push %esi + mov 0x8(%esp), %esi + push %esi + mov %esp, %esi + int $GET_CURSOR_POS_INT + add $0x8, %esp + ret + +.global get_ticks + +get_ticks: + int $GET_TICKS_INT + ret + +.global gettid + +# int gettid(void); +gettid: + int $GETTID_INT + ret + +.global halt + +halt: + int $HALT_INT + ret + +.global make_runnable + +make_runnable: + mov 0x4(%esp), %esi + int $MAKE_RUNNABLE_INT + ret + +.global misbehave + +misbehave: + mov 0x4(%esp), %esi + int $MISBEHAVE_INT + ret + +.global new_pages + +new_pages: + mov 0x8(%esp), %esi + push %esi + mov 0x8(%esp), %esi + push %esi + mov %esp, %esi + int $NEW_PAGES_INT + add $0x8, %esp + ret + +.global print + +print: + mov 0x8(%esp), %esi + push %esi + mov 0x8(%esp), %esi + push %esi + mov %esp, %esi + int $PRINT_INT + add $0x8, %esp + ret + +.global readfile + +readfile: + mov 0x10(%esp), %esi + push %esi + mov 0x10(%esp), %esi + push %esi + mov 0x10(%esp), %esi + push %esi + mov 0x10(%esp), %esi + push %esi + mov %esp, %esi + int $READFILE_INT + add $0x10, %esp + ret + +.global readline + +readline: + mov 0x8(%esp), %esi + push %esi + mov 0x8(%esp), %esi + push %esi + mov %esp, %esi + int $READLINE_INT + add $0x8, %esp + ret + +.global remove_pages + +remove_pages: + mov 0x4(%esp), %esi + int $REMOVE_PAGES_INT + ret + +.global set_cursor_pos + +set_cursor_pos: + mov 0x8(%esp), %esi + push %esi + mov 0x8(%esp), %esi + push %esi + mov %esp, %esi + int $SET_CURSOR_POS_INT + add $0x8, %esp + ret + +.global set_status + +# void set_status(int status); +set_status: + mov 0x4(%esp), %esi + int $SET_STATUS_INT + ret + +.global set_term_color + +set_term_color: + mov 0x4(%esp), %esi + int $SET_TERM_COLOR_INT + ret + +.global sleep + +sleep: + mov 0x4(%esp), %esi + int $SLEEP_INT + ret + +.global swexn + +swexn: + mov 0x10(%esp), %esi + push %esi + mov 0x10(%esp), %esi + push %esi + mov 0x10(%esp), %esi + push %esi + mov 0x10(%esp), %esi + push %esi + mov %esp, %esi + int $SWEXN_INT + add $0x10, %esp + ret + +.global task_vanish + +# void task_vanish(int status) NORETURN; +task_vanish: + mov 0x4(%esp), %esi + int $TASK_VANISH_INT + +.global vanish + +# void vanish(void) NORETURN; +vanish: + int $VANISH_INT + +.global wait + +# int wait(int *status_ptr); +wait: + mov 0x4(%esp), %esi + int $WAIT_INT + ret + +.global yield + +# int yield(int pid); +yield: + mov 0x4(%esp), %esi + int $YIELD_INT + ret diff --git a/user/libthread/cond.c b/user/libthread/cond.c new file mode 100644 index 0000000..ccc7767 --- /dev/null +++ b/user/libthread/cond.c @@ -0,0 +1,108 @@ +/** + * @file cond.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief + * @date 2023-02-22 + * + */ + +#include +#include +#include +#include + +/** + * @brief initialize the condition variable pointed by cv + * + * @param cv + * @return 0 + */ +int cond_init(cond_t* cv) { + mutex_init(&cv->lock); + cv->queue = NULL; + return 0; +} + +/** + * @brief destroy the condition variable pointed by cv. + * + * @param cv + */ +void cond_destroy(cond_t* cv) { + affirm(cv->queue == NULL); + mutex_destroy(&cv->lock); +} + +/** + * @brief wait on a cv until signaled and lock mp + * + * @param cv + */ +void cond_wait(cond_t* cv, mutex_t* mp) { + cond_node_t self; + mutex_lock(&cv->lock); + self.tid = gettid(); + self.signaled = 0; + if (cv->queue == NULL) { /* add self node to wait list */ + cv->queue = &self; + self.next = self.prev = &self; + } else { + self.next = cv->queue; + self.prev = cv->queue->prev; + cv->queue->prev->next = &self; + cv->queue->prev = &self; + } + mutex_unlock(mp); + mutex_unlock(&cv->lock); + while (self.signaled != 1) { + deschedule(&self.signaled); /* will be set to 1 after other thread + signal the cv */ + } + mutex_lock(mp); +} + +/** + * @brief signal a cv and wake up one thread + * + * @param cv + */ +void cond_signal(cond_t* cv) { + mutex_lock(&cv->lock); + if (cv->queue != NULL) { /* remove a waiter from the list */ + cond_node_t* p = cv->queue; + if (p->next == p) { + cv->queue = NULL; + } else { + cv->queue = p->next; + p->next->prev = p->prev; + p->prev->next = p->next; + } + int tid = p->tid; + p->signaled = 1; + make_runnable(tid); + } + mutex_unlock(&cv->lock); +} + +/** + * @brief signal a cv and wake up all threads + * + * @param cv + */ +void cond_broadcast(cond_t* cv) { + mutex_lock(&cv->lock); + cond_node_t* p = cv->queue; + if (p != NULL) { + cond_node_t* end = p; + do { + cond_node_t* q = p->next; + int tid = p->tid; + p->signaled = 1; + make_runnable(tid); + p = q; + } while (p != end); + cv->queue = NULL; + } + mutex_unlock(&cv->lock); +} diff --git a/user/libthread/malloc.c b/user/libthread/malloc.c new file mode 100644 index 0000000..8be6683 --- /dev/null +++ b/user/libthread/malloc.c @@ -0,0 +1,40 @@ +/** + * @file malloc.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief Thread safe wrappers for malloc and family + * @date 2023-02-22 + * + */ + +#include +#include + +mutex_t malloc_lock = MUTEX_INIT; + +void* malloc(size_t size) { + mutex_lock(&malloc_lock); + void* result = _malloc(size); + mutex_unlock(&malloc_lock); + return result; +} + +void* calloc(size_t nelt, size_t eltsize) { + mutex_lock(&malloc_lock); + void* result = _calloc(nelt, eltsize); + mutex_unlock(&malloc_lock); + return result; +} + +void* realloc(void* buf, size_t new_size) { + mutex_lock(&malloc_lock); + void* result = _realloc(buf, new_size); + mutex_unlock(&malloc_lock); + return result; +} + +void free(void* buf) { + mutex_lock(&malloc_lock); + _free(buf); + mutex_unlock(&malloc_lock); +} diff --git a/user/libthread/mutex.c b/user/libthread/mutex.c new file mode 100644 index 0000000..f78a6e8 --- /dev/null +++ b/user/libthread/mutex.c @@ -0,0 +1,35 @@ +/** + * @file mutex.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief Mutex implementation + * @date 2023-02-22 + * + */ + +#include + +#include +#include + +/** + * @brief initialize the mutex pointed by mp + * + * @param mp mutex + * @return 0 + */ +int mutex_init(mutex_t* mp) { + mp->locked = 0; + mp->w_lock = 0; + mp->w_list = NULL; + return 0; +} + +/** + * @brief deactivate the mutex pointed by mp + * + * @param mp mutex + */ +void mutex_destroy(mutex_t* mp) { + affirm(mp->locked == 0); +} diff --git a/user/libthread/mutex_lock.S b/user/libthread/mutex_lock.S new file mode 100644 index 0000000..731ab59 --- /dev/null +++ b/user/libthread/mutex_lock.S @@ -0,0 +1,114 @@ +#include + +// it is impossible to implement mutex_unlock_vanish without stack in c +// so we implement all lock functions in assembly and mutex_unlock can +// share function body with mutex_unlock_vanish + +.mutex_unlock_body: + xor %eax, %eax // + lock xchg %eax, (%ebp) // mp->locked = 0; +.mutex_unlock_try: // while(true) { + xor %eax, %eax // + mov $1, %edi // + lock cmpxchg %edi, 0x4(%ebp) // eax = compare_and_set(&mp->w_lock, 1); + test %eax, %eax // if(eax == 0) {break;} + jnz .mutex_unlock_try // } + mov 0x8(%ebp), %edi // edi = mp->w_list; + test %edi, %edi // + jz .mutex_unlock_w_empty // if(edi != NULL) { + mov $1, %edx // + mov %edx, 0x28(%edi) // edi->mutex_resume = 1; + mov (%edi), %esi // + int $MAKE_RUNNABLE_INT // make_runnable(edi->tid); +.mutex_unlock_w_empty: // } + xor %eax, %eax // + lock xchg %eax, 0x4(%ebp) // mp->w_lock = 0; + jmp *%ebx + +.global mutex_unlock +.type mutex_unlock, %function +mutex_unlock: + push %ebx + push %ebp + mov 0xc(%esp), %ebp // ebp = mp + lea .mutex_unlock_done, %ebx // ebx will be used by mutex_unlock_body as return address + jmp .mutex_unlock_body +.mutex_unlock_done: + pop %ebp + pop %ebx + ret + +.global mutex_unlock_vanish +.type mutex_unlock_vanish, %function +mutex_unlock_vanish: + mov 0x4(%esp), %ebp + lea .mutex_unlock_do_vanish, %ebx + jmp .mutex_unlock_body +.mutex_unlock_do_vanish: + int $VANISH_INT + +.global mutex_lock +.type mutex_lock, %function +mutex_lock: + push %ebx // + push %ebp // + call get_self_tcb // + mov %eax, %ebx // ebx = get_self_tcb(); + xor %eax, %eax // + mov %eax, 0x28(%ebx) // ebx->mutex_resume = 0; + mov 0xc(%esp), %ebp // ebp = mp; +.mutex_lock_w_lock: // while(true) { + xor %eax, %eax // + mov $1, %edi // + lock cmpxchg %edi, 0x4(%ebp) // eax = compare_and_set(&mp->w_lock, 1); + test %eax, %eax // if(eax == 0) {break;} + jnz .mutex_lock_w_lock // } + mov 0x8(%ebp), %edi // edi = mp->w_list; + test %edi, %edi // + jz .mutex_lock_w_empty // if(edi != NULL) { + mov %edi, 0x20(%ebx) // ebx->mutex_next = edi; + mov 0x24(%edi), %edx // edx = edi->mutex_prev; + mov %edx, 0x24(%ebx) // ebx->mutex_prev = edx; + mov %ebx, 0x20(%edx) // edx->mutex_next = ebx; + mov %ebx, 0x24(%edi) // edi->mutex_prev = ebx; + jmp .mutex_lock_w_done // } +.mutex_lock_w_empty: // else { + mov %ebx, 0x8(%ebp) // mp->w_list = ebx; + mov %ebx, 0x20(%ebx) // ebx->mutex_next = ebx; + mov %ebx, 0x24(%ebx) // ebx->mutex_prev = ebx; +.mutex_lock_w_done: // } + lock xchg %eax, 0x4(%ebp) // mp->w_lock = 0; +.mutex_lock_try: // + xor %eax, %eax // while(true) { + mov $1, %edi // + lock cmpxchg %edi, (%ebp) // eax = compare_and_set(&mp->locked, 1); + test %eax, %eax // + jz .mutex_lock_success // if(eax == 0) {break;} + lea 0x28(%ebx), %eax // + push %eax // + call deschedule // deschedule(&ebx->mutex_resume); + add $0x4, %esp // + jmp .mutex_lock_try // } +.mutex_lock_success: // while(true) { + xor %eax, %eax // + mov $1, %edi // + lock cmpxchg %edi, 0x4(%ebp) // eax = compare_and_set(&mp->w_lock, 1); + test %eax, %eax // if(eax == 0) {break;} + jnz .mutex_lock_success // } + mov 0x20(%ebx), %edi // edi = ebx->mutex_next; + mov 0x24(%ebx), %edx // edx = ebx->mutex_prev; + cmp %edi, %ebx // + je .mutex_lock_w_last // if(edi != ebx) { + mov %edx, 0x24(%edi) // edi->mutex_prev = edx; + mov %edi, 0x20(%edx) // edx->mutex_next = edi; + cmp %ebx, 0x8(%ebp) // + jne .mutex_lock_w_end // if(ebx == mp->w_list) + mov %edi, 0x8(%ebp) // mp->w_list = edi; + jmp .mutex_lock_w_end // } +.mutex_lock_w_last: // else { + mov %eax, 0x8(%ebp) // mp->w_list = NULL; +.mutex_lock_w_end: // } + lock xchg %eax, 0x4(%ebp) // mp->w_lock = 0; + pop %ebp + pop %ebx + ret diff --git a/user/libthread/panic.c b/user/libthread/panic.c new file mode 100644 index 0000000..7e9be35 --- /dev/null +++ b/user/libthread/panic.c @@ -0,0 +1,25 @@ +/** + * @file panic.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief panic implementation + * @date 2023-02-22 + * + */ + +#include +#include + +/** + * @brief print msg and die + */ +void panic(const char* fmt, ...) { + va_list va; + va_start(va, fmt); + + vprintf(fmt, va); + + va_end(va); + + exit(-1); +} diff --git a/user/libthread/rb_tcb.c b/user/libthread/rb_tcb.c new file mode 100644 index 0000000..40eac5b --- /dev/null +++ b/user/libthread/rb_tcb.c @@ -0,0 +1,283 @@ +/** + * @file rb_tcb.c + * @author Hanjie Wu (hanjiew) + * @brief rbtree for tcbs + * @date 2023-02-22 + * + */ + +#include +#include + +#include + +/** + * @brief rbtree color + */ +#define RB_BLACK 0 +#define RB_RED 1 + +/** + * @brief sentinel node + */ +static tcb_t rb_nil = { + .color = RB_BLACK, + .parent = &rb_nil, + .left = &rb_nil, + .right = &rb_nil, +}; + +/** + * @brief rbtree root + */ +static tcb_t* root = &rb_nil; + +/** + * @brief find a tcb by tid + */ +tcb_t* rb_find_tcb(int tid) { + tcb_t* p = root; + while (p != &rb_nil) { + if (tid == p->tid) { + return p; + } + p = (tid > p->tid) ? p->right : p->left; + } + return NULL; +} + +/** + * @brief left rotate on a node + */ +static void rb_rotate_left(tcb_t** root, tcb_t* block) { + tcb_t* r = block->right; + block->right = r->left; + if (r->left != &rb_nil) { + r->left->parent = block; + } + r->parent = block->parent; + if (block->parent == &rb_nil) { + *root = r; + } else if (block == block->parent->left) { + block->parent->left = r; + } else { + block->parent->right = r; + } + r->left = block; + block->parent = r; +} + +/** + * @brief right rotate on a node + */ +static void rb_rotate_right(tcb_t** root, tcb_t* block) { + tcb_t* l = block->left; + block->left = l->right; + if (l->right != &rb_nil) { + l->right->parent = block; + } + l->parent = block->parent; + if (block->parent == &rb_nil) { + *root = l; + } else if (block == block->parent->left) { + block->parent->left = l; + } else { + block->parent->right = l; + } + l->right = block; + block->parent = l; +} + +/** + * @brief fixup after insertion + */ +static void rb_fixup(tcb_t** root, tcb_t* block) { + while (block->parent->color == RB_RED) { + tcb_t* grand = block->parent->parent; + if (block->parent == grand->left) { + tcb_t* uncle = grand->right; + if (uncle->color == RB_RED) { + block->parent->color = RB_BLACK; + uncle->color = RB_BLACK; + block->parent->parent->color = RB_RED; + block = block->parent->parent; + } else { + if (block == block->parent->right) { + block = block->parent; + rb_rotate_left(root, block); + } + block->parent->color = RB_BLACK; + grand->color = RB_RED; + rb_rotate_right(root, grand); + } + } else { + tcb_t* uncle = grand->left; + if (uncle->color == RB_RED) { + block->parent->color = RB_BLACK; + uncle->color = RB_BLACK; + block->parent->parent->color = RB_RED; + block = block->parent->parent; + } else { + if (block == block->parent->left) { + block = block->parent; + rb_rotate_right(root, block); + } + block->parent->color = RB_BLACK; + grand->color = RB_RED; + rb_rotate_left(root, grand); + } + } + } + (*root)->color = RB_BLACK; +} + +/** + * @brief insert a node + */ +static void rb_insert(tcb_t** root, tcb_t* block) { + tcb_t *p = *root, *parent = &rb_nil; + while (p != &rb_nil) { + parent = p; + p = (block->tid > p->tid) ? p->right : p->left; + } + block->parent = parent; + if (parent == &rb_nil) { + *root = block; + } else if (block->tid > parent->tid) { + parent->right = block; + } else { + parent->left = block; + } + block->left = block->right = &rb_nil; + block->color = RB_RED; + rb_fixup(root, block); +} + +/** + * @brief move node v to u + */ +static void rb_transplant(tcb_t** root, tcb_t* u, tcb_t* v) { + if (u->parent == &rb_nil) { + *root = v; + } else if (u == u->parent->left) { + u->parent->left = v; + } else { + u->parent->right = v; + } + v->parent = u->parent; +} + +/** + * @brief find minimum node + */ +static tcb_t* rb_min(tcb_t* block) { + while (block->left != &rb_nil) { + block = block->left; + } + return block; +} + +/** + * @brief fixup after deletion + */ +static void rb_delete_fixup(tcb_t** root, tcb_t* block) { + while (block != *root && block->color == RB_BLACK) { + if (block == block->parent->left) { + tcb_t* r = block->parent->right; + if (r->color == RB_RED) { + r->color = RB_BLACK; + block->parent->color = RB_RED; + rb_rotate_left(root, block->parent); + r = block->parent->right; + } + if (r->left->color == RB_BLACK && r->right->color == RB_BLACK) { + r->color = RB_RED; + block = block->parent; + } else { + if (r->right->color == RB_BLACK) { + r->left->color = RB_BLACK; + r->color = RB_RED; + rb_rotate_right(root, r); + r = block->parent->right; + } + r->color = block->parent->color; + block->parent->color = RB_BLACK; + r->right->color = RB_BLACK; + rb_rotate_left(root, block->parent); + block = *root; + } + } else { + tcb_t* l = block->parent->left; + if (l->color == RB_RED) { + l->color = RB_BLACK; + block->parent->color = RB_RED; + rb_rotate_right(root, block->parent); + l = block->parent->left; + } + if (l->right->color == RB_BLACK && l->left->color == RB_BLACK) { + l->color = RB_RED; + block = block->parent; + } else { + if (l->left->color == RB_BLACK) { + l->right->color = RB_BLACK; + l->color = RB_RED; + rb_rotate_left(root, l); + l = block->parent->left; + } + l->color = block->parent->color; + block->parent->color = RB_BLACK; + l->left->color = RB_BLACK; + rb_rotate_right(root, block->parent); + block = *root; + } + } + } + block->color = RB_BLACK; +} + +/** + * @brief delete a node + */ +static void rb_delete(tcb_t** root, tcb_t* block) { + tcb_t *x, *y = block; + int orig_color = y->color; + if (block->left == &rb_nil) { + x = block->right; + rb_transplant(root, block, x); + } else if (block->right == &rb_nil) { + x = block->left; + rb_transplant(root, block, x); + } else { + y = rb_min(block->right); + orig_color = y->color; + x = y->right; + if (y->parent == block) { + x->parent = y; + } else { + rb_transplant(root, y, y->right); + y->right = block->right; + y->right->parent = y; + } + rb_transplant(root, block, y); + y->left = block->left; + y->left->parent = y; + y->color = block->color; + } + if (orig_color == RB_BLACK) { + rb_delete_fixup(root, x); + } +} + +/** + * @brief add a tcb to rbtree + */ +void rb_insert_tcb(tcb_t* tcb) { + rb_insert(&root, tcb); +} + +/** + * @brief remove a tcb from rbtree + */ +void rb_delete_tcb(tcb_t* tcb) { + rb_delete(&root, tcb); +} diff --git a/user/libthread/rwlock.c b/user/libthread/rwlock.c new file mode 100644 index 0000000..4535d9b --- /dev/null +++ b/user/libthread/rwlock.c @@ -0,0 +1,89 @@ +/** + * @file rwlock.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief RW Lock implementation + * @date 2023-02-22 + * + */ + +#include +#include + +/** + * @brief initialize the lock pointed to by rwlock + * + * @param rwlock + * @return int + */ +int rwlock_init(rwlock_t* rwlock) { + rwlock->status = RWLOCK_STATUS_UNLOCK; + rwlock->num_reader = 0; + mutex_init(&rwlock->status_lock); + cond_init(&rwlock->reader_cv); + cond_init(&rwlock->writer_cv); + return 0; +} + +/** + * @brief lock a rwlock + */ +void rwlock_lock(rwlock_t* rwlock, int type) { + mutex_lock(&rwlock->status_lock); + if (type == RWLOCK_READ) { + while (rwlock->status == RWLOCK_STATUS_WRITE) { + /* wait for the write to release */ + cond_wait(&rwlock->reader_cv, &rwlock->status_lock); + } + rwlock->status = RWLOCK_STATUS_READ; + rwlock->num_reader++; + } else { + while (rwlock->status != RWLOCK_STATUS_UNLOCK) { + affirm(rwlock->status == RWLOCK_STATUS_WRITE); + /* wait for readers to release */ + cond_wait(&rwlock->writer_cv, &rwlock->status_lock); + } + rwlock->status = RWLOCK_STATUS_WRITE; + } + mutex_unlock(&rwlock->status_lock); +} + +/** + * @brief unlock a rwlock + */ +void rwlock_unlock(rwlock_t* rwlock) { + mutex_lock(&rwlock->status_lock); + if (rwlock->status == RWLOCK_STATUS_READ) { + rwlock->num_reader--; + /* the last reader should notify the writers */ + if (rwlock->num_reader == 0) { + rwlock->status = RWLOCK_STATUS_UNLOCK; + cond_broadcast(&rwlock->writer_cv); + } + } else { + affirm(rwlock->status == RWLOCK_STATUS_WRITE); + rwlock->status = RWLOCK_STATUS_UNLOCK; + /* notify all readers */ + cond_broadcast(&rwlock->reader_cv); + } + mutex_unlock(&rwlock->status_lock); +} + +/** + * @brief destroy a rwlock + */ +void rwlock_destroy(rwlock_t* rwlock) { + affirm(rwlock->status == RWLOCK_STATUS_UNLOCK); + mutex_destroy(&rwlock->status_lock); + cond_destroy(&rwlock->reader_cv); + cond_destroy(&rwlock->writer_cv); +} + +/** + * @brief downgrade a rwlock + */ +void rwlock_downgrade(rwlock_t* rwlock) { + affirm(rwlock->status == RWLOCK_STATUS_WRITE); + rwlock->status = RWLOCK_STATUS_READ; + cond_broadcast(&rwlock->reader_cv); +} diff --git a/user/libthread/sem.c b/user/libthread/sem.c new file mode 100644 index 0000000..d4d723e --- /dev/null +++ b/user/libthread/sem.c @@ -0,0 +1,71 @@ +/** + * @file sem.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief Semaphore implementation + * @date 2023-02-22 + * + */ + + +#include + +/** + * @brief Initializes the semaphore pointed to by 'sem' tp value 'count' + * + * @param sem semaphore + * @param count count + * @return int + */ +int sem_init(sem_t* sem, int count) { + sem->value = count; + + mutex_init(&sem->value_lock); + cond_init(&sem->value_cv); + + return 0; +} + +/** + * @brief Decrement sem value, may block until it is possible to do so + * + * @param sem semaphore + */ +void sem_wait(sem_t* sem) { + mutex_lock(&sem->value_lock); + + while (sem->value <= 0) { + /* wait until value goes up */ + cond_wait(&sem->value_cv, &sem->value_lock); + } + sem->value -= 1; + mutex_unlock(&sem->value_lock); +} + +/** + * @brief wake up a thread waiting on the semaphore pointed to by sem + * + * @param sem semaphore + */ +void sem_signal(sem_t* sem) { + mutex_lock(&sem->value_lock); + + sem->value += 1; + + if (sem->value == 1) { + /* notify when value goes up from zero */ + cond_signal(&sem->value_cv); + } + mutex_unlock(&sem->value_lock); +} + +/** + * @brief deactivate semaphore. Must not be called on semaphores bwing waited + * upon + * + * @param sem semaphore + */ +void sem_destroy(sem_t* sem) { + mutex_destroy(&sem->value_lock); + cond_destroy(&sem->value_cv); +} diff --git a/user/libthread/thread.c b/user/libthread/thread.c new file mode 100644 index 0000000..56f6ac0 --- /dev/null +++ b/user/libthread/thread.c @@ -0,0 +1,325 @@ +/** + * @file thread.c + * @author Hanjie Wu (hanjiew) + * @author Devang Acharya (devanga) + * @brief Implementation of main thread functions + * @date 2023-02-22 + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* return value for thread swexn */ +#define THREAD_EXIT_SWEXN -2 + +/** + * @brief stack size requested + */ +static uintptr_t thr_stack_size; +/** + * @brief stack size aligned + */ +static uintptr_t thr_stack_alloc_size; +/** + * @brief highest address of thread stacks + */ +static uintptr_t thr_stack_begin; +/** + * @brief lowest address of thread stacks + */ +static uintptr_t thr_stack_end; + +/** + * @brief tcb for main thread + */ +tcb_t main_tcb; + +/** + * @brief global lock for tcb operations + */ +mutex_t tcb_lock; + +/** + * @brief list of unused tcbs + */ +tcb_t* free_tcbs = NULL; + +/** + * @brief get esp register + */ +uintptr_t get_esp(); +/** + * @brief swexn handler for multithread programs + */ +static void thr_swexn_handler(void* arg, ureg_t* reg); +/** + * @brief wrapper function for thread_fork syscall + * @param tcb tcb for new thread + * @param f user thread entry point + * @param args user arg for f + */ +int thread_fork(tcb_t* tcb, void* (*f)(void*), void* args); + +/** + * @brief Get the tcb of the thread this function is called form + * + * @return tcb_t* pointer to current thread's TCB + */ +tcb_t* get_self_tcb() { + uintptr_t esp = get_esp(); + + /* check esp in main thread area */ + if (esp > main_tcb.stack_lo) { + return &main_tcb; + } + + /* calculate stack area from esp */ + uintptr_t stack_end = esp + (thr_stack_begin - esp) % thr_stack_alloc_size; + /* pointer to tcb is at highest address in current thread stack */ + return *(tcb_t**)(stack_end - sizeof(tcb_t*)); +} + +/** + * @brief Initialize thread library. Must be called once before using any thread + * functions. + * + * Thread stack structure: + * +-------------------------+-----+---------------+ + * | thread stack |address of tcb | + * +-------------------------+-----+---------------+ + * + * + * @param size the amount of stack space available for each thread + * + * @return int 0 on success, -1 on faliure + */ +int thr_init(uintptr_t size) { + /* set globals */ + thr_stack_size = size; + thr_stack_alloc_size = ((size + PAGE_SIZE - 1) & PAGE_ALIGN_MASK); + thr_stack_begin = ((main_tcb.stack_lo) & PAGE_ALIGN_MASK); + thr_stack_end = thr_stack_begin; + + /* initialize global lock - will never fail */ + mutex_init(&tcb_lock); + + if (swexn(ex_stack_end, thr_swexn_handler, NULL, NULL) < 0) + return -1; + + return 0; +} + +/** + * @brief Create a new thread with the entry point 'func', and arguments 'args' + * + * @param func thread entry point + * @param args thread entry function arguments + * + * @return -1 on failure, 0 on success + */ +int thr_create(void* (*func)(void*), void* args) { + /* holds return values for error checking and the TID to be returned */ + int result; + + /* holds pointer tcb for new thread */ + tcb_t* thread_tcb; + + mutex_lock(&tcb_lock); + + /* find tcb from free list */ + if (free_tcbs != NULL) { + thread_tcb = free_tcbs; + /* reuse stack area */ + result = new_pages((void*)thread_tcb->stack_lo, thr_stack_alloc_size); + + if (result != 0) { + mutex_unlock(&tcb_lock); + return -1; + } + + /* remove from list (use tcb->right as link list) */ + free_tcbs = free_tcbs->right; + } + + else { + /* allocate new tcb */ + thread_tcb = malloc(sizeof(tcb_t)); + + if (thread_tcb == NULL) { + mutex_unlock(&tcb_lock); + return -1; + } + + thr_stack_end -= thr_stack_alloc_size; + result = new_pages((void*)thr_stack_end, thr_stack_alloc_size); + + /* if new_pages unsuccessful */ + if (result != 0) { + thr_stack_end += thr_stack_alloc_size; + free(thread_tcb); + mutex_unlock(&tcb_lock); + return -1; + } + + /* set tcb stack boundaries */ + thread_tcb->stack_lo = thr_stack_end; + thread_tcb->stack_hi = + thr_stack_end + thr_stack_alloc_size - sizeof(tcb_t*); + } + + /* put pointer to tcb at the top of stack for get_self_tcb() use */ + *(tcb_t**)(thread_tcb->stack_lo + thr_stack_alloc_size - sizeof(tcb_t*)) = + thread_tcb; + + thread_tcb->waiter = 0; + thread_tcb->exited = 0; + thread_tcb->is_main = 0; + + cond_init(&thread_tcb->wait_cv); + + thread_tcb->mutex_next = NULL; + thread_tcb->mutex_resume = 0; + + /* create new thread */ + result = thread_fork(thread_tcb, func, args); + + /* if thread_fork failed */ + if (result < 0) { + cond_destroy(&thread_tcb->wait_cv); + remove_pages((void*)thread_tcb->stack_lo); + + thread_tcb->right = free_tcbs; + free_tcbs = thread_tcb; + + mutex_unlock(&tcb_lock); + + return -1; + } + + /* thread successfully created, return tid */ + + thread_tcb->tid = result; + rb_insert_tcb(thread_tcb); + + mutex_unlock(&tcb_lock); + + return result; +} + +/** + * @brief wait thread tid to exit and get exit status + * + * @param tid thread to wait + * @param statusp output pointer for exit status + * @return int 0 on success, -1 on error + */ +int thr_join(int tid, void** statusp) { + mutex_lock(&tcb_lock); + + tcb_t* tcb = rb_find_tcb(tid); + + if (tcb == NULL) { + mutex_unlock(&tcb_lock); + return -1; + } + + /* other thread is waiting for the thread */ + if (tcb->waiter != 0) { + mutex_unlock(&tcb_lock); + return -1; + } + + /* make sure others will not wait on this thread */ + tcb->waiter = 1; + + /* wait until thread exits */ + if (tcb->exited != 1) { + cond_wait(&tcb->wait_cv, &tcb_lock); + } + + /* return exited thread status if user wants it */ + if (statusp != NULL) { + *statusp = tcb->exit_value; + } + + /* cleanup and return */ + rb_delete_tcb(tcb); + cond_destroy(&tcb->wait_cv); + + if (tcb->is_main == 0) { + remove_pages((void*)tcb->stack_lo); + tcb->right = free_tcbs; + free_tcbs = tcb; + } + + mutex_unlock(&tcb_lock); + return 0; +} + +/** + * @brief exit from thread with given status + * + * @param status + */ +void thr_exit(void* status) { + tcb_t* tcb = get_self_tcb(); + mutex_lock(&tcb_lock); + + tcb->exit_value = (void*)status; + tcb->exited = 1; + + cond_signal(&tcb->wait_cv); + /* call vanish after unlock and do not use stack becuase the stack may have + * been freed by other threads */ + mutex_unlock_vanish(&tcb_lock); +} + +/** + * @brief return the ID of the current thread + * + * @return int - ID of the current thread + */ +int thr_getid(void) { + return get_self_tcb()->tid; +} + +/** + * @brief Defers execution of involing thread + * + * @param tid + * @return int + */ +int thr_yield(int tid) { + return yield(tid); +} + +/** + * @brief thread entrypoint wrapper + * @param f user func + * @param arg user argument + */ +void thr_begin(void* (*f)(void*), void* arg) { + mutex_lock(&tcb_lock); + mutex_unlock(&tcb_lock); + thr_exit(f(arg)); +} + +/** + * @brief swexn handler + * + * @param arg + * @param reg + */ +static void thr_swexn_handler(void* arg, ureg_t* reg) { + task_vanish(THREAD_EXIT_SWEXN); +} diff --git a/user/libthread/thread_fork.S b/user/libthread/thread_fork.S new file mode 100644 index 0000000..143f17b --- /dev/null +++ b/user/libthread/thread_fork.S @@ -0,0 +1,26 @@ +#include + +// int thread_fork(tcb_t* tcb, +// void* (*f)(void*), +// void* args); +.global thread_fork +.type thread_fork, %function +thread_fork: + mov 0x4(%esp), %edi // tcb + mov 0x8(%esp), %esi // f + mov 0xc(%esp), %edx // arg + int $THREAD_FORK_INT + cmp $0, %eax + jne .parent // both failure and success returns non-zero for parent + mov 0x8(%edi), %esp // read tcb.stack_hi and set stack + push %edx + push %esi + call thr_begin // thread entry point and this will not return +.parent: + ret + +.global get_esp +.type get_esp, %function +get_esp: + lea -0x4(%esp), %eax + ret diff --git a/user/progs/README.userprogs b/user/progs/README.userprogs new file mode 100644 index 0000000..d8c7ab0 --- /dev/null +++ b/user/progs/README.userprogs @@ -0,0 +1 @@ +Your own test programs go in this directory. diff --git a/user/progs/mandelbrot.c b/user/progs/mandelbrot.c new file mode 100644 index 0000000..957d513 --- /dev/null +++ b/user/progs/mandelbrot.c @@ -0,0 +1,533 @@ +/*! + * @file mandelbrot.c + * + * @brief A very cool, fractal test. + * + * Written by Keith Bare sometime aeons ago, improved by sully + * to support panning and zooming in Spring 2014. + * + * This version compromises on some of the original behaviors of + * mandelbrot in order to get panning/zooming to perform better + * in Simics. Both versions run beautifully in QEMU, though. + * + * In particular, we skip displaying a blue + in squares about to be + * updated and we only update squares that don't need it with + * probability 1/REDO_FACTOR. + * + * Setting TRADITIONAL to 1 recovers the old behaviors. + * + * @author Keith Bare + * @author Michael Sullivan (mjsulliv@) + */ + +/* Whether to do certain traditional mandelbrot behaviors or to skip them + * in favor of being faster. */ +#define TRADITIONAL 0 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// We define this as assert for convenience, but it isn't really intended +// to be the same. We use expect to check for fatal errors that require +// us to abort the program. +#define expect assert + +/* Not all kernels support getchar(). Try to use it, but if it doesn't work, + * fall back to readline. */ +static int fallback_getchar(void) +{ + char buf[2]; + readline(2, buf); + return (unsigned char)buf[0]; // cast prevents sign extension +} +static int try_getchar(void) +{ + static int no_getchar = 0; + int c; + if (no_getchar || (c = getchar()) < 0) { + no_getchar = 1; + return fallback_getchar(); + } + return c; +} +#define getchar try_getchar + + +// Filled in by find_console_size +int console_width; /*!<@brief Height of the console */ +int console_height; /*!<@brief Width of the console */ + +// Some tunables +#define YIELD_FACTOR 8 /*!<@brief Higher => thread is less likely to yield */ +#define REDO_FACTOR 4 /*!<@brief Higher => thread is less likely to redo */ + +#define MAX_TRAPS 30 /*!<@brief Maximum number of support traps */ + +// Fixed point stuff +typedef int fixed_t; + +#define FRACTIONAL_BITS 24 /*!<@brief Number of fixed point fractional bits */ + +// A bunch of macros for constructing fixed point numbers. +#define SIGN(n) ((n) < 0 ? -1 : 1) +#define INT_TO_FIXED(n) ((n) << FRACTIONAL_BITS) +#define FRAC_TO_FIXED(n, d) ((fixed_t)(INT_TO_FIXED((long long)n) / d)) +#define IMPROPER_TO_FIXED(i, n, d) FRAC_TO_FIXED(i*d + SIGN(i)*n, d) +#define DEC3_TO_FIXED(i, dec) IMPROPER_TO_FIXED(i, dec, 1000) + +#define INITIAL_COL_BASE DEC3_TO_FIXED(-2,500) +#define INITIAL_COL_LAST DEC3_TO_FIXED( 1,450) +#define INITIAL_ROW_BASE DEC3_TO_FIXED(-1,500) +#define INITIAL_ROW_LAST DEC3_TO_FIXED( 1,375) + + +/*!<@brief The real coordinates for the left and right edges of the screen */ +fixed_t col_base = INITIAL_COL_BASE; +fixed_t col_last = INITIAL_COL_LAST; +/*!<@brief The imaginary coordinates for the top and bottom edges */ +fixed_t row_base = INITIAL_ROW_BASE; +fixed_t row_last = INITIAL_ROW_LAST; + +// These get set by recompute_steps() +fixed_t col_step; +fixed_t row_step; + +int cur_generation = 0; + +/*! + * @brief Type for state that the threads modify + */ +typedef struct mandelbrot_state { + mutex_t cell_mutex; /*!< Mutex protecting this cell */ + int count; /*!< Number of threads that have visited this cell */ + int trap_num; /*!< -1, or the index of the condition variable in + which visited threads are trapped */ + int trapped_threads;/*!< Number of threads trapped at this cell */ + int exiting; /*!< Indicates that the program is terminating */ + int generation; /*!< What generation the cell was last updated at */ + int color; +} mandelbrot_state_t; + + +mutex_t console_lock; /*!<@brief Mutex protecting the console */ + +cond_t traps[MAX_TRAPS]; /*!<@brief Array of condition variables in which + threads can get "stuck" */ + +int exiting = 0; /*!<@brief Flag the indicates the test is exiting */ + +int wakeup_threshold = 1;/*!<@brief Maximum number of waiting threads */ + +/*! + * @brief Shared state that the threads modify. + */ +mandelbrot_state_t *state; + +unsigned long getrand(void) { + // FIXME: XXX: rand is not threadsafe! + return rand(); +} + +/*! + * @brief Fixed point multiplication. + * + * This is so I can do cool things, even though Pebbles doesn't allow programs + * to use the FPU. + */ +fixed_t fixed_mult(fixed_t a, fixed_t b) +{ + // Multiply the numbers, getting a result with FRACTIONAL_BITS*2 + // fractional bits. + long long mult_result = (long long)a * (long long)b; + // Round off + mult_result += (1 << (FRACTIONAL_BITS-1)); + return (fixed_t)(mult_result >> FRACTIONAL_BITS); +} + +/*! @brief Compute the squared magnitude of a complex number. */ +fixed_t mag2(fixed_t r, fixed_t i) { + return fixed_mult(r, r) + fixed_mult(i, i); +} + +/*! + * @brief Calculates the color that a (row, column) pair of the + * mandelbrot set should be. + * + * Returns the number of iterations of the Mandelbrot equation, Z = + * (Z_{n - 1})^2 + Z_0, occur before Z is more than a distance of one + * from the complex origin. + */ +int mandelbrot_calc(int row, int col) +{ + int i; + + fixed_t imag_coord_init = row_base + row*row_step; + fixed_t real_coord_init = col_base + col*col_step; + fixed_t imag_coord = imag_coord_init; + fixed_t real_coord = real_coord_init; + + for (i = 0; i < 14 && mag2(real_coord,imag_coord) < INT_TO_FIXED(4); i++) { + int tmp_imag_coord = 2*fixed_mult(real_coord, imag_coord) + + imag_coord_init; + real_coord = fixed_mult(real_coord, real_coord) - + fixed_mult(imag_coord, imag_coord) + + real_coord_init; + imag_coord = tmp_imag_coord; + } + + return i; +} + +/*! + * @brief Processes and draws a "pixel". + * + * Assumes that the caller has console_lock. + * + * @param row row of the pixel to draw + * @param col column of the pixel to draw + */ +int process_pixel(int row, int col) +{ + mandelbrot_state_t *st = &state[row*console_width + col]; + int wokeup = 0; + + mutex_lock(&st->cell_mutex); + + if (st->exiting) { + mutex_unlock(&st->cell_mutex); + return -1; + } + + // Do wakeups before considering whether to bail on this location. + if (st->trapped_threads >= wakeup_threshold) { + cond_broadcast(&traps[st->trap_num]); + wokeup = 1; + } + + // Compute the color if it is out of date. If it isn't, + // skip the rest of the processing "most of the time". + if (st->generation < cur_generation) { + st->color = mandelbrot_calc(row, col); + st->generation = cur_generation; + } else if (!TRADITIONAL && getrand() % REDO_FACTOR != 0) { + mutex_unlock(&st->cell_mutex); + return -1; + } + + // If there is a trap, get caught in it. (Unless we freed threads from it.) + if (!wokeup && st->trap_num >= 0) { + st->trapped_threads++; + + mutex_lock(&console_lock); + set_cursor_pos(row, col); + set_term_color((15 - st->color) | BGND_RED); + putchar('0' + st->trapped_threads % 10); + mutex_unlock(&console_lock); + + cond_wait(&traps[st->trap_num], + &st->cell_mutex); + + st->trapped_threads--; + } + + st->count++; + + mutex_lock(&console_lock); + set_cursor_pos(row, col); + set_term_color((15 - st->color) | BGND_BLACK); + putchar('a' + st->count % 26); + mutex_unlock(&console_lock); + + mutex_unlock(&st->cell_mutex); + + return 0; +} + +/*! + * @brief Main function for wanderer_threads. + * + * @param arg + */ +void *wanderer_main(void *arg) +{ + int row, col; + + row = getrand() % (console_height - 1); + col = getrand() % console_width; + + while (!exiting) { + process_pixel(row, col); + + row = getrand() % (console_height - 1); + col = getrand() % console_width; + + if (getrand() % YIELD_FACTOR == 0) { + yield(-1); + } + +#if TRADITIONAL + mutex_lock(&console_lock); + set_cursor_pos(row, col); + set_term_color(FGND_BLACK | BGND_BLUE); + printf("%c", '+'); + mutex_unlock(&console_lock); + + if (getrand() % YIELD_FACTOR == 0) { + yield(-1); + } +#endif + } + + return NULL; +} + +/*! + * @brief Prints a usage message. + */ +void usage() { + printf("mandelbrot [num_threads] [num_traps] [wakeup_threshold]\n\n"); + printf("num_traps must be <= %d\n", MAX_TRAPS); + printf("if num_traps * (wakeup_threshold - 1) >= num_threads " + "deadlock may result\n"); +} + +// Dynamically determine the console size. Most Pebbles implementations +// are 80x25, but there have been students who handed in window managers, +// and there exist at least two projects that attempt to run Pebbles +// binaries on Linux. +static void find_console_size() { + int orig_row, orig_col; + get_cursor_pos(&orig_row, &orig_col); + + /* determine the height of the console */ + console_height = 0; + while (set_cursor_pos(console_height, 0) == 0) { + console_height++; + } + /* determine the width of the console */ + console_width = 0; + while (set_cursor_pos(0, console_width) == 0) { + console_width++; + } + + set_cursor_pos(orig_row, orig_col); +} + +// Recompute the step amounts after something changes. +void recompute_steps(void) { + col_step = ((col_last-col_base)/(console_width-1)); + row_step = ((row_last-row_base)/(console_height-2)); +} + +// When we pan around, we update the parameters without synchronizing +// with computation threads at all. This is sort of hokey but ultimately +// we don't care. The worst that can happen is some pixels are the +// wrong color for a bit. +void input_loop(void) { + fixed_t row_move; + fixed_t col_move; + + while (1) { + char c = getchar(); + switch (c) { + case 'q': + return; + case 'w': + row_base -= row_step; + row_last -= row_step; + break; + case 's': + row_base += row_step; + row_last += row_step; + break; + case 'a': + col_base -= col_step; + col_last -= col_step; + break; + case 'd': + col_base += col_step; + col_last += col_step; + break; + case 'i': + // We want to cut the distance between the edges by a factor + // of 2, which means moving each edge + // current_distance/4. + row_move = (row_last-row_base)/4; + row_base += row_move; + row_last -= row_move; + col_move = (col_last-col_base)/4; + col_base += col_move; + col_last -= col_move; + + recompute_steps(); + + break; + + case 'o': + // We want to increase the distance between the edges by a factor + // of 2, which means moving each edge + // current_distance/2? + row_move = (row_last-row_base)/2; + row_base -= row_move; + row_last += row_move; + col_move = (col_last-col_base)/2; + col_base -= col_move; + col_last += col_move; + + recompute_steps(); + + break; + + case 'r': + col_base = INITIAL_COL_BASE; + col_last = INITIAL_COL_LAST; + row_base = INITIAL_ROW_BASE; + row_last = INITIAL_ROW_LAST; + + recompute_steps(); + + break; + default: + break; + } + + cur_generation++; + } +} + + +/*! + * @brief Code entry-point. + * + * @param argc + * @param argv + */ +int main(int argc, char *argv[]) +{ + thrgrp_group_t thread_group; + int num_threads = 15; + int num_traps = 8; + void *status; + + int i; + + if (argc >= 2) { + if (sscanf(argv[1], "%d", &num_threads) < 1 || num_threads <= 0) { + usage(); + return 0; + } + } + if (argc >= 3) { + if (sscanf(argv[2], "%d", &num_traps) < 1 || num_traps < 0 || + num_traps > MAX_TRAPS) { + usage(); + return 0; + } + } + if (argc >= 4) { + if (sscanf(argv[3], "%d", &wakeup_threshold) < 1) { + usage(); + return 0; + } + } + + srand(get_ticks()); + + lprintf("Initializing thread library..."); + expect(thr_init(PAGE_SIZE * 10) >= 0); + + lprintf("Initializing console lock..."); + expect(mutex_init(&console_lock) >= 0); + + lprintf("Finding console size..."); + find_console_size(); + + lprintf("Initializing state..."); + int num_spots = console_width*(console_height-1); + state = malloc(num_spots*sizeof(*state)); + expect(state != NULL); + + for (i = 0; i < num_spots; i++) { + expect(mutex_init(&state[i].cell_mutex) >= 0); + state[i].count = -1; + state[i].trap_num = -1; + state[i].trapped_threads = 0; + state[i].exiting = 0; + state[i].generation = -1; + } + + lprintf("Initializing traps..."); + /* May not assign all the traps, but it doesn't matter. */ + for (i = 0; i < num_traps; i++) { + expect(cond_init(&traps[i]) >= 0); + state[getrand() % num_spots].trap_num = i; + } + + // Set up the values + recompute_steps(); + + lprintf("Clearing console..."); + for (i = 0; i < console_height; i++) { + printf("\n"); + } + + set_cursor_pos(console_height-1, 0); + printf("wasd to pan, i = zoom in, o = zoom out, r = reset, q = quit"); + + lprintf("Initializing thread group..."); + expect(thrgrp_init_group(&thread_group) >= 0); + + lprintf("Creating wanderer threads..."); + for (i = 0; i < num_threads; i++) { + thrgrp_create(&thread_group, &wanderer_main, NULL); + } + + lprintf("Waiting for input..."); + input_loop(); + + exiting = 1; + + for (i = 0; i < num_spots; i++) { + mutex_lock(&state[i].cell_mutex); + state[i].exiting = 1; + mutex_unlock(&state[i].cell_mutex); + } + + for (i = 0; i < num_traps; i++) { + cond_broadcast(&traps[i]); + } + + lprintf("Joining with wanderer threads..."); + for (i = 0; i < num_threads; i++) { + thrgrp_join(&thread_group, &status); + } + + lprintf("Destroying thread group..."); + thrgrp_destroy_group(&thread_group); + + for (i = 0; i < num_spots; i++) { + mutex_destroy(&state[i].cell_mutex); + } + + for (i = 0; i < num_traps; i++) { + cond_destroy(&traps[i]); + } + + mutex_destroy(&console_lock); + + set_cursor_pos(console_height - 1, 0); + set_term_color(FGND_CYAN | BGND_BLACK); + + thr_exit(NULL); + return 0; +} diff --git a/user/progs/nibbles.c b/user/progs/nibbles.c new file mode 100644 index 0000000..31de3a5 --- /dev/null +++ b/user/progs/nibbles.c @@ -0,0 +1,462 @@ +/* + * Test program for the Spring 2004 15-410 Kernel project + * Clone of the nibbles/snake game + * + * by Michael Ashley-Rollman (mpa) + * tweaked by Dave Eckhardt (de0u) for Fall 2011 P4 + */ + +#include +#include +#include +#include +#include +#include + +#define SLEEP_TICKS 75 + +#define SNAKE_COLOR 0x60 +#define SNAKE_CHAR " " + +#define APPLE_COLOR 0x4 +#define APPLE_CHAR "@" + +#define BORDER_COLOR 0x30 +#define BORDER_CHAR ' ' + +#define BLANK_COLOR 0x0 +#define TEXT_COLOR 0x2 + +/* Maximum possible console width */ +#define MAX_POS_WIDTH 128 + +/* Maximum snake length */ +#define SNAKE_MAX_LENGTH 100 + +/* Minimum snake length */ +#define SNAKE_MIN_LENGTH 10 + +#define SNAKE_UP 'w' +#define SNAKE_DOWN 's' +#define SNAKE_LEFT 'a' +#define SNAKE_RIGHT 'd' + +#define SNAKE_START_ROW 10 +#define SNAKE_START_COL 10 +#define SNAKE_START_DIR SNAKE_RIGHT + +#define APPLE_MIN_WAIT 20 +#define APPLE_MAX_WAIT 40 + +#define APPLE_MAX_NUM 10 +#define APPLE_SCORE 10 + +/* The snake */ +typedef struct { + int length; + int start; + int spot[SNAKE_MAX_LENGTH][2]; + char direction; +} snake_t; + +/* The Apples */ +typedef struct { + int x; + int y; + int valid; +} apple_t; + +/* inter-move delay + * (adjustable for simulation vs. hardware) + * (could be adjusted downward as play progresses) + */ +int sleep_ticks = SLEEP_TICKS; + +/* width of the console */ +int con_width; + +/* height of the console */ +int con_height; + +/* the current score */ +int score; + +/* the last key pressed */ +volatile int last_key; + +int spawn_key_grabber(void); + +/* prints out the play instructions */ +void print_directions() +{ + printf("Move the snake using the controls listed below.\n"); + printf("Eat the apples to get points, but don't hit the\n"); + printf("wall or let the snake bite himself.\n"); + printf("UP - w\n"); + printf("DOWN - s\n"); + printf("LEFT - a\n"); + printf("RIGHT - d\n"); + printf("\n\n"); +}; + +/* draws the border around the edge of the screen and blanks the middle */ +void draw_border() +{ + int i; + char buf[MAX_POS_WIDTH]; + + for (i = 0; i < con_width; i++) { + buf[i] = BORDER_CHAR; + } + + set_term_color(BLANK_COLOR); + set_cursor_pos(con_height-1,0); + print(con_width, buf); + + set_term_color(BORDER_COLOR); + set_cursor_pos(0,0); + print(con_width, buf); + + for (i = 1; i < con_height - 2; i++) { + set_term_color(BLANK_COLOR); + set_cursor_pos(i,0); + print(con_width, buf); + + set_term_color(BORDER_COLOR); + set_cursor_pos(i, 0); + print(1, buf); + + set_cursor_pos(i, con_width-1); + print(1, buf); + } + + set_cursor_pos(con_height - 2,0); + print(con_width, buf); + + score = 0; + set_cursor_pos(con_height - 1, 0); + set_term_color(TEXT_COLOR); + printf("score: %d", score); +} + +/* initializes a snake to the starting size and location */ +void init_snake(snake_t *snake) { + int i; + + snake->length = SNAKE_MIN_LENGTH; + snake->start = SNAKE_MIN_LENGTH - 1; + + for (i = 0; i < SNAKE_MIN_LENGTH; i++) { + snake->spot[i][0] = SNAKE_START_COL; + snake->spot[i][1] = SNAKE_START_ROW; + } + + snake->direction = SNAKE_START_DIR; +} + +/* checks to see if the snake has killed itself + * + * returns 0 if the snake is still alive and -1 on death + */ +int snake_disaster(snake_t *snake) +{ + int i, stop; + int snake_x = snake->spot[snake->start][0]; + int snake_y = snake->spot[snake->start][1]; + + /* check to see if the snake is within bounds */ + if (snake_x <= 0 || + snake_x >= con_width - 1 || + snake_y <= 0 || + snake_y >= con_height - 2) + return -1; + + /* check to see if the snake is biting itself */ + stop = (snake->start - snake->length + SNAKE_MAX_LENGTH) % SNAKE_MAX_LENGTH; + + for (i = (snake->start - 1 + SNAKE_MAX_LENGTH) % SNAKE_MAX_LENGTH; + i != stop; + i = (i-1 + SNAKE_MAX_LENGTH) % SNAKE_MAX_LENGTH) + if (snake->spot[i][0] == snake_x && + snake->spot[i][1] == snake_y) + return -1; + + return 0; +} + +/* moves the snake forward a space, eating any apples there */ +void move_snake(snake_t *snake, apple_t *apples) +{ + int old_x, old_y; + int new_x, new_y; + int remove_x, remove_y; + + int i; + + /* get the position of the head of the snake */ + old_x = snake->spot[snake->start][0]; + old_y = snake->spot[snake->start][1]; + + snake->start = (snake->start + 1) % SNAKE_MAX_LENGTH; + + /* get the position of the tail of the snake */ + remove_x = snake->spot[(snake->start - + snake->length + + SNAKE_MAX_LENGTH) % + SNAKE_MAX_LENGTH][0]; + remove_y = snake->spot[(snake->start - + snake->length + + SNAKE_MAX_LENGTH) % + SNAKE_MAX_LENGTH][1]; + + /* find where the head of the snake has slithered to */ + switch (snake->direction) { + case SNAKE_UP: + new_x = old_x; + new_y = old_y - 1; + break; + + case SNAKE_DOWN: + new_x = old_x; + new_y = old_y + 1; + break; + + case SNAKE_LEFT: + new_x = old_x - 1; + new_y = old_y; + break; + + case SNAKE_RIGHT: + new_x = old_x + 1; + new_y = old_y; + break; + + default: + panic("Impossible direction %d", snake->direction); + return; + } + + /* fill int he new head */ + snake->spot[snake->start][0] = new_x; + snake->spot[snake->start][1] = new_y; + + /* delete the old tail */ + if (!set_cursor_pos(remove_y, remove_x)) { + set_term_color(BLANK_COLOR); + print(1, " "); + } + + /* display the head */ + if (!set_cursor_pos(new_y, new_x)) { + set_term_color(SNAKE_COLOR); + print(1, SNAKE_CHAR); + } + + /* ate any apples that the snake has hit */ + for (i = 0; i < APPLE_MAX_NUM; i++) + if (apples[i].valid == 1 && + apples[i].x == new_x && + apples[i].y == new_y) { + score += APPLE_SCORE; + apples[i].valid = 0; + snake->length++; + if (snake->length > SNAKE_MAX_LENGTH) + snake->length = SNAKE_MAX_LENGTH; + } +} + +/* randomly place a new apple on the screen */ +void new_apple(snake_t *snake, apple_t *apple) +{ + int spot; + int x,y; + + /* find a spot for an apple in the array */ + for (spot = 0; spot < APPLE_MAX_NUM; spot++) + if (!apple[spot].valid) break; + + if (spot == APPLE_MAX_NUM) return; + + /* pick a place on the screen */ + x = genrand() / ((unsigned int)(-1) / (con_width - 2)) + 1; + y = genrand() / ((unsigned int)(-1) / (con_height - 3)) + 1; + + /* set the apple */ + apple[spot].valid = 1; + apple[spot].x = x; + apple[spot].y = y; + + /* draw the apple */ + set_term_color(APPLE_COLOR); + set_cursor_pos(y, x); + print(1, APPLE_CHAR); +} + +/* plays through the game once */ +void play_game(snake_t *snake) +{ + int next_apple = 0; + int i; + + /* initialize the apples */ + apple_t apples[APPLE_MAX_NUM]; + + for (i = 0; i < APPLE_MAX_NUM; i++) + apples[i].valid = 0; + + do { + /* change the snake direction if appropriate */ + switch (last_key) { + case SNAKE_UP: + if (snake->direction != SNAKE_DOWN) + snake->direction = SNAKE_UP; + break; + + case SNAKE_DOWN: + if (snake->direction != SNAKE_UP) + snake->direction = SNAKE_DOWN; + break; + + case SNAKE_LEFT: + if (snake->direction != SNAKE_RIGHT) + snake->direction = SNAKE_LEFT; + break; + + case SNAKE_RIGHT: + if (snake->direction != SNAKE_LEFT) + snake->direction = SNAKE_RIGHT; + break; + + default: + break; + } + + /* add a new apple if it's time */ + if (next_apple == 0) { + new_apple(snake, apples); + next_apple = genrand() / + (((unsigned int)-1) / (APPLE_MAX_WAIT - APPLE_MIN_WAIT)) + + APPLE_MIN_WAIT; + } + + /* move the snake */ + move_snake(snake, apples); + + /* update the score */ + set_cursor_pos(con_height - 1, 7); + set_term_color(TEXT_COLOR); + printf("%d", score); + + /* nap for a bit to prevent the game from going too fast */ + sleep(sleep_ticks); + next_apple--; + } + /* loop until the snake kills itself */ + while(!snake_disaster(snake)); +} + +/* the game nibbles */ +void nibbles() +{ + + char again; + snake_t snake; + + do { + /* do the initial set up */ + draw_border(); + init_snake(&snake); + last_key = -1; + + /* play the game */ + play_game(&snake); + + /* query to play again */ + set_term_color(TEXT_COLOR); + set_cursor_pos(con_height / 2, (con_width - 11) / 2); + + last_key = -1; + print(11, "Play again?"); + + while ((again = last_key) != 'y' && + again != 'Y' && + again != 'n' && + again != 'N'); + + } while (again == 'y' || again == 'Y'); + + task_vanish(0); +} + +int main(int argc, char *argv[]) +{ + int rand_seed, child_tid; + + if (argc > 1) { + sleep_ticks = atoi(argv[1]); + } + + /* find the width of the console */ + for(con_width = 0; !set_cursor_pos(0, con_width); con_width++) + continue; + + /* find the height of the console */ + for(con_height = 0; !set_cursor_pos(con_height, 0); con_height++) + continue; + + /* spawn key_scanner */ + child_tid = spawn_key_grabber(); + + if (child_tid < 0) { + printf("Cannot launch \"thread\" (%d)\n", child_tid); + task_vanish(child_tid); + } + + /* print out the directions */ + print_directions(); + + /* get random number */ + printf("Press any key to begin nibbles\n"); + for (rand_seed = 0; last_key == -1; rand_seed++) + sleep(1); + sgenrand(rand_seed); + + /* start game */ + nibbles(); + + return 0; +} + +/***************************************************************** + * ____ _____ ___ ____ + * / ___| |_ _| / _ \ | _ \ + * \___ \ | | | | | | | |_) | + * ___) | | | | |_| | | __/ + * |____/ |_| \___/ |_| + * + * You may NOT write code this way. + * + * This code was written this way so it doesn't need to depend + * on your thread library, and then because the build framework + * requires each test program to be built from just one source + * file. + * + *****************************************************************/ + +void foobar() { +asm(".global spawn_key_grabber\n" + +"spawn_key_grabber:\n" +" movl $-1,last_key\n" /* set the last key pressed to none*/ +" int %0\n" /* Fork a clone */ +" cmpl $0,%%eax\n" +" je key_grab\n" /* Child starts grabbing keys */ +" ret\n" /* Parent returns child tid */ + +"key_grab:\n" +" int %1\n" /* Get a new character */ +" movl %%eax,last_key\n" /* Save it */ +" jmp key_grab\n" /* Do it again =) */ + :: "i" (THREAD_FORK_INT) + , "i" (GETCHAR_INT)); +} diff --git a/user/progs/racer.c b/user/progs/racer.c new file mode 100644 index 0000000..1d633de --- /dev/null +++ b/user/progs/racer.c @@ -0,0 +1,207 @@ +/** + * @file racer.c + * + * @brief a very strenuous test of mutexes, condition variables, and semaphores + * + * @author Peter Nelson + * + * This creates number of threads. Each thread gets 1 line of the + * terminal. Every thread attempts to aquire the semaphore which was + * initialized with a value of . When a thread aquires the sem + * it prints out number of characters, one at a time. + * + * There is an additional that can be used to cause each thread + * to call sleep of that value. Finally there is a "bad" thread that + * cycles misbehave states and then sleeps for . + * + * The expected default result is seeing a group of 12 threads run out for 5 + * characters. Then the next group of 12 threades will run out for 5 characters. + * The bottom-right corner shows the current number of threads that are active + * (should always be <=12) and the current misbehave state. + * + * threads and semaphores should be set to 24 and 12 for best effect + * runlength should be set to 5-10 to be able to see how many are active, + * or set to 1 for the most strenuous + * + * Colors are pseudo-randomly rotated by continuously adding get_ticks() to + * the color value. No real point other than to be trippy. + * + * Arguments: program threads runlength semaphores pausetime misbehavetime + */ + +#include +#include +#include +#include +#include +#include +#include + +#define STACK_SIZE 4096 +#define MAX_MISBEHAVE 64 + +// Uses my static initializer, you might have to change this +mutex_t lock_print; + +// Default values +int threads = 24; +int run = 5; +int sems = 12; +sem_t sem; +int pause = 0; +int bad_sleep = 50; + +char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; +char empty[81]; +mutex_t lock_running; +int running = 0; + +char color = 0; + +#define expect(exp) \ + { \ + err = exp; \ + if(err < 0) \ + lprintf("%s:%u: returned %d", \ + __FILE__, __LINE__, err); \ + } + +void *race(void *arg) +{ + int err; + int col = -1; + int i; + int row = (int)arg; + + mutex_lock(&lock_print); + color += get_ticks(); + set_term_color(color); + expect(set_cursor_pos(row, 0)); + printf("%s", &empty[0]); + mutex_unlock(&lock_print); + + while(1) + { + sem_wait(&sem); + + mutex_lock(&lock_running); + int r = ++running; + mutex_unlock(&lock_running); + if(r > sems) + lprintf("BAD! I have %d > %d threads running", r, sems); + + mutex_lock(&lock_print); + expect(set_cursor_pos(24, 77)); + printf("%.2d", running); + mutex_unlock(&lock_print); + + for(i = 0; i < run; i++) + { + col++; + if(80 == col) + { + mutex_lock(&lock_print); + color += get_ticks(); + set_term_color(color); + expect(set_cursor_pos(row, 0)); + printf("%s", &empty[0]); + mutex_unlock(&lock_print); + col = 0; + } + + mutex_lock(&lock_print); + color += get_ticks(); + set_term_color(color); + expect(set_cursor_pos(row, col)); + printf("%c", alphabet[i]); + mutex_unlock(&lock_print); + + if(pause) + expect(sleep(pause)); + thr_yield(-1); + } + + mutex_lock(&lock_running); + running--; + mutex_unlock(&lock_running); + + sem_signal(&sem); + } +} + +void *bad(void *arg) +{ + while(1) + { + int err; + int i = (int)arg; + + for(i=-1; i= 0) + bad_sleep = i; + /* FALLTHROUGH */ + case 5: + i = atoi(argv[4]); + if(i >= 0) + pause = i; + /* FALLTHROUGH */ + case 4: + i = atoi(argv[3]); + if(i > 0) + sems = i; + /* FALLTHROUGH */ + case 3: + i = atoi(argv[2]); + if(i <= 26 && i > 0) + run = i; + /* FALLTHROUGH */ + case 2: + i = atoi(argv[1]); + if(i > 1 && i <= 24) + threads = i; + /* FALLTHROUGH */ + default: + break; + } + + expect(thr_init(STACK_SIZE)); + expect(mutex_init(&lock_print)); + expect(mutex_init(&lock_running)); + expect(sem_init(&sem, sems)); + + for(i=0; i<80; i++) + empty[i] = ' '; + empty[80] = '\0'; + + expect(thr_create(bad, (void*)i) >= 0); + + for(i=0; i= 0); + + getchar(); + expect(set_cursor_pos(24,0)); + + task_vanish(0); +} -- cgit