summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-18 02:21:10 -0400
committerHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-18 02:21:10 -0400
commitc71294cdd3581c3738d24ffd65414f8644a1094d (patch)
treec86245d50fad9eee4163dbba169bd1839edbf88f
initial commit
-rw-r--r--.gitignore13
-rwxr-xr-x410guests/cliff.binbin0 -> 94244 bytes
-rw-r--r--410guests/cliff/config.mk7
-rw-r--r--410guests/cliff/kern/cliff.S26
-rw-r--r--410guests/cliff/kern/fake_console.c87
-rw-r--r--410guests/cliff/kern/hvstubs.S33
-rw-r--r--410guests/cliff/kern/inc/console.h159
-rwxr-xr-x410guests/console.binbin0 -> 96196 bytes
-rw-r--r--410guests/console/config.mk7
-rw-r--r--410guests/console/kern/console.c173
-rw-r--r--410guests/console/kern/fake_console.c87
-rw-r--r--410guests/console/kern/hvstubs.S33
-rw-r--r--410guests/console/kern/inc/console.h159
-rwxr-xr-x410guests/dog.binbin0 -> 92376 bytes
-rw-r--r--410guests/dog/config.mk9
-rw-r--r--410guests/dog/kern/devices.S37
-rw-r--r--410guests/dog/kern/dog.c110
-rw-r--r--410guests/dog/kern/fake_console.c43
-rw-r--r--410guests/dog/kern/hvstubs.S33
-rw-r--r--410guests/dog/kern/inc/console.h159
-rw-r--r--410guests/dog/kern/inc/devices.h32
-rwxr-xr-x410guests/dumper.binbin0 -> 95716 bytes
-rw-r--r--410guests/dumper/config.mk7
-rw-r--r--410guests/dumper/kern/dumper.c63
-rw-r--r--410guests/dumper/kern/fake_console.c87
-rw-r--r--410guests/dumper/kern/hvstubs.S33
-rw-r--r--410guests/dumper/kern/inc/console.h159
-rwxr-xr-x410guests/flayrod.binbin0 -> 94020 bytes
-rw-r--r--410guests/flayrod/config.mk8
-rw-r--r--410guests/flayrod/kern/fake_console.c87
-rw-r--r--410guests/flayrod/kern/flayrod.c20
-rw-r--r--410guests/flayrod/kern/inc/console.h159
-rw-r--r--410guests/flayrod/kern/try_catch.S42
-rwxr-xr-x410guests/fondle.binbin0 -> 96164 bytes
-rw-r--r--410guests/fondle/config.mk7
-rw-r--r--410guests/fondle/kern/fake_console.c87
-rw-r--r--410guests/fondle/kern/fondle2.c245
-rw-r--r--410guests/fondle/kern/hvstubs.S33
-rw-r--r--410guests/fondle/kern/inc/console.h159
-rwxr-xr-x410guests/gomoku.binbin0 -> 99556 bytes
-rw-r--r--410guests/guests.mk28
-rwxr-xr-x410guests/hello.binbin0 -> 94404 bytes
-rw-r--r--410guests/hello/config.mk7
-rw-r--r--410guests/hello/kern/fake_console.c87
-rw-r--r--410guests/hello/kern/hello.c59
-rw-r--r--410guests/hello/kern/hvstubs.S33
-rw-r--r--410guests/hello/kern/inc/console.h159
-rwxr-xr-x410guests/magic.binbin0 -> 94564 bytes
-rw-r--r--410guests/magic/config.mk7
-rw-r--r--410guests/magic/kern/fake_console.c87
-rw-r--r--410guests/magic/kern/hvstubs.S33
-rw-r--r--410guests/magic/kern/inc/console.h159
-rw-r--r--410guests/magic/kern/magic.c66
-rwxr-xr-x410guests/pathos.binbin0 -> 748768 bytes
-rwxr-xr-x410guests/station.binbin0 -> 94904 bytes
-rw-r--r--410guests/station/config.mk7
-rw-r--r--410guests/station/kern/fake_console.c87
-rw-r--r--410guests/station/kern/hvstubs.S33
-rw-r--r--410guests/station/kern/inc/console.h159
-rw-r--r--410guests/station/kern/station.c97
-rwxr-xr-x410guests/teeny.binbin0 -> 95300 bytes
-rw-r--r--410guests/teeny/config.mk7
-rw-r--r--410guests/teeny/kern/fake_console.c87
-rw-r--r--410guests/teeny/kern/hvstubs.S33
-rw-r--r--410guests/teeny/kern/inc/console.h159
-rw-r--r--410guests/teeny/kern/teeny.c97
-rwxr-xr-x410guests/tick_tock.binbin0 -> 94756 bytes
-rw-r--r--410guests/tick_tock/config.mk7
-rw-r--r--410guests/tick_tock/kern/fake_console.c87
-rw-r--r--410guests/tick_tock/kern/hvstubs.S33
-rw-r--r--410guests/tick_tock/kern/inc/console.h159
-rw-r--r--410guests/tick_tock/kern/tick_tock.c107
-rwxr-xr-x410guests/vast.binbin0 -> 95236 bytes
-rw-r--r--410guests/vast/config.mk7
-rw-r--r--410guests/vast/kern/fake_console.c87
-rw-r--r--410guests/vast/kern/hvstubs.S33
-rw-r--r--410guests/vast/kern/inc/console.h159
-rw-r--r--410guests/vast/kern/vast.c111
-rwxr-xr-x410guests/warp.binbin0 -> 119428 bytes
-rw-r--r--410guests/warp/config.mk7
-rw-r--r--410guests/warp/kern/fake_console.c87
-rw-r--r--410guests/warp/kern/hvstubs.S33
-rw-r--r--410guests/warp/kern/inc/console.h159
-rw-r--r--410guests/warp/kern/inc/warp.h11
-rw-r--r--410guests/warp/kern/warp.S35
-rw-r--r--410guests/warp/kern/warp_main.c118
-rw-r--r--410guests/warp/kern/warp_map.S4126
-rw-r--r--410kern/RNG/kernel.mk6
-rw-r--r--410kern/RNG/mt19937int.c97
-rw-r--r--410kern/RNG/mt19937int.h35
-rw-r--r--410kern/boot/head.S200
-rw-r--r--410kern/boot/kernel.mk13
-rw-r--r--410kern/boot/multiboot.h181
-rw-r--r--410kern/boot/util.h10
-rw-r--r--410kern/boot/util_cmdline.c82
-rw-r--r--410kern/boot/util_lmm.c150
-rw-r--r--410kern/bootfd.img.gzbin0 -> 274856 bytes
-rw-r--r--410kern/elf/elf32.h245
-rw-r--r--410kern/elf/elf_410.h39
-rw-r--r--410kern/elf/elf_common.h866
-rw-r--r--410kern/elf/kernel.mk9
-rw-r--r--410kern/elf/load_helper.c212
-rw-r--r--410kern/entry.c111
-rw-r--r--410kern/inc/asm_style.h126
-rw-r--r--410kern/inc/assert.h69
-rw-r--r--410kern/inc/exec2obj.h29
-rw-r--r--410kern/inc/kvmphys.h47
-rw-r--r--410kern/inc/malloc.h16
-rw-r--r--410kern/inc/stdarg.h18
-rw-r--r--410kern/inc/stdbool.h15
-rw-r--r--410kern/inc/stddef.h12
-rw-r--r--410kern/inc/stdint.h114
-rw-r--r--410kern/inc/types.h23
-rw-r--r--410kern/kernel.lds191
-rw-r--r--410kern/kernel.mk32
-rw-r--r--410kern/lmm/README50
-rw-r--r--410kern/lmm/kernel.mk21
-rw-r--r--410kern/lmm/lmm.h65
-rw-r--r--410kern/lmm/lmm_add_free.c80
-rw-r--r--410kern/lmm/lmm_add_region.c73
-rw-r--r--410kern/lmm/lmm_alloc.c87
-rw-r--r--410kern/lmm/lmm_alloc_aligned.c32
-rw-r--r--410kern/lmm/lmm_alloc_gen.c156
-rw-r--r--410kern/lmm/lmm_alloc_page.c31
-rw-r--r--410kern/lmm/lmm_avail.c51
-rw-r--r--410kern/lmm/lmm_dump.c75
-rw-r--r--410kern/lmm/lmm_find_free.c75
-rw-r--r--410kern/lmm/lmm_free.c109
-rw-r--r--410kern/lmm/lmm_free_page.c30
-rw-r--r--410kern/lmm/lmm_init.c29
-rw-r--r--410kern/lmm/lmm_remove_free.c50
-rw-r--r--410kern/lmm/lmm_types.h58
-rw-r--r--410kern/malloc/calloc.c38
-rw-r--r--410kern/malloc/free.c31
-rw-r--r--410kern/malloc/kernel.mk18
-rw-r--r--410kern/malloc/malloc.c39
-rw-r--r--410kern/malloc/malloc_internal.h53
-rw-r--r--410kern/malloc/malloc_lmm.c39
-rw-r--r--410kern/malloc/memalign.c51
-rw-r--r--410kern/malloc/realloc.c56
-rw-r--r--410kern/malloc/sfree.c33
-rw-r--r--410kern/malloc/smalloc.c40
-rw-r--r--410kern/malloc/smemalign.c53
-rw-r--r--410kern/menu.lst4
-rw-r--r--410kern/misc/gccisms.c346
-rw-r--r--410kern/misc/kernel.mk9
-rw-r--r--410kern/simics/kernel.mk10
-rw-r--r--410kern/simics/simics.S13
-rw-r--r--410kern/simics/simics.h75
-rw-r--r--410kern/simics/simics_c.c60
-rw-r--r--410kern/smp/L36_P4.pdfbin0 -> 92302 bytes
-rw-r--r--410kern/smp/README17
-rw-r--r--410kern/smp/apic.c104
-rw-r--r--410kern/smp/apic.h139
-rw-r--r--410kern/smp/kernel.mk12
-rw-r--r--410kern/smp/mptable.c246
-rw-r--r--410kern/smp/mptable.h119
-rw-r--r--410kern/smp/smp.c200
-rw-r--r--410kern/smp/smp.h20
-rw-r--r--410kern/smp/smp4.pdfbin0 -> 284148 bytes
-rw-r--r--410kern/smp/smp_start.S55
-rw-r--r--410kern/smp/smpboot.h19
-rw-r--r--410kern/stdio/doprnt.c646
-rw-r--r--410kern/stdio/doprnt.h34
-rw-r--r--410kern/stdio/doscan.c181
-rw-r--r--410kern/stdio/doscan.h30
-rw-r--r--410kern/stdio/hexdump.c71
-rw-r--r--410kern/stdio/kernel.mk17
-rw-r--r--410kern/stdio/printf.c109
-rw-r--r--410kern/stdio/putchar.c30
-rw-r--r--410kern/stdio/puts.c39
-rw-r--r--410kern/stdio/sprintf.c104
-rw-r--r--410kern/stdio/sscanf.c65
-rw-r--r--410kern/stdio/stdio.h46
-rw-r--r--410kern/stdlib/abs.c27
-rw-r--r--410kern/stdlib/atol.c8
-rw-r--r--410kern/stdlib/ctype.c91
-rw-r--r--410kern/stdlib/ctype.h37
-rw-r--r--410kern/stdlib/kernel.mk17
-rw-r--r--410kern/stdlib/panic.c52
-rw-r--r--410kern/stdlib/qsort.c170
-rw-r--r--410kern/stdlib/rand.c62
-rw-r--r--410kern/stdlib/stdlib.h23
-rw-r--r--410kern/stdlib/strtol.c68
-rw-r--r--410kern/stdlib/strtoul.c62
-rw-r--r--410kern/string/kernel.mk27
-rw-r--r--410kern/string/memcmp.c53
-rw-r--r--410kern/string/memset.c34
-rw-r--r--410kern/string/rindex.c35
-rw-r--r--410kern/string/strcat.c38
-rw-r--r--410kern/string/strchr.c35
-rw-r--r--410kern/string/strcmp.c55
-rw-r--r--410kern/string/strcpy.c45
-rw-r--r--410kern/string/strcspn.c64
-rw-r--r--410kern/string/strdup.c31
-rw-r--r--410kern/string/string.h57
-rw-r--r--410kern/string/strlen.c45
-rw-r--r--410kern/string/strncat.c64
-rw-r--r--410kern/string/strncmp.c38
-rw-r--r--410kern/string/strncpy.c51
-rw-r--r--410kern/string/strpbrk.c54
-rw-r--r--410kern/string/strrchr.c35
-rw-r--r--410kern/string/strspn.c57
-rw-r--r--410kern/string/strstr.c37
-rw-r--r--410kern/string/strtok.c86
-rw-r--r--410kern/toplevel.mk46
-rw-r--r--410kern/x86/asm.S220
-rw-r--r--410kern/x86/asm.h47
-rw-r--r--410kern/x86/bcopy.S135
-rw-r--r--410kern/x86/bzero.S47
-rw-r--r--410kern/x86/cr.h123
-rw-r--r--410kern/x86/eflags.S27
-rw-r--r--410kern/x86/eflags.h60
-rw-r--r--410kern/x86/idt.h36
-rw-r--r--410kern/x86/interrupt_defines.h20
-rw-r--r--410kern/x86/interrupts.c13
-rw-r--r--410kern/x86/kernel.mk17
-rw-r--r--410kern/x86/keyhelp.c401
-rw-r--r--410kern/x86/keyhelp.h205
-rw-r--r--410kern/x86/keylayout.c234
-rw-r--r--410kern/x86/keylayout.h66
-rw-r--r--410kern/x86/misc.h13
-rw-r--r--410kern/x86/page.h20
-rw-r--r--410kern/x86/pic.c123
-rw-r--r--410kern/x86/pic.h224
-rw-r--r--410kern/x86/rtc.c17
-rw-r--r--410kern/x86/rtc.h27
-rw-r--r--410kern/x86/seg.h39
-rw-r--r--410kern/x86/timer_defines.h24
-rw-r--r--410kern/x86/video_defines.h54
-rw-r--r--410user/crt0.c19
-rw-r--r--410user/exec2obj.c208
-rw-r--r--410user/inc/410_tests.h77
-rw-r--r--410user/inc/asm_style.h126
-rw-r--r--410user/inc/assert.h69
-rw-r--r--410user/inc/cond.h18
-rw-r--r--410user/inc/malloc.h17
-rw-r--r--410user/inc/mutex.h15
-rw-r--r--410user/inc/rand.h35
-rw-r--r--410user/inc/rwlock.h20
-rw-r--r--410user/inc/sem.h16
-rw-r--r--410user/inc/stdarg.h18
-rw-r--r--410user/inc/stdbool.h15
-rw-r--r--410user/inc/stddef.h12
-rw-r--r--410user/inc/stdint.h114
-rw-r--r--410user/inc/thread.h26
-rw-r--r--410user/inc/types.h23
-rw-r--r--410user/libRNG/mt19937int.c97
-rw-r--r--410user/libRNG/user.mk6
-rw-r--r--410user/libmalloc/malloc.c639
-rw-r--r--410user/libmalloc/memlib.c72
-rw-r--r--410user/libmalloc/memlib.h13
-rw-r--r--410user/libmalloc/user.mk7
-rw-r--r--410user/libsimics/simics.S14
-rw-r--r--410user/libsimics/simics.h84
-rw-r--r--410user/libsimics/simics_c.c61
-rw-r--r--410user/libsimics/user.mk10
-rw-r--r--410user/libstdio/doprnt.c646
-rw-r--r--410user/libstdio/doprnt.h34
-rw-r--r--410user/libstdio/doscan.c181
-rw-r--r--410user/libstdio/doscan.h30
-rw-r--r--410user/libstdio/hexdump.c71
-rw-r--r--410user/libstdio/printf.c97
-rw-r--r--410user/libstdio/putchar.c31
-rw-r--r--410user/libstdio/puts.c14
-rw-r--r--410user/libstdio/sprintf.c104
-rw-r--r--410user/libstdio/sscanf.c65
-rw-r--r--410user/libstdio/stdio.h46
-rw-r--r--410user/libstdio/user.mk16
-rw-r--r--410user/libstdlib/abs.c27
-rw-r--r--410user/libstdlib/atol.c9
-rw-r--r--410user/libstdlib/ctype.c91
-rw-r--r--410user/libstdlib/ctype.h37
-rw-r--r--410user/libstdlib/exit.c15
-rw-r--r--410user/libstdlib/qsort.c170
-rw-r--r--410user/libstdlib/rand.c62
-rw-r--r--410user/libstdlib/stdlib.h30
-rw-r--r--410user/libstdlib/strtol.c68
-rw-r--r--410user/libstdlib/strtoul.c62
-rw-r--r--410user/libstdlib/user.mk17
-rw-r--r--410user/libstring/memcmp.c53
-rw-r--r--410user/libstring/memset.c34
-rw-r--r--410user/libstring/rindex.c35
-rw-r--r--410user/libstring/strcat.c38
-rw-r--r--410user/libstring/strchr.c35
-rw-r--r--410user/libstring/strcmp.c55
-rw-r--r--410user/libstring/strcpy.c45
-rw-r--r--410user/libstring/strcspn.c64
-rw-r--r--410user/libstring/strdup.c31
-rw-r--r--410user/libstring/string.h57
-rw-r--r--410user/libstring/strlen.c45
-rw-r--r--410user/libstring/strncat.c64
-rw-r--r--410user/libstring/strncmp.c38
-rw-r--r--410user/libstring/strncpy.c51
-rw-r--r--410user/libstring/strpbrk.c54
-rw-r--r--410user/libstring/strrchr.c35
-rw-r--r--410user/libstring/strspn.c57
-rw-r--r--410user/libstring/strstr.c37
-rw-r--r--410user/libstring/strtok.c86
-rw-r--r--410user/libstring/user.mk27
-rw-r--r--410user/libtest/report.c98
-rw-r--r--410user/libtest/report.h109
-rw-r--r--410user/libtest/test.c0
-rw-r--r--410user/libtest/test.h52
-rw-r--r--410user/libtest/testasm.S82
-rw-r--r--410user/libtest/user.mk6
-rw-r--r--410user/libthrgrp/thrgrp.c201
-rw-r--r--410user/libthrgrp/thrgrp.h71
-rw-r--r--410user/libthrgrp/user.mk7
-rw-r--r--410user/libx86/bcopy.S135
-rw-r--r--410user/libx86/bzero.S47
-rw-r--r--410user/libx86/gccisms.c346
-rw-r--r--410user/libx86/user.mk11
-rw-r--r--410user/progs/ack.c56
-rw-r--r--410user/progs/actual_wait.c131
-rw-r--r--410user/progs/bg.c39
-rw-r--r--410user/progs/bistromath.c7711
-rw-r--r--410user/progs/cat.c30
-rw-r--r--410user/progs/cho.c103
-rw-r--r--410user/progs/cho2.c108
-rw-r--r--410user/progs/cho_variant.c171
-rw-r--r--410user/progs/chow.c142
-rw-r--r--410user/progs/ck1.c26
-rw-r--r--410user/progs/coolness.c26
-rw-r--r--410user/progs/deschedule_hang.c32
-rw-r--r--410user/progs/exec_basic.c33
-rw-r--r--410user/progs/exec_basic_helper.c25
-rw-r--r--410user/progs/exec_nonexist.c31
-rw-r--r--410user/progs/fib.c49
-rw-r--r--410user/progs/fork_bomb.c27
-rw-r--r--410user/progs/fork_exit_bomb.c41
-rw-r--r--410user/progs/fork_test1.c41
-rw-r--r--410user/progs/fork_wait.c46
-rw-r--r--410user/progs/fork_wait_bomb.c50
-rw-r--r--410user/progs/getpid_test1.c34
-rw-r--r--410user/progs/halt_test.c26
-rw-r--r--410user/progs/idle.c14
-rw-r--r--410user/progs/init.c28
-rw-r--r--410user/progs/knife.c43
-rw-r--r--410user/progs/loader_test1.c94
-rw-r--r--410user/progs/loader_test2.c273
-rw-r--r--410user/progs/make_crash.c50
-rw-r--r--410user/progs/make_crash_helper.c41
-rw-r--r--410user/progs/mem_eat_test.c58
-rw-r--r--410user/progs/mem_permissions.c98
-rw-r--r--410user/progs/merchant.c59
-rw-r--r--410user/progs/minclone_many.S177
-rw-r--r--410user/progs/minclone_mem.S78
-rw-r--r--410user/progs/new_pages.c95
-rw-r--r--410user/progs/new_shell.c27
-rw-r--r--410user/progs/peon.c35
-rw-r--r--410user/progs/print_basic.c27
-rw-r--r--410user/progs/progs.mk15
-rw-r--r--410user/progs/readline_basic.c25
-rw-r--r--410user/progs/register_test.S172
-rw-r--r--410user/progs/remove_pages_test1.c63
-rw-r--r--410user/progs/remove_pages_test2.c60
-rw-r--r--410user/progs/score.c146
-rw-r--r--410user/progs/shell.c276
-rw-r--r--410user/progs/slaughter.c144
-rw-r--r--410user/progs/sleep_test1.c32
-rw-r--r--410user/progs/stack_test1.c47
-rw-r--r--410user/progs/swexn_basic_test.c77
-rw-r--r--410user/progs/swexn_cookie_monster.c85
-rw-r--r--410user/progs/swexn_dispatch.c55
-rw-r--r--410user/progs/swexn_rampage.c96
-rw-r--r--410user/progs/swexn_regs.c65
-rw-r--r--410user/progs/swexn_stands_for_swextensible.c58
-rw-r--r--410user/progs/swexn_uninstall_test.c60
-rw-r--r--410user/progs/wait_getpid.c48
-rw-r--r--410user/progs/wild_test1.c31
-rw-r--r--410user/progs/work.c58
-rw-r--r--410user/progs/yield_desc_mkrun.c68
-rw-r--r--410user/user.mk60
-rw-r--r--Makefile487
-rw-r--r--README.STARTING_P426
-rw-r--r--config.mk218
-rw-r--r--doxygen.conf1101
-rw-r--r--guests/README60
-rw-r--r--kern/asm_instr.S22
-rw-r--r--kern/common.c472
-rw-r--r--kern/console.c212
-rw-r--r--kern/inc/asm_instr.h25
-rw-r--r--kern/inc/common.h228
-rw-r--r--kern/inc/console.h162
-rw-r--r--kern/inc/interrupt.h27
-rw-r--r--kern/inc/kbd.h30
-rw-r--r--kern/inc/loader.h46
-rw-r--r--kern/inc/mm.h55
-rw-r--r--kern/inc/paging.h155
-rw-r--r--kern/inc/sched.h361
-rw-r--r--kern/inc/sync.h102
-rw-r--r--kern/inc/timer.h24
-rw-r--r--kern/inc/usermem.h50
-rw-r--r--kern/interrupt.c502
-rw-r--r--kern/interrupt_asm.S134
-rw-r--r--kern/kbd.c218
-rw-r--r--kern/kernel.c109
-rw-r--r--kern/loader.c58
-rw-r--r--kern/malloc_wrappers.c70
-rw-r--r--kern/mm.c318
-rw-r--r--kern/paging.c76
-rw-r--r--kern/sched.c762
-rw-r--r--kern/sched_asm.S67
-rw-r--r--kern/sync.c78
-rw-r--r--kern/sync_asm.S75
-rw-r--r--kern/syscall_asm.S61
-rw-r--r--kern/syscall_io.c151
-rw-r--r--kern/syscall_memory.c137
-rw-r--r--kern/syscall_misc.c169
-rw-r--r--kern/syscall_process.c397
-rw-r--r--kern/syscall_thread.c274
-rw-r--r--kern/timer.c74
-rw-r--r--kern/usermem.c153
-rw-r--r--kern/usermem_asm.S35
-rw-r--r--spec/common_kern.h56
-rw-r--r--spec/compiler.h23
-rw-r--r--spec/contracts.h32
-rw-r--r--spec/hvcall.h135
-rw-r--r--spec/hvcall_int.h49
-rw-r--r--spec/limits.h36
-rw-r--r--spec/syscall.h98
-rw-r--r--spec/syscall_int.h69
-rw-r--r--spec/ureg.h50
-rwxr-xr-xupdate.sh107
-rw-r--r--user/files/README5
-rw-r--r--user/inc/README.userinc2
-rw-r--r--user/inc/cond_type.h32
-rw-r--r--user/inc/mutex_type.h38
-rw-r--r--user/inc/rwlock_type.h41
-rw-r--r--user/inc/sem_type.h24
-rw-r--r--user/inc/thr_internals.h74
-rw-r--r--user/libautostack/autostack.c71
-rw-r--r--user/libsyscall/syscall.S218
-rw-r--r--user/libthread/cond.c108
-rw-r--r--user/libthread/malloc.c40
-rw-r--r--user/libthread/mutex.c35
-rw-r--r--user/libthread/mutex_lock.S114
-rw-r--r--user/libthread/panic.c25
-rw-r--r--user/libthread/rb_tcb.c283
-rw-r--r--user/libthread/rwlock.c89
-rw-r--r--user/libthread/sem.c71
-rw-r--r--user/libthread/thread.c325
-rw-r--r--user/libthread/thread_fork.S26
-rw-r--r--user/progs/README.userprogs1
-rw-r--r--user/progs/mandelbrot.c533
-rw-r--r--user/progs/nibbles.c462
-rw-r--r--user/progs/racer.c207
448 files changed, 49383 insertions, 0 deletions
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
--- /dev/null
+++ b/410guests/cliff.bin
Binary files 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 <x86/idt.h>
+#include <hvcall_int.h>
+
+.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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/console.bin
Binary files 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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+#include <video_defines.h>
+
+#define DEBUG
+#include <contracts.h>
+
+#include <assert.h>
+#include <string.h>
+
+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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/dog.bin
Binary files 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 <hvcall_int.h>
+
+.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 <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <common_kern.h>
+
+#include <simics.h> /* lprintf() */
+#include <multiboot.h> /* boot_info */
+
+#include <console.h> /* putbyte() */
+#include <hvcall.h>
+#include <devices.h> /* augchar(), kbd_intr(), timer_intr() */
+#include <x86/keyhelp.h> /* KH_* */
+#include <x86/video_defines.h> /* 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 <types.h>
+#include <console.h>
+#include <hvcall.h>
+
+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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/dumper.bin
Binary files 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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/flayrod.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <simics.h>
+#include <hvcall.h>
+#include <common_kern.h>
+#include <multiboot.h>
+
+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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/fondle.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdint.h>
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <eflags.h>
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+#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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/gomoku.bin
Binary files 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
--- /dev/null
+++ b/410guests/hello.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+/** @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 <video_defines.h>
+
+/** @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
--- /dev/null
+++ b/410guests/magic.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+/** @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
--- /dev/null
+++ b/410guests/pathos.bin
Binary files differ
diff --git a/410guests/station.bin b/410guests/station.bin
new file mode 100755
index 0000000..f78e679
--- /dev/null
+++ b/410guests/station.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+#include <video_defines.h>
+
+#define DEBUG
+#include <contracts.h>
+
+#include <assert.h>
+#include <string.h>
+
+/* 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
--- /dev/null
+++ b/410guests/teeny.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+/** @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
--- /dev/null
+++ b/410guests/tick_tock.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/keyhelp.h>
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+#include <x86/timer_defines.h>
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+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
--- /dev/null
+++ b/410guests/vast.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+#include <string.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <compiler.h>
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#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
--- /dev/null
+++ b/410guests/warp.bin
Binary files 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 <console.h>
+
+/* Not very reentrant, but enough to lmm_dump() */
+#include <simics.h>
+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 <video_defines.h>
+
+/** @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 <hvcall_int.h>
+
+.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 <common_kern.h>
+
+/* libc includes. */
+#include <malloc.h>
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+
+/* multiboot header file */
+#include <multiboot.h> /* boot_info */
+
+/* memory includes. */
+#include <lmm.h> /* lmm_remove_free() */
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+#include <x86/interrupt_defines.h> /* interrupt_setup() */
+#include <x86/page.h>
+#include <x86/seg.h> /* install_user_segs() */
+
+#include <hvcall.h>
+#include <malloc_internal.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <warp.h>
+
+/* 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; mti++)
+ mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
+}
+
+unsigned long
+genrand()
+{
+ unsigned long y;
+ static unsigned long mag01[2]={0x0, MATRIX_A};
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if (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<N-M;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
+ }
+ for (;kk<N-1;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+(M-N)] ^ (y >> 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 <simics.h>
+#include <x86/video_defines.h>
+#include <x86/seg.h>
+
+/** @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 <types.h>
+
+/* 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 <boot/multiboot.h>
+#include <lmm/lmm.h>
+
+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 <boot/multiboot.h>
+#include <boot/util.h>
+#include <kvmphys.h>
+#include <stdlib/ctype.h>
+#include <stdlib/stdlib.h>
+#include <string/string.h>
+#include <malloc/malloc_internal.h>
+
+ /* 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 <boot/multiboot.h>
+#include <string/string.h>
+#include <malloc/malloc_internal.h>
+#include <kvmphys.h>
+#include <lmm/lmm_types.h>
+
+/* 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, &reg1mb,
+ (void*)phystokv(0x00000000), 0x00100000,
+ LMMF_1MB | LMMF_16MB, LMM_PRI_1MB);
+ lmm_add_region(&malloc_lmm, &reg16mb,
+ (void*)phystokv(0x00100000), 0x00f00000,
+ LMMF_16MB, LMM_PRI_16MB);
+ lmm_add_region(&malloc_lmm, &reghigh,
+ (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
--- /dev/null
+++ b/410kern/bootfd.img.gz
Binary files 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/elf_common.h>
+
+/*
+ * 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 <elf/elf32.h>
+
+/* --- 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 <stdint.h>
+
+/*
+ * 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 <elf/elf_410.h>
+#include <exec2obj.h>
+ /** FIXME: Should probably use something other than lprintf? */
+#include <simics.h>
+#include <stdio/stdio.h>
+#include <string/string.h>
+
+#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 <common_kern.h>
+#include <x86/cr.h>
+#include <x86/page.h>
+#include <x86/interrupt_defines.h>
+#include <boot/multiboot.h>
+#include <boot/util.h>
+#include <simics.h>
+#include <lmm/lmm.h>
+#include <malloc/malloc_internal.h>
+#include <assert.h>
+
+#include <kvmphys.h>
+
+/* 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 <lmm/lmm_types.h>
+
+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, &region, 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 <types.h>
+
+/** 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 <stdlib.h>
+#include <types.h>
+
+#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 <types.h> /* 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 <types.h>
+
+/* 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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+/* 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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+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 = &reg->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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+
+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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+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 = &reg->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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#include <x86/page.h>
+
+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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+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 <stdio/stdio.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+#include <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+
+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 <assert.h>
+#include <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+
+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 <assert.h>
+#include <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+
+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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#include <x86/page.h>
+
+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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+
+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 <lmm/lmm.h>
+#include <lmm/lmm_types.h>
+#undef NDEBUG // LMM assert()s are O(1) and vital
+#include <assert.h>
+
+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 <stddef.h>
+#include <malloc/malloc_internal.h>
+#include <string/string.h>
+
+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 <types.h>
+#include <lmm/lmm.h>
+
+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 <assert.h> // 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 <stddef.h>
+#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 <stddef.h>
+#include <string/string.h>
+
+#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 <stddef.h>
+#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 <stddef.h>
+#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 <stdarg.h>
+
+/** @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 <simics.h>
+#include <stdarg.h>
+#include <stdio/stdio.h>
+
+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
--- /dev/null
+++ b/410kern/smp/L36_P4.pdf
Binary files 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 <assert.h>
+#include <smp/smp.h>
+#include <smp/mptable.h>
+#include <smp/apic.h>
+
+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 <stdint.h>
+
+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 <jhb@FreeBSD.org>
+ * 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 <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <stddef.h>
+
+
+#include <multiboot.h>
+
+#include <smp/smp.h>
+#include <smp/mptable.h>
+#include <smp/apic.h>
+
+#include <compiler.h>
+
+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 <jhb@FreeBSD.org>
+ * 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 <multiboot.h> // mbinfo_t
+#include <stdint.h>
+
+#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 <assert.h>
+#include <string.h>
+#include <smp/smp.h>
+#include <smp/smpboot.h>
+#include <smp/mptable.h>
+#include <smp/apic.h>
+
+#include <x86/timer_defines.h>
+#include <x86/asm.h>
+#include <x86/seg.h>
+#include <x86/idt.h>
+#include <x86/cr.h>
+#include <x86/page.h>
+
+
+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 <stdint.h>
+#include <stddef.h>
+
+#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
--- /dev/null
+++ b/410kern/smp/smp4.pdf
Binary files 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 <x86/seg.h>
+#include <x86/cr.h>
+#include <smp/smpboot.h>
+
+/** @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<<INIT_STACK_SHIFT)
+
+#endif
diff --git a/410kern/stdio/doprnt.c b/410kern/stdio/doprnt.c
new file mode 100644
index 0000000..548e626
--- /dev/null
+++ b/410kern/stdio/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 <stdarg.h>
+#include <string.h>
+#include <types.h>
+#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, "<base><arg>*")
+ *
+ * where <base> is the output base expressed as a control character:
+ * i.e. '\10' gives octal, '\20' gives hex. Each <arg> 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<BITTWO,BITONE>
+ *
+ * If the second character in <arg> 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<FIELD1=2,BITONE>
+ */
+/*
+ * 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 <stdarg.h>
+
+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 <stddef.h>
+#include <stdarg.h>
+#include <types.h>
+#include <ctype.h>
+#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 <ctype.h>
+#include <stdio.h>
+
+/*
+ * 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 <stdio.h>
+#include <stdarg.h>
+#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 <stdio.h>
+#include <console.h>
+
+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 <stdio.h>
+
+/* 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 <stdarg.h>
+#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 <stdarg.h>
+#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 <stddef.h> /* For size_t, NULL */
+#include <stdarg.h>
+#include <types.h>
+
+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 <stdlib.h>
+
+#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 <stddef.h>
+#include <stdlib.h>
+
+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 <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <simics.h>
+#include <x86/asm.h>
+
+/*
+ * 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 <types.h>
+#include <stdlib.h>
+
+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 <stdlib.h>
+
+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 <stddef.h> /* For size_t, NULL */
+#include <malloc.h> /* "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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+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 <types.h>
+
+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 <string.h>
+#include <stdlib.h>
+
+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 <string.h>
+
+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 <types.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+
+
+
+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 <types.h>
+
+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 <types.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+
+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 <types.h>
+#include <stddef.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+#include <stddef.h>
+
+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 <types.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+
+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 <string.h>
+#include <stddef.h>
+
+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 <x86/seg.h>
+
+.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 <stdint.h>
+
+/** @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 <asm_style.h>
+
+
+#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 <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <asm_style.h>
+
+#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 <stdint.h>
+
+/** 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 <stdint.h>
+
+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 <x86/pic.h>
+
+#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 <x86/interrupt_defines.h>
+
+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 <smuckle@andrew.cmu.edu>
+ *
+ * @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 <x86/keyhelp.h>
+#include <x86/keylayout.h>
+
+#include <stddef.h>
+#include <assert.h>
+
+/** 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 <x86/keyhelp.h>
+#include <x86/keylayout.h>
+#include <assert.h>
+
+/** 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 <x86/pic.h>
+#include <x86/asm.h>
+
+ /** @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 <x86/rtc.h>
+#include <x86/asm.h>
+
+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 <smuckle@andrew.cmu.edu>
+ *
+ * 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 <smuckle@andrew.cmu.edu>
+ * @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 <stdlib.h>
+#include <syscall.h>
+#include <assert.h>
+
+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 <stdio.h>
+#include <string.h>
+
+#define STABS 0
+
+void print_usage() {
+ fprintf(stderr, "Usage: exec2obj <file>...\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 <simics.h> /* lprintf() */
+
+#ifndef ASSEMBLER
+
+#include <report.h> /* 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 <mutex.h>
+#include <cond_type.h>
+
+/* 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 <stdlib.h>
+#include <types.h>
+
+#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 <mutex_type.h>
+
+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 <rwlock_type.h>
+
+/* 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 <sem_type.h>
+
+/* 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 <types.h> /* 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 <thr_internals.h>
+
+/* 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; mti++)
+ mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
+}
+
+unsigned long
+genrand()
+{
+ unsigned long y;
+ static unsigned long mag01[2]={0x0, MATRIX_A};
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if (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<N-M;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
+ }
+ for (;kk<N-1;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+(M-N)] ^ (y >> 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#undef NDEBUG // the assert()s in this particular implementation are all O(1) and vital
+#include <assert.h>
+
+#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 <stddef.h>
+#include <stdio.h>
+#include <syscall.h>
+
+/* #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 <stdarg.h>
+
+/** @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 <simics.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <syscall.h> /* 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 <stdarg.h>
+#include <string.h>
+#include <types.h>
+#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, "<base><arg>*")
+ *
+ * where <base> is the output base expressed as a control character:
+ * i.e. '\10' gives octal, '\20' gives hex. Each <arg> 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<BITTWO,BITONE>
+ *
+ * If the second character in <arg> 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<FIELD1=2,BITONE>
+ */
+/*
+ * 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 <stdarg.h>
+
+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 <stddef.h>
+#include <stdarg.h>
+#include <types.h>
+#include <ctype.h>
+#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 <ctype.h>
+#include <stdio.h>
+
+/*
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <syscall.h>
+#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 <stdio.h>
+#include <syscall.h>
+
+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 <stdio.h>
+#include <string.h>
+#include <syscall.h>
+
+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 <stdarg.h>
+#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 <stdarg.h>
+#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 <stddef.h> /* For size_t, NULL */
+#include <stdarg.h>
+#include <types.h>
+
+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 <stdlib.h>
+
+#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 <stddef.h>
+#include <stdlib.h>
+
+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 <syscall.h>
+
+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 <types.h>
+#include <stdlib.h>
+
+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 <stdlib.h>
+
+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 <stddef.h> /* For size_t, NULL */
+#include <malloc.h> /* "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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+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 <types.h>
+
+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 <string.h>
+#include <stdlib.h>
+
+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 <string.h>
+
+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 <types.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+
+
+
+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 <types.h>
+
+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 <types.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+
+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 <types.h>
+#include <stddef.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+#include <stddef.h>
+
+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 <types.h>
+#include <string.h>
+
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+
+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 <string.h>
+#include <stddef.h>
+
+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 <stdio.h> /* snprintf */
+#include <stdlib.h> /* exit */
+#include <report.h>
+
+#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
--- /dev/null
+++ b/410user/libtest/test.c
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 <simics.h>
+#include <syscall_int.h>
+
+.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 <cond.h>
+#include <thrgrp.h>
+#include <thread.h>
+#include <stddef.h>
+#include <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <simics.h>
+#include <assert.h>
+
+/**
+ * @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 <cond.h>
+
+/**
+ * @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 <asm_style.h>
+
+
+#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 <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <asm_style.h>
+
+#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 <thread.h>
+#include <thrgrp.h>
+#include <410_tests.h>
+#include <stdio.h>
+#include <syscall.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <simics.h>
+
+#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 <syscall.h>
+#include <stdio.h>
+#include <assert.h>
+
+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 <bblum@andrew.cmu.edu>
+ * 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 <bblum@andrew.cmu.edu>.
+ *
+ ******************************************************************************
+ *
+ * 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 <syscall.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#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
+ <http://www.gnu.org/licenses/>. */
+
+#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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <color>'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 <color> on the given <rank> */
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <simics.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h> /* gettid() */
+#include <simics.h> /* 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 <syscall.h>
+#include <simics.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <simics.h>
+#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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <simics.h>
+#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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <stdio.h>
+#include <syscall.h>
+#include <thread.h>
+#include <thrgrp.h>
+
+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 <syscall.h> /* for fork */
+#include <stdlib.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h> /* for fork, getpid */
+#include <stdlib.h> /* for exit */
+#include <stdio.h> /* for lprintf */
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <report.h>
+#include <simics.h> /* for lprintf */
+#include <stdlib.h> /* for exit */
+#include <syscall.h> /* 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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <simics.h>
+#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 <syscall.h>
+#include <stdio.h>
+
+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 <syscall.h>
+#include <stdio.h>
+#include <simics.h>
+
+#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 <stdlib.h>
+#include <syscall.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <stdlib.h>
+#include <syscall.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdio.h>
+#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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#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 <limits.h>
+#include <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#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 <syscall.h>
+#include <stdio.h>
+#include <string.h>
+#include <simics.h>
+
+#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 <syscall_int.h>
+
+.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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "410_tests.h"
+#include <report.h>
+#include <test.h>
+
+/* 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 <syscall.h>
+#include <stdio.h>
+
+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 <syscall.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <simics.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#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 <syscall.h>
+#include <stdlib.h>
+#include <simics.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+#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 <syscall.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+#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 <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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 <string.h>
+#include <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <simics.h>
+
+/* --- 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 <syscall.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <recursive depth> "
+ "<recursive width> <exit status> <command line>\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 <syscall.h> /* for sleep, getpid */
+#include <stdio.h>
+#include <simics.h> /* for lprintf */
+#include <stdlib.h> /* for atoi, exit */
+#include "410_tests.h"
+#include <report.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+#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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+
+#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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+#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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+#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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+
+#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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+#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 <stddef.h>
+#include <stdlib.h>
+#include <syscall.h>
+#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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <syscall.h> /* was for exit */
+#include <stdlib.h> /* for exit */
+#include <stdio.h>
+#include <simics.h> /* 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 <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <stdint.h>
+
+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 <syscall.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "410_tests.h"
+#include <report.h>
+
+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 <lib/header.h> 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 <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> 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 <common.h>
+
+#include <string.h>
+
+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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <x86/asm.h>
+#include <x86/video_defines.h>
+
+#include <console.h>
+
+/** 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 <paging.h>
+
+/**
+ * @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 <stdlib.h>
+
+/**
+ * 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 <video_defines.h>
+
+#include <sync.h>
+
+/** 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 <common.h>
+#include <sched.h>
+#include <sync.h>
+
+/**
+ * @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 <exec2obj.h>
+
+/* --- 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 <syscall_int.h>
+
+#include <paging.h>
+#include <sync.h>
+
+/** 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 <x86/page.h>
+
+/* 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 <common_kern.h>
+#include <elf/elf_410.h>
+
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <common.h>
+#include <paging.h>
+#include <sync.h>
+
+/** 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 <common.h>
+
+/** 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 <stdint.h>
+
+#include <common_kern.h>
+
+#include <paging.h>
+
+/**
+ * @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 <x86/asm.h>
+#include <x86/eflags.h>
+#include <x86/idt.h>
+#include <x86/interrupt_defines.h>
+#include <x86/seg.h>
+#include <x86/timer_defines.h>
+
+#include <keyhelp.h>
+#include <simics.h>
+#include <stdio.h>
+#include <string.h>
+#include <syscall_int.h>
+#include <ureg.h>
+
+#include <asm_instr.h>
+#include <interrupt.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+#include <usermem.h>
+
+/** 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 <x86/seg.h>
+#include <x86/interrupt_defines.h>
+
+#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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <x86/asm.h>
+#include <x86/interrupt_defines.h>
+#include <x86/keyhelp.h>
+
+#include <console.h>
+#include <interrupt.h>
+#include <kbd.h>
+#include <paging.h>
+#include <sync.h>
+#include <usermem.h>
+
+/** 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 <common_kern.h>
+
+/* libc includes. */
+#include <simics.h> /* lprintf() */
+#include <stdio.h>
+#include <string.h>
+
+/* multiboot header file */
+#include <mptable.h>
+#include <multiboot.h> /* boot_info */
+#include <smp.h>
+
+/* x86 specific includes */
+#include <x86/asm.h> /* enable_interrupts() */
+#include <x86/cr.h>
+
+#include <assert.h>
+#include <common.h>
+#include <console.h>
+#include <interrupt.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <timer.h>
+
+/**
+ * @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 <elf_410.h>
+#include <exec2obj.h>
+#include <loader.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+/* --- 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 <malloc.h>
+#include <malloc_internal.h>
+#include <stddef.h>
+
+#include <sync.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+#include <common_kern.h>
+#include <x86/asm.h>
+
+#include <asm_instr.h>
+#include <common.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+
+/** 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 <common_kern.h>
+#include <malloc_internal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <apic.h>
+#include <mptable.h>
+#include <smp.h>
+#include <x86/asm.h>
+#include <x86/cr.h>
+
+#include <asm_instr.h>
+#include <paging.h>
+#include <sched.h>
+
+/** 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 <malloc_internal.h>
+#include <string.h>
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <loader.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+
+/* .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, &current->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 <x86/seg.h>
+
+.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 <x86/asm.h>
+
+#include <interrupt.h>
+#include <sched.h>
+#include <sync.h>
+
+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, &current->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, &current->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 <simics.h>
+#include <x86/seg.h>
+
+#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 <common_kern.h>
+#include <elf/elf_410.h>
+#include <string.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <console.h>
+#include <kbd.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <usermem.h>
+
+/**
+ * @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 <string.h>
+#include <common_kern.h>
+#include <elf/elf_410.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <usermem.h>
+
+/**
+ * @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 <simics.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common_kern.h>
+#include <elf/elf_410.h>
+#include <malloc_internal.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <assert.h>
+#include <loader.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+#include <usermem.h>
+
+/**
+ * @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 <simics.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common_kern.h>
+#include <elf/elf_410.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <assert.h>
+#include <loader.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+#include <usermem.h>
+
+/**
+ * @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 <string.h>
+
+#include <common_kern.h>
+#include <elf/elf_410.h>
+#include <simics.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <assert.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <usermem.h>
+
+/**
+ * @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(&current->status_lock);
+ if (copy_from_user(preject, sizeof(int), &reject) != 0) {
+ spl_unlock(&current->status_lock, old_if);
+ f->eax = (reg_t)-1;
+ return;
+ }
+ if (reject != 0 || current->pending_exit != 0) {
+ spl_unlock(&current->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, &current->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 <common_kern.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <assert.h>
+#include <x86/asm.h>
+#include <x86/interrupt_defines.h>
+#include <x86/timer_defines.h>
+
+#include <interrupt.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+
+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 <stdlib.h>
+#include <string.h>
+
+#include <common_kern.h>
+#include <x86/asm.h>
+
+#include <console.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+
+/**
+ * @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 <boot/multiboot.h>
+
+ /** @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 <assert.h>
+
+/* 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 <ureg.h> /* 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 <how> [query]
+#
+# <how>:
+# 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 <mutex.h>
+
+/**
+ * @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 <stdint.h>
+#include <stdlib.h>
+
+/* 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 <cond.h>
+#include <mutex.h>
+
+/**
+ * @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 <cond.h>
+#include <mutex.h>
+
+/**
+ * @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 <stdint.h>
+
+#include <cond.h>
+#include <mutex.h>
+#include <syscall.h>
+
+/**
+ * @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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <simics.h>
+#include <syscall.h>
+#include <thr_internals.h>
+#include <ureg.h>
+
+/**
+ * @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 <syscall_int.h>
+
+.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 <assert.h>
+#include <cond.h>
+#include <stdlib.h>
+#include <syscall.h>
+
+/**
+ * @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 <malloc.h>
+#include <mutex.h>
+
+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 <stdint.h>
+
+#include <assert.h>
+#include <mutex.h>
+
+/**
+ * @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 <syscall_int.h>
+
+// 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 <stdio.h>
+#include <stdlib.h>
+
+/**
+ * @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 <stdbool.h>
+#include <stdlib.h>
+
+#include <thr_internals.h>
+
+/**
+ * @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 <assert.h>
+#include <rwlock.h>
+
+/**
+ * @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 <sem.h>
+
+/**
+ * @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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <mutex.h>
+#include <simics.h>
+#include <syscall.h>
+#include <thr_internals.h>
+#include <thread.h>
+#include <ureg.h>
+
+/* 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 <syscall_int.h>
+
+// 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 <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <syscall.h>
+#include <simics.h>
+#include <stdlib.h>
+
+#include <malloc.h>
+#include <thread.h>
+#include <cond.h>
+#include <mutex.h>
+#include <thrgrp.h>
+
+// 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 &quot;stuck&quot; */
+
+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 <stdlib.h>
+#include <stdio.h>
+#include <syscall.h>
+#include <syscall_int.h>
+#include <rand.h>
+#include <assert.h>
+
+#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 <pnelson>
+ *
+ * This creates <threads> 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 <semaphores>. When a thread aquires the sem
+ * it prints out <runlength> number of characters, one at a time.
+ *
+ * There is an additional <pausetime> 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 <misbehavetime>.
+ *
+ * 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 <thread.h>
+#include <syscall.h>
+#include <simics.h>
+#include <stdio.h>
+#include <sem.h>
+#include <mutex.h>
+#include <stdlib.h>
+
+#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<MAX_MISBEHAVE; i++)
+ {
+ lprintf("calling misbehave(%d)", i);
+
+ mutex_lock(&lock_print);
+ expect(set_cursor_pos(24, 73));
+ printf("% .2d", i);
+ mutex_unlock(&lock_print);
+
+ misbehave(i);
+ sleep(bad_sleep);
+ }
+ }
+ return arg;
+}
+
+int main( int argc, char *argv[] )
+{
+ int i, err;
+
+ switch(argc) {
+ case 6:
+ i = atoi(argv[5]);
+ if(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<threads; i++)
+ expect(thr_create(race, (void*)i) >= 0);
+
+ getchar();
+ expect(set_cursor_pos(24,0));
+
+ task_vanish(0);
+}